/* <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 Material = require("js/lib/rdge/materials/material").Material; var __textureCounter = 0; /////////////////////////////////////////////////////////////////////// // Class GLTexture // GL representation of a texture. /////////////////////////////////////////////////////////////////////// function Texture( dstWorld, texMapName, wrap, mips ) { /////////////////////////////////////////////////////////////////////// // Instance variables /////////////////////////////////////////////////////////////////////// this._texture; // the canvas generating the texture map (if there is one) this._srcCanvas; this._srcWorld; // texture attributes if (typeof texMapName === "string") this._texMapName = texMapName.slice(); else this._srcCanvas = texMapName; // set default values for wrap and mips if (wrap === undefined) wrap = "REPEAT"; if (mips === undefined) mips = true; this._wrap = wrap; this._mips = mips; // cache whether or not the source is animated this._isAnimated = false; // the destination world that will use the texture map this._dstWorld = dstWorld; this._texCount = __textureCounter; __textureCounter++; /////////////////////////////////////////////////////////////////////// // Property Accessors /////////////////////////////////////////////////////////////////////// this.getTexture = function() { return this._texture; } this.setSrcWorld = function(w) { this._srcWorld = w; } this.getSrcWorld = function() { return this._srcWorld; } this.setDstWorld = function(w) { this._dstWorld = w; } this.getDstWorld = function() { return this._dstWorld; } this.isAnimated = function() { return this._isAnimated; } /////////////////////////////////////////////////////////////////////// // Methods /////////////////////////////////////////////////////////////////////// this.init = function() { // determine if the source is a canvas or an image file var viewUtils = require("js/helper-classes/3D/view-utils").ViewUtils; //var root = viewUtils.application.ninja.currentDocument.documentRoot; var root; if (viewUtils.application.ninja.currentDocument) root = viewUtils.application.ninja.currentDocument.model.documentRoot; var srcCanvas = this._srcCanvas; if (!srcCanvas && root) srcCanvas = this.findCanvas( this._texMapName, root ); if (srcCanvas) { this._srcCanvas = srcCanvas; var srcWorld if (srcCanvas.elementModel && srcCanvas.elementModel.shapeModel && srcCanvas.elementModel.shapeModel.GLWorld) srcWorld = srcCanvas.elementModel.shapeModel.GLWorld; if (!srcWorld) srcWorld = srcCanvas.__GLWorld; if (srcWorld) { this._srcWorld = srcWorld; // add a notifier to the world srcWorld.addListener( this, this.worldCallback, { srcWorld: this._srcWorld } ); // check if the source is animated this._isAnimated = srcWorld._hasAnimatedMaterials; } this.loadFromCanvas(); } else { this.loadFromFile(); } } this.worldCallback = function( type, callbackObj, calleeData, callerData ) { console.log( "texture callback, type: " + type ); if (calleeData.srcWorld) { var srcWorld = callbackObj.getSrcWorld(); var dstWorld = callbackObj.getDstWorld(); var notifier = srcWorld._notifier; var texture = this.callbackObj; if (texture) { switch (type) { case notifier.OBJECT_DELETE: texture.rebuildSrcLocally(); break; case notifier.OBJECT_REINSTANTIATE: break; case notifier.OBJECT_CHANGE: break; case notifier.FIRST_RENDER: texture._isAnimated = srcWorld.hasAnimatedMaterials(); break; default: throw new Exception( "unrecognized texture callback type: " + type ); break; } } } } this.rebuildSrcLocally = function() { var srcWorld = this._srcWorld; if (srcWorld) { // get the data from the old world var jStr = srcWorld.exportJSON(); var index = jStr.indexOf( ';' ); if ((jStr[0] === 'v') && (index < 24)) jStr = jStr.substr( index+1 ); var jObj = JSON.parse( jStr ); var oldCanvas = srcWorld.getCanvas(); // create a new canvas var NJUtils = require("js/lib/NJUtils").NJUtils; this._srcCanvas = NJUtils.makeNJElement("canvas", "texture_internal_canvas", "shape", {"data-RDGE-id": NJUtils.generateRandom()}, true); srcCanvas = this._srcCanvas; srcCanvas.width = oldCanvas.width; srcCanvas.height = oldCanvas.height; // rebuild the world var GLWorld = require("js/lib/drawing/world").World; this._srcWorld = new GLWorld( this._srcCanvas, true, true ); this._srcWorld.importJSON( jObj ); this._isLocal = true; } } this.loadFromFile = function() { var tex = this._texture; this._srcCanvas = null; // only load if something has changed //if (this._texMapName !== texMapName) // does RDGE allow us to change wrap or mips? { var texMapName = this._texMapName; var wrap = this._wrap; var mips = this._mips; var dstWorld = this.getDstWorld(); if (dstWorld) { var renderer = dstWorld.getRenderer(); tex = renderer.getTextureByName(texMapName, wrap, mips ); this._texture = tex; dstWorld.textureToLoad( tex ); } } return tex; } var __texCounter = 0; this.loadFromCanvas = function() { var NJUtils = require("js/lib/NJUtils").NJUtils; var srcCanvas = this._srcCanvas; var wrap = this._wrap; var mips = this._mips; this._texMapName = "GLTexture_" + __texCounter; __texCounter++; // create the texture var world = this.getDstWorld(); tex = world.getGLContext().createTexture(); this._texture = tex; tex.texparams = new _texparams(wrap, mips); // defined in renderer.js tex.image = new Image; // create the canvas and context to render into var doc = srcCanvas.ownerDocument; //this._renderCanvas = doc.createElement("texture_canvas"); this._renderCanvas = NJUtils.makeNJElement("canvas", "texture_canvas", "shape", {"data-RDGE-id": NJUtils.generateRandom()}, true); this.render(); return tex; } this.render = function() { if (!this._srcCanvas) return; var srcCanvas = this._srcCanvas; if (this._isLocal) { this._srcWorld.update(); this._srcWorld.draw(); } var world = this.getDstWorld(); if (!world) { console.log( "no world in GLTexture.render" ); return; } var renderer = world.getRenderer(); var width = srcCanvas.width, height = srcCanvas.height; if (!this.isPowerOfTwo(width) || !this.isPowerOfTwo(height)) { width = this.nextLowerPowerOfTwo( width ); height = this.nextLowerPowerOfTwo( height ); } // create a canvas to be used as the image for the texture map var renderCanvas = this._renderCanvas; if (!renderCanvas) { console.log( "no render canvas in GLTexture.render" ); return; } renderCanvas.width = width; renderCanvas.height = height; var renderCtx = renderCanvas.getContext("2d"); // create the texture var tex = this._texture; if (!tex) { console.log( "no texture in GLTexture.render" ); return; } // copy the source canvas to the context to be used in the texture renderCtx.drawImage(srcCanvas, 0, 0, width, height); /* renderCtx.fillStyle = "#00000a"; renderCtx.fillRect(0, 0, width, height ); var imageData = renderCtx.getImageData(0,0,width, height); for (var i=3; i<imageData.data.length; i+=4) { imageData.data[i] = 128; } */ ///////////////// tex.image = renderCanvas; renderer.commitTexture( tex ); return tex; } this.isPowerOfTwo = function(x) { return (x & (x - 1)) == 0; } this.nextHighestPowerOfTwo = function(x) { --x; for (var i = 1; i < 32; i <<= 1) { x = x | x >> i; } return x + 1; } this.nextLowerPowerOfTwo = function(x) { return this.nextHighestPowerOfTwo(x) >> 1; } this.findCanvas = function( id, elt ) { if (elt.id && elt.id === id) return elt; if (elt.children) { var nKids = elt.children.length; for (var i=0; i<nKids; i++) { var child = elt.children[i]; var canvas = this.findCanvas( id, child ); if (canvas) return canvas; } } } // initialize the object this.init(); } if (typeof exports === "object") { exports.Texture = Texture; }