/* This file contains proprietary software owned by Motorola Mobility, Inc.
No rights, expressed or implied, whatsoever to this software are provided by Motorola Mobility, Inc. hereunder.
(c) Copyright 2011 Motorola Mobility, Inc. All Rights Reserved.
*/ // namespace for the Ninja Canvas Runtime var NinjaCvsRt = NinjaCvsRt || {}; /////////////////////////////////////////////////////////////////////// //Loading webGL/canvas data NinjaCvsRt.initWebGl = function (rootElement, directory) { var cvsDataMngr, ninjaWebGlData = JSON.parse((document.querySelectorAll(['script[data-ninja-webgl]'])[0].innerHTML.replace('(', '')).replace(')', '')); if (ninjaWebGlData && ninjaWebGlData.data) { for (var n=0; ninjaWebGlData.data[n]; n++) { ninjaWebGlData.data[n] = unescape(ninjaWebGlData.data[n]); } } //Creating data manager cvsDataMngr = new NinjaCvsRt.CanvasDataManager(); //Loading data to canvas(es) cvsDataMngr.loadGLData(rootElement, ninjaWebGlData.data, directory); }; /////////////////////////////////////////////////////////////////////// // Class ShapeRuntime // Manages runtime shape display /////////////////////////////////////////////////////////////////////// NinjaCvsRt.CanvasDataManager = function () { this.loadGLData = function(root, valueArray, assetPath ) { if (assetPath) this._assetPath = assetPath.slice(); var value = valueArray; var nWorlds = value.length; for (var i=0; i= 0.001) { var scale = len/sum; rtnVec = []; for (i = 0; i 0.001) ctx.quadraticCurveTo( inset, height-inset, inset+rad, height-inset ); // do the bottom of the rectangle pt = [width - inset, height - inset]; rad = brRad - inset; if (rad < 0) rad = 0; pt[0] -= rad; ctx.lineTo( pt[0], pt[1] ); // get the bottom right arc if (rad > 0.001) ctx.quadraticCurveTo( width-inset, height-inset, width-inset, height-inset-rad ); // get the right of the rectangle pt = [width - inset, inset]; rad = trRad - inset; if (rad < 0) rad = 0; pt[1] += rad; ctx.lineTo( pt[0], pt[1] ); // do the top right corner if (rad > 0.001) ctx.quadraticCurveTo( width-inset, inset, width-inset-rad, inset ); // do the top of the rectangle pt = [inset, inset]; rad = tlRad - inset; if (rad < 0) rad = 0; pt[0] += rad; ctx.lineTo( pt[0], pt[1] ); // do the top left corner if (rad > 0.001) ctx.quadraticCurveTo( inset, inset, inset, inset+rad ); else ctx.lineTo( inset, 2*inset ); } }; this.render = function() { // get the world var world = this.getWorld(); if (!world) throw( "null world in rectangle render" ); // get the context var ctx = world.get2DContext(); if (!ctx) return; // get some dimensions var lw = this._strokeWidth; var w = world.getViewportWidth(), h = world.getViewportHeight(); var c, inset, gradient, colors, len, n, position, cs; // render the fill ctx.beginPath(); if (this._fillColor) { inset = Math.ceil( lw ) + 0.5; if(this._fillColor.gradientMode) { if(this._fillColor.gradientMode === "radial") { gradient = ctx.createRadialGradient(w/2, h/2, 0, w/2, h/2, Math.max(w/2, h/2)-inset); } else { gradient = ctx.createLinearGradient(inset, h/2, w-2*inset, h/2); } colors = this._fillColor.color; len = colors.length; for(n=0; n 0) { p0 = [this._xAdj, this._yAdj]; p1 = [w - this._xAdj, h - this._yAdj]; } else { p0 = [this._xAdj, h - this._yAdj]; p1 = [w - this._xAdj, this._yAdj]; } // draw the line ctx.moveTo( p0[0], p0[1] ); ctx.lineTo( p1[0], p1[1] ); ctx.stroke(); } }; }; /////////////////////////////////////////////////////////////////////// // Class RuntimeOval /////////////////////////////////////////////////////////////////////// NinjaCvsRt.RuntimeOval = function () { // inherit the members of NinjaCvsRt.RuntimeGeomObj this.inheritedFrom = NinjaCvsRt.RuntimeGeomObj; this.inheritedFrom(); this.importJSON = function( jObj ) { this._xOffset = jObj.xoff; this._yOffset = jObj.yoff; this._width = jObj.width; this._height = jObj.height; this._strokeWidth = jObj.strokeWidth; this._strokeColor = jObj.strokeColor; this._fillColor = jObj.fillColor; this._innerRadius = jObj.innerRadius; this._strokeStyle = jObj.strokeStyle; var strokeMaterialName = jObj.strokeMat; var fillMaterialName = jObj.fillMat; this.importMaterials( jObj.materials ); }; this.render = function() { // get the world var world = this.getWorld(); if (!world) throw( "null world in buildBuffers" ); // get the context var ctx = world.get2DContext(); if (!ctx) return; // declare some variables var p0, p1; var x0, y0, x1, y1; // create the matrix var lineWidth = this._strokeWidth; var innerRad = this._innerRadius; var xScale = 0.5*this._width - lineWidth, yScale = 0.5*this._height - lineWidth; // translate var xCtr = 0.5*world.getViewportWidth() + this._xOffset, yCtr = 0.5*world.getViewportHeight() + this._yOffset; var mat = this.MatrixIdentity( 4 ); mat[0] = xScale; mat[12] = xCtr; mat[5] = yScale; mat[13] = yCtr; /* var mat = [ [ xScale, 0.0, 0.0, xCtr], [ 0.0, yScale, 0.0, yCtr], [ 0.0, 0.0, 1.0, 0.0], [ 0.0, 0.0, 0.0, 1.0] ]; */ // get a bezier representation of the circle var bezPts = this.circularArcToBezier( [0,0,0], [1,0,0], 2.0*Math.PI ); if (bezPts) { var n = bezPts.length; var gradient, colors, len, j, position, cs, c; // set up the fill style ctx.beginPath(); ctx.lineWidth = 0; if (this._fillColor) { if(this._fillColor.gradientMode) { if(this._fillColor.gradientMode === "radial") { gradient = ctx.createRadialGradient(xCtr, yCtr, 0, xCtr, yCtr, Math.max(yScale, xScale)); } else { gradient = ctx.createLinearGradient(0, this._height/2, this._width, this._height/2); } colors = this._fillColor.color; len = colors.length; for(j=0; j 0.001) { xScale = 0.5*innerRad*this._width; yScale = 0.5*innerRad*this._height; mat[0] = xScale; mat[5] = yScale; // get the bezier points var bezPtsInside = this.circularArcToBezier( [0,0,0], [1,0,0], -2.0*Math.PI ); if (bezPtsInside) { n = bezPtsInside.length; p = this.transformPoint( bezPtsInside[0], mat ); ctx.moveTo( p[0], p[1] ); index = 1; while (index < n) { p0 = this.transformPoint( bezPtsInside[index], mat ); p1 = this.transformPoint( bezPtsInside[index+1], mat ); x0 = p0[0]; y0 = p0[1]; x1 = p1[0]; y1 = p1[1]; ctx.quadraticCurveTo( x0, y0, x1, y1 ); index += 2; } } } // fill the path ctx.fill(); } // calculate the stroke matrix xScale = 0.5*this._width - 0.5*lineWidth; yScale = 0.5*this._height - 0.5*lineWidth; mat[0] = xScale; mat[5] = yScale; // set up the stroke style ctx.beginPath(); ctx.lineWidth = lineWidth; if (this._strokeColor) { if(this._strokeColor.gradientMode) { if(this._strokeColor.gradientMode === "radial") { gradient = ctx.createRadialGradient(xCtr, yCtr, Math.min(xScale, yScale), xCtr, yCtr, 0.5*Math.max(this._height, this._width)); } else { gradient = ctx.createLinearGradient(0, this._height/2, this._width, this._height/2); } colors = this._strokeColor.color; len = colors.length; for(j=0; j 0.001) { // calculate the stroke matrix xScale = 0.5*innerRad*this._width - 0.5*lineWidth; yScale = 0.5*innerRad*this._height - 0.5*lineWidth; mat[0] = xScale; mat[5] = yScale; // draw the stroke p = this.transformPoint( bezPts[0], mat ); ctx.moveTo( p[0], p[1] ); index = 1; while (index < n) { p0 = this.transformPoint( bezPts[index], mat ); p1 = this.transformPoint( bezPts[index+1], mat ); x0 = p0[0]; y0 = p0[1]; x1 = p1[0]; y1 = p1[1]; ctx.quadraticCurveTo( x0, y0, x1, y1 ); index += 2; } } // render the stroke ctx.stroke(); } } }; /////////////////////////////////////////////////////////////////////// // this function returns the quadratic Bezier approximation to the specified // circular arc. The input can be 2D or 3D, determined by the minimum dimension // of the center and start point. // includedAngle is in radians, can be positiveor negative this.circularArcToBezier= function( ctr_, startPt_, includedAngle ) { var dimen = 3; var ctr = ctr_.slice(); var startPt = startPt_.slice(); // make sure the start point is good var pt = this.vecSubtract(dimen, startPt, ctr); var rad = this.vecMag(dimen, pt); if ((dimen != 3) || (rad <= 0) || (includedAngle === 0)) { if (dimen != 3) console.log( "circularArcToBezier works for 3 dimensional points only. Was " + dimen ); return [ startPt.slice(0), startPt.slice(0), startPt.slice(0) ]; } // determine the number of segments. 45 degree span maximum. var nSegs = Math.ceil( Math.abs(includedAngle)/(0.25*Math.PI) ); if (nSegs <= 0) return [ startPt.slice(0), startPt.slice(0), startPt.slice(0) ]; var dAngle = includedAngle/nSegs; // determine the length of the center control point from the circle center var cs = Math.cos( 0.5*Math.abs(dAngle) ), sn = Math.sin( 0.5*Math.abs(dAngle) ); var c = rad*sn; var h = c*sn/cs; var d = rad*cs + h; var rtnPts = [ this.vecAdd(dimen, pt, ctr) ]; var rotMat = this.MatrixRotationZ( dAngle ); for ( var i=0; i 200.0) this._time = 0.0; } } }; }; NinjaCvsRt.RuntimeRadialGradientMaterial = function () { // inherit the members of NinjaCvsRt.RuntimeMaterial this.inheritedFrom = NinjaCvsRt.RuntimeMaterial; this.inheritedFrom(); this._name = "RadialGradientMaterial"; this._shaderName = "radialGradient"; // setup default values this._color1 = [1,0,0,1]; this._colorStop1 = 0.0; this._color2 = [0,1,0,1]; this._colorStop2 = 0.3; this._color3 = [0,1,0,1]; this._colorStop3 = 0.6; this._color4 = [0,1,0,1]; this._colorStop4 = 1.0; this.init = function() { var material = this._materialNode; if (material) { var technique = material.shaderProgram["default"]; var renderer = RDGE.globals.engine.getContext().renderer; if (renderer && technique) { if (this._shader && this._shader["default"]) { this._shader["default"].u_color1.set( this._color1 ); this._shader["default"].u_color2.set( this._color2 ); this._shader["default"].u_color3.set( this._color3 ); this._shader["default"].u_color4.set( this._color4 ); this._shader["default"].u_colorStop1.set( [this._colorStop1] ); this._shader["default"].u_colorStop2.set( [this._colorStop2] ); this._shader["default"].u_colorStop3.set( [this._colorStop3] ); this._shader["default"].u_colorStop4.set( [this._colorStop4] ); if (this._angle !== undefined) this._shader["default"].u_cos_sin_angle.set([Math.cos(this._angle), Math.sin(this._angle)]); } } } }; this.importJSON = function( jObj ) { this._color1 = jObj.color1; this._color2 = jObj.color2; this._color3 = jObj.color3; this._color4 = jObj.color4; this._colorStop1 = jObj.colorStop1; this._colorStop2 = jObj.colorStop2; this._colorStop3 = jObj.colorStop3; this._colorStop4 = jObj.colorStop4; if (this._angle !== undefined) this._angle = jObj.angle; }; }; NinjaCvsRt.RuntimeLinearGradientMaterial = function () { // inherit the members of NinjaCvsRt.RuntimeMaterial this.inheritedFrom = NinjaCvsRt.RuntimeRadialGradientMaterial; this.inheritedFrom(); this._name = "LinearGradientMaterial"; this._shaderName = "linearGradient"; // the only difference between linear & radial gradient is the existance of an angle for linear. this._angle = 0.0; }; NinjaCvsRt.RuntimeBumpMetalMaterial = function () { // inherit the members of NinjaCvsRt.RuntimeMaterial this.inheritedFrom = NinjaCvsRt.RuntimeMaterial; this.inheritedFrom(); this._name = "BumpMetalMaterial"; this._shaderName = "bumpMetal"; this._lightDiff = [0.3, 0.3, 0.3, 1.0]; this._diffuseTexture = "assets/images/metal.png"; this._specularTexture = "assets/images/silver.png"; this._normalTexture = "assets/images/normalMap.png"; this.importJSON = function( jObj ) { this._lightDiff = jObj.lightDiff; this._diffuseTexture = jObj.diffuseTexture; this._specularTexture = jObj.specularTexture; this._normalTexture = jObj.normalMap; }; this.init = function( world ) { var material = this._materialNode; if (material) { var technique = material.shaderProgram["default"]; var renderer = RDGE.globals.engine.getContext().renderer; if (renderer && technique) { if (this._shader && this._shader["default"]) { technique.u_light0Diff.set( this._lightDiff ); var tex; var wrap = 'REPEAT', mips = true; if (this._diffuseTexture) { tex = renderer.getTextureByName(this._diffuseTexture, wrap, mips ); if (tex) technique.u_colMap.set( tex ); } if (this._normalTexture) { tex = renderer.getTextureByName(this._normalTexture, wrap, mips ); if (tex) technique.u_normalMap.set( tex ); } if (this._specularTexture) { tex = renderer.getTextureByName(this._specularTexture, wrap, mips ); technique.u_glowMap.set( tex ); } } } } }; }; NinjaCvsRt.RuntimeUberMaterial = function () { // inherit the members of NinjaCvsRt.RuntimeMaterial this.inheritedFrom = NinjaCvsRt.RuntimeMaterial; this.inheritedFrom(); this._MAX_LIGHTS = 4; this.init = function( ) { var material = this._materialNode; if (material) { var technique = material.shaderProgram.defaultTechnique; var renderer = RDGE.globals.engine.getContext().renderer; if (renderer && technique) { if (this._shader && this._shader.defaultTechnique) { if (this._ambientColor && technique.u_ambientColor) technique.u_ambientColor.set(this._ambientColor ); if (this._diffuseColor && technique.u_diffuseColor ) technique.u_diffuseColor.set(this._diffuseColor ); if (this._specularColor && technique.u_specularColor) technique.u_specularColor.set(this._specularColor); if (this._specularPower && technique.u_specularPower) technique.u_specularPower.set([this._specularPower]); if (this._lights) { for(var i = 0; i < 4; ++i) { var light = this._lights[i]; if (light) { if(light.type == 'directional') { technique['u_light'+i+'Dir'].set( light.direction || [ 0, 0, 1 ]); } else if(light.type == 'spot') { var deg2Rad = Math.PI / 180; technique['u_light'+i+'Atten'].set(light.attenuation || [ 1,0,0 ]); technique['u_light'+i+'Pos'].set(light.position || [ 0, 0, 0 ]); technique['u_light'+i+'Spot'].set([ Math.cos( ( light.spotInnerCutoff || 45.0 ) * deg2Rad ), Math.cos( ( light.spotOuterCutoff || 90.0 ) * deg2Rad )]); } else { technique['u_light'+i+'Pos'].set(light.position || [ 0, 0, 0 ]); technique['u_light'+i+'Atten'].set(light.attenuation || [ 1,0,0 ]); } // set the common light properties technique['u_light'+i+'Color'].set(light.diffuseColor || [ 1,1,1,1 ]); technique['u_light'+i+'Specular'].set(light.specularColor || [ 1, 1, 1, 1 ]); } } } // currently not exported var uvTransform = [ 2.0, 0, 0, 0, 0, 2.0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 1]; technique.u_uvMatrix.set(uvTransform); var tex = null; if (this._diffuseMap) { tex = renderer.getTextureByName(this._diffuseMap, 'REPEAT'); technique.s_diffuseMap.set( tex ); } if (this._normalMap) { tex = renderer.getTextureByName(this._normalMap, 'REPEAT'); technique.s_normalMap.set( tex ); } if (this._specularMap) { tex = renderer.getTextureByName(this._specularMap, 'REPEAT'); technique.s_specMap.set( tex ); } if(this._environmentMap) { tex = renderer.getTextureByName(this._environmentMap, 'CLAMP'); technique.s_envMap.set( tex ); if (this._environmentAmount) technique.u_envReflection.set([ this._environmentAmount ] ); } } } } }; this.update = function( time ) { }; this.importJSON = function( jObj ) { if (jObj.materialProps) { this._ambientColor = jObj.materialProps.ambientColor; this._diffuseColor = jObj.materialProps.diffuseColor; this._specularColor = jObj.materialProps.specularColor; this._specularPower = jObj.materialProps.specularPower; } var lightArray = jObj.lights; if (lightArray) { this._lights = []; for (var i=0; i 200.0) this._time = 0.0; } } }; };