From b89a7ee8b956c96a1dcee995ea840feddc5d4b27 Mon Sep 17 00:00:00 2001 From: Pierre Frisch Date: Thu, 22 Dec 2011 07:25:50 -0800 Subject: First commit of Ninja to ninja-internal Signed-off-by: Valerio Virgillito --- js/helper-classes/RDGE/src/core/script/renderer.js | 1696 ++++++++++++++++++++ 1 file changed, 1696 insertions(+) create mode 100644 js/helper-classes/RDGE/src/core/script/renderer.js (limited to 'js/helper-classes/RDGE/src/core/script/renderer.js') diff --git a/js/helper-classes/RDGE/src/core/script/renderer.js b/js/helper-classes/RDGE/src/core/script/renderer.js new file mode 100644 index 00000000..0c51d2cb --- /dev/null +++ b/js/helper-classes/RDGE/src/core/script/renderer.js @@ -0,0 +1,1696 @@ +/* +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. +
*/ + +g_renderStats = {}; +g_renderStats.numDrawCalls = new stat("rendering", "numDrawCalls", 0, null, false); +g_renderStats.numTriangles = new stat("rendering", "numTriangles", 0, null, false); +g_renderStats.numVerts = new stat("rendering", "numVerts", 0, null, false); +g_renderStats.numPasses = new stat("rendering", "numPasses", 0, null, false); +g_renderStats.reset = function() { + g_renderStats.numTriangles.value = 0; + g_renderStats.numDrawCalls.value = 0; + g_renderStats.numVerts.value = 0; + g_renderStats.numPasses.value = 0; +}; + +rdgeConstants = {}; + +/* + * clear flags + */ +rdgeConstants.colorBuffer = 0x00004000; +rdgeConstants.depthBuffer = 0x00000100; +rdgeConstants.stencilBuffer = 0x00000400; + +/* +* buffer types +*/ +rdgeConstants.BUFFER_STATIC = 0; +rdgeConstants.BUFFER_DYNAMIC = 1; +rdgeConstants.BUFFER_STREAM = 2; + +/* +* primitive types +*/ +rdgeConstants.POINTS = 0; +rdgeConstants.LINES = 1; +rdgeConstants.LINE_LOOP = 2; +rdgeConstants.LINE_STRIP = 3; +rdgeConstants.TRIANGLES = 4; +rdgeConstants.TRIANGLE_STRIP = 5; +rdgeConstants.TRIANGLE_FAN = 6; + +/* + * primitive data types + */ +rdgeConstants.BYTE = 0x1400; +rdgeConstants.UNSIGNED_BYTE = 0x1401; +rdgeConstants.SHORT = 0x1402; +rdgeConstants.UNSIGNED_SHORT = 0x1403; +rdgeConstants.INT = 0x1404; +rdgeConstants.UNSIGNED_INT = 0x1405; +rdgeConstants.FLOAT = 0x1406; + +/* +* pre-defined vertex element type +*/ +rdgeConstants.VS_ELEMENT_FLOAT4 = 4; +rdgeConstants.VS_ELEMENT_POS = 3; +rdgeConstants.VS_ELEMENT_NORM = 3; +rdgeConstants.VS_ELEMENT_FLOAT3 = 3; +rdgeConstants.VS_ELEMENT_FLOAT2 = 2; +rdgeConstants.VS_ELEMENT_UV = 2; +rdgeConstants.VS_ELEMENT_FLOAT = 1; +rdgeConstants.MAX_ELEM_TYPES = 7; + +// GL Definition of buffer types +rdgeConstants.BUFFER_STATIC = 0x88E0; +rdgeConstants.BUFFER_DYNAMIC = 0x88E4; +rdgeConstants.BUFFER_STREAM = 0x88E8; + +// render constants +rdgeConstants.MAX_MATERIAL_LIGHTS = 4; + +/* +* Material categories determine sorting +* materials support the following categories +*/ +rdgeConstants.categoryEnumeration = +{ + 'BACKGROUND' : 0, + 'OPAQUE' : 1, + 'TRANSPARENT' : 2, + 'ADDITIVE' : 3, + 'TRANSLUCENT' : 4, + 'FOREGROUND' : 5, + 'MAX_CAT' : 6 +}; + +/* + * Node types supported by the scene graph + */ +rdgeConstants.nodeType = +{ + 'TRNODE' : 0, + 'MESHNODE' : 1, + 'MATNODE' : 2, + 'LIGHTNODE' : 3 +}; + +// generate an id for the renderer to map a render buffer to primitive +rdgeId = 0; +function getBufferID() +{ + return rdgeId++; +} + + +_renderer = function(canvas) { + + /* + * Initialize the context associated with this canvas + */ + this.ctx; + + try { + this.ctx = canvas.getContext("experimental-webgl", { preserveDrawingBuffer: true }); // true, true, false, true, true); + + if (!this.ctx) this.ctx = canvas.getContext("webgl", { preserveDrawingBuffer: true }); + if (!this.ctx) this.ctx = canvas.getContext("webkit-3d", { preserveDrawingBuffer: true }); + if (!this.ctx) this.ctx = canvas.getContext("moz-webgl", { preserveDrawingBuffer: true }); + } + catch (err) { } + if (!this.ctx) { + window.console.log("Could not create GL context"); + return null; + } + + // set viewport for the first time + this.ctx.viewport(0, 0, canvas.width, canvas.height); + + // Add a console output to the renderer + this.console = ("console" in window) ? window.console : { log: function() { } }; + + /* + * Set the default clear color + */ + this.ctx.clearColor(1, 0, 0, 1); + + /* + * the clear color of this renderer + */ + this.clearColor = [1, 0, 0, 1]; + + /* + * The clear flags clear color and depth buffers by default + */ + this.clearFlags = this.ctx.COLOR_BUFFER_BIT | this.ctx.DEPTH_BUFFER_BIT + + /* + * clear flags + */ + this.colorBuffer = this.ctx.COLOR_BUFFER_BIT; + this.depthBuffer = this.ctx.DEPTH_BUFFER_BIT; + this.stencilBuffer = this.ctx.STENCIL_BUFFER_BIT; + + /* + * buffer types + */ + this.BUFFER_STATIC = 0; + this.BUFFER_DYNAMIC = 1; + this.BUFFER_STREAM = 2; + + /* + * primitive types + */ + this.POINTS = 0; + this.LINES = 1; + this.LINE_LOOP = 2; + this.LINE_STRIP = 3; + this.TRIANGLES = 4; + this.TRIANGLE_STRIP = 5; + this.TRIANGLE_FAN = 6; + + /* + * primitive data types + */ + this.BYTE = 0x1400; + this.UNSIGNED_BYTE = 0x1401; + this.SHORT = 0x1402; + this.UNSIGNED_SHORT = 0x1403; + this.INT = 0x1404; + this.UNSIGNED_INT = 0x1405; + this.FLOAT = 0x1406; + + /* + * pre-defined vertex element type + */ + this.VS_ELEMENT_FLOAT4 = 4; + this.VS_ELEMENT_POS = 3; + this.VS_ELEMENT_NORM = 3; + this.VS_ELEMENT_FLOAT3 = 3; + this.VS_ELEMENT_FLOAT2 = 2; + this.VS_ELEMENT_UV = 2; + this.VS_ELEMENT_FLOAT = 1; + this.MAX_ELEM_TYPES = 7; + + // GL Definition of buffer types + this.BUFFER_STATIC = 0x88E0; + this.BUFFER_DYNAMIC = 0x88E4; + this.BUFFER_STREAM = 0x88E8; + + // render constants + this.MAX_MATERIAL_LIGHTS = 4; + + // max system textures + this.usedTextureUnits = 5; + + /* + * the renderers current viewport + */ + this.vpX = 0; + this.vpY = 0; + this.vpWidth = canvas.width; + this.vpHeight = canvas.height; + + /* + * the camera manager - contains the camera stack for this render context + */ + this.cameraMan = new cameraManager(); + + /* + * a list of device buffers that are owned by this render context + */ + this.buffers = []; + + + /* + * State wrappers + */ + this.cullBackFace = function() { + this.ctx.cullFace(this.ctx.Back); + } + + this.cullFrontFace = function() { + this.ctx.cullFace(this.ctx.FRONT); + } + + this.disableCulling = function() { + this.ctx.disable(this.ctx.CULL_FACE); + } + + this.enableCulling = function() { + this.ctx.enable(this.ctx.CULL_FACE); + } + + this.enablePolyOffsetFill = function() { + this.ctx.enable(this.ctx.POLYGON_OFFSET_FILL); + } + + this.disablePolyOffsetFill = function() { + this.ctx.enable(this.ctx.POLYGON_OFFSET_FILL); + } + + this.enablePointSprites = function() { +// this.ctx.enable(0x8642); + } + + this.disablePointSprites = function() { +// this.ctx.enable(0x8642); + } + + this.setClearColor = function(color) { + this.clearColor = color.slice(); + this.ctx.clearColor(color[0], color[1], color[2], color[3]); + } + + /* + * flags that specify how to clear the scene, can be OR'ed together + */ + this.setClearFlags = function(flags) { + this.clearFlags = flags; + } + + /* + * called by the system to clear the video buffer according to pre-set flags + */ + this._clear = function() { + this.ctx.clear(this.clearFlags); + } + + /* + * clears the video buffer with flags provided + */ + this.clear = function(flags) { + this.ctx.clear(flags); + } + + /* + * flush the video buffer + */ + this.flush = function() { + this.ctx.flush(); + } + + /* + * Sets the current viewport + */ + this.setViewPort = function(x, y, width, height) { + this.vpX = x; + this.vpY = y; + this.vpWidth = width; + this.vpHeight = height; + this.ctx.viewport(this.vpX, this.vpY, this.vpWidth, this.vpHeight); + } + + /* + * access the camera manager associated with the renderer + */ + this.cameraManager = function() { + return this.cameraMan; + } + + /* + * Sets of texture maps owned by the renderer + */ + this.textureMap = []; + this.rttMap = []; + + /* + * gets the texture by name or creates the texture requested + * @param name - the name of the texture to try and get + * @param wrap - optional "CLAMP or "REPEAT", default is clamp + * @param mips - optional true/false value to create mipmaps, the default is true + */ + this.getTextureByName = function(name, wrap, mips) { + var ext = name.split('.')[1]; + + if (!ext) + ext = ".png"; + else + ext = ""; + + var tex = this.textureMap[name]; + + if (tex === undefined) { + + + // load the texture + tex = this.createTexture(name + ext, wrap, mips); + this.textureMap[name] = tex; + tex.lookUpName = name; + } + + return tex; + + }; + + /* + * creates a texture from the given URL + * @param url - the resource location + * @param wrap - optional "CLAMP or "REPEAT", default is clamp + * @param mips - optional true/false value to create mipmaps, the default is true + */ + _texparams = function(wrap, mips) { this.wrap = wrap, this.mips = mips }; + this.createTexture = function(url, wrap, mips) { + var texture = this.ctx.createTexture(); + + if (wrap === undefined) + wrap = "CLAMP"; + if (mips === undefined) + mips = true; + + if (texture) { + texture.image = new Image(); + texture.image.src = url; + texture.image.context = g_Engine.getContext(); + texture.texparams = new _texparams(wrap, mips); + texture.image.onload = function() { + var stateMan = this.context.ctxStateManager; + stateMan.RDGEInitState.loadTexture(texture); + }; + } + return texture; + } + + /* + * commits a texture to video memory + * @param - the texture object created by a call to create texture + */ + this.commitTexture = function(texture) { + this.ctx.bindTexture(this.ctx.TEXTURE_2D, texture); + this.ctx.texImage2D(this.ctx.TEXTURE_2D, 0, this.ctx.RGBA, this.ctx.RGBA, this.ctx.UNSIGNED_BYTE, texture.image); + + if (texture.texparams.mips) + this.ctx.generateMipmap(this.ctx.TEXTURE_2D); + + this.ctx.texParameteri(this.ctx.TEXTURE_2D, this.ctx.TEXTURE_MAG_FILTER, this.ctx.LINEAR); + this.ctx.texParameteri(this.ctx.TEXTURE_2D, this.ctx.TEXTURE_MIN_FILTER, texture.texparams.mips ? this.ctx.LINEAR_MIPMAP_LINEAR : this.ctx.LINEAR); + this.ctx.texParameteri(this.ctx.TEXTURE_2D, this.ctx.TEXTURE_WRAP_S, texture.texparams.wrap === "REPEAT" ? this.ctx.REPEAT : this.ctx.CLAMP_TO_EDGE); + this.ctx.texParameteri(this.ctx.TEXTURE_2D, this.ctx.TEXTURE_WRAP_T, texture.texparams.wrap === "REPEAT" ? this.ctx.REPEAT : this.ctx.CLAMP_TO_EDGE); + + this.ctx.bindTexture(this.ctx.TEXTURE_2D, null); + } + + this.verify = function(label) { + var error = this.ctx.getError(); + if (error != 0) { + window.console.log("GLError ( " + label + ") : " + error); + } + } + + this.createRenderTargetTexture = function(lookUpName, width, height, generateMips) { + var ctx = this.ctx; + // create framebuffer + var renderTargetFrameBuffer = ctx.createFramebuffer(); + ctx.bindFramebuffer(ctx.FRAMEBUFFER, renderTargetFrameBuffer); + + // setup parameters (width, hight, filtering) + renderTargetFrameBuffer.width = width; + renderTargetFrameBuffer.height = height; + + // create the texture + var renderTarget = ctx.createTexture(); + ctx.bindTexture(ctx.TEXTURE_2D, renderTarget); + + try { + // Do it the way the spec requires + ctx.texImage2D(ctx.TEXTURE_2D, 0, ctx.RGBA, renderTargetFrameBuffer.width, renderTargetFrameBuffer.height, 0, ctx.RGBA, ctx.UNSIGNED_BYTE, null); + } catch (exception) { + // Workaround for what appears to be a Minefield bug. + var textureStorage = new WebctxUnsignedByteArray(renderTargetFrameBuffer.width * renderTargetFrameBuffer.height * 4); + ctx.texImage2D(ctx.TEXTURE_2D, 0, ctx.RGBA, renderTargetFrameBuffer.width, renderTargetFrameBuffer.height, 0, ctx.RGBA, ctx.UNSIGNED_BYTE, textureStorage); + } + + ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MAG_FILTER, ctx.LINEAR); + ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MIN_FILTER, generateMips ? ctx.LINEAR_MIPMAP_NEAREST : ctx.LINEAR); + ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_WRAP_S, ctx.CLAMP_TO_EDGE); + ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_WRAP_T, ctx.CLAMP_TO_EDGE); + + if (generateMips) { + ctx.generateMipmap(ctx.TEXTURE_2D); + } + + // set frame buffer storage and texture + var renderBuffer = ctx.createRenderbuffer(); + ctx.bindRenderbuffer(ctx.RENDERBUFFER, renderBuffer); + ctx.renderbufferStorage(ctx.RENDERBUFFER, ctx.DEPTH_COMPONENT16, renderTargetFrameBuffer.width, renderTargetFrameBuffer.height); + + // bind + var error = ctx.getError(ctx.bindFramebuffer(ctx.FRAMEBUFFER, renderTargetFrameBuffer)); + error = ctx.getError(ctx.bindRenderbuffer(ctx.RENDERBUFFER, renderBuffer)); + error = ctx.getError(ctx.renderbufferStorage(ctx.RENDERBUFFER, ctx.DEPTH_COMPONENT16, renderTargetFrameBuffer.width, renderTargetFrameBuffer.height)); + + ctx.bindRenderbuffer(ctx.RENDERBUFFER, null); + + // bind texture handle and renderBuffer to frame buffer + error = ctx.getError(ctx.framebufferTexture2D(ctx.FRAMEBUFFER, ctx.COLOR_ATTACHMENT0, ctx.TEXTURE_2D, renderTarget, 0)); + + error = ctx.getError(ctx.framebufferRenderbuffer(ctx.FRAMEBUFFER, ctx.DEPTH_ATTACHMENT, ctx.RENDERBUFFER, renderBuffer)); + + ctx.bindFramebuffer(ctx.FRAMEBUFFER, null); + + /* + var status=ctx.checkFramebufferStatus(ctx.FRAMEBUFFER); + switch(status) { + case ctx.FRAMEBUFFER_COMPLETE: + break; + case ctx.FRAMEBUFFER_INCOMPLETE_ATTACHMENT: + ctx.console.log("Incomplete framebuffer: FRAMEBUFFER_INCOMPLETE_ATTACHMENT"); + return null; + case ctx.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: + ctx.console.log("Incomplete framebuffer: FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT"); + return null; + case ctx.FRAMEBUFFER_INCOMPLETE_DIMENSIONS: + ctx.console.log("Incomplete framebuffer: FRAMEBUFFER_INCOMPLETE_DIMENSIONS"); + return null; + case ctx.FRAMEBUFFER_UNSUPPORTED: + ctx.console.log("Incomplete framebuffer: FRAMEBUFFER_UNSUPPORTED"); + return null; + default: + ctx.console.log("Incomplete framebuffer: "+status); + return null; + } + */ + + // unbind + ctx.bindTexture(ctx.TEXTURE_2D, null); + ctx.bindRenderbuffer(ctx.RENDERBUFFER, null); + ctx.bindFramebuffer(ctx.FRAMEBUFFER, null); + + renderTarget.id = "RT_" + nodeIdGen.getId(); + + renderTarget.frameBuffer = renderTargetFrameBuffer; + + if (this.textureMap[lookUpName]) + window.console.log("Notification: render target: " + lookUpName + " has overwritten an existing render target"); + + // add to lookup map + this.textureMap[lookUpName] = renderTarget; + + return renderTarget; + } + + + + /* + * The default shader setup + */ + this.defaultShaderDefintion = { + 'shaders': { + 'defaultVShader': "assets/shaders/test_vshader.glsl", + 'defaultFShader': "assets/shaders/test_fshader.glsl" + }, + 'techniques': { + 'defaultTechnique': [{ + 'vshader': 'defaultVShader', + 'fshader': 'defaultFShader', + // attributes + 'attributes': + { + 'vert': { 'type': 'vec3' }, + 'normal': { 'type': 'vec3' }, + 'texcoord': { 'type': 'vec2' } + }, + // parameters + 'params': + { + }, + + // render states + 'states': + { + 'depthEnable': true, + 'blendEnable': false, + 'culling': true, + 'cullFace': "BACK" + } +}] + } + }; + + + }; + +/* + * Shader definitions + */ + +/* + * The default shader setup + */ +rdgeDefaultShaderDefintion = { + 'shaders': { + 'defaultVShader':"assets/shaders/test_vshader.glsl", + 'defaultFShader':"assets/shaders/test_fshader.glsl" + }, + 'techniques': { + 'defaultTechnique':[{ + 'vshader' : 'defaultVShader', + 'fshader' : 'defaultFShader', + // attributes + 'attributes' : + { + 'vert' : { 'type' : 'vec3' }, + 'normal' : { 'type' : 'vec3' }, + 'texcoord' : { 'type' : 'vec2' } + }, + // parameters + 'params' : + { + }, + + // render states + 'states' : + { + 'depthEnable' : true, + 'blendEnable' : false, + 'culling' : true, + 'cullFace' : "BACK" + } + }]}}; + +/* + * The default depth map shader techniques + */ +rdgeDepthMapShaderDef = { +'shaders': { + 'depthMapVShader':"assets/shaders/depthMap_vshader.glsl", + 'depthMapFShader':"assets/shaders/depthMap_fshader.glsl" + }, +'techniques': +{ + 'shadowDepthMap': + [{ + 'vshader' : 'depthMapVShader', + 'fshader' : 'depthMapFShader', + // attributes + 'attributes' : + { 'vert' : { 'type' : 'vec3' }, + 'normal' : { 'type' : 'vec3' }, + 'texcoord' : { 'type' : 'vec2' } }, + // parameters + 'params' :{ }, + // render states + 'states' : + { 'depthEnable' : true, + 'blendEnable' : false, + 'culling' : true, + 'cullFace' : "BACK"} + }], + 'depthMap': + [{ + 'vshader' : 'depthMapVShader', + 'fshader' : 'depthMapFShader', + // attributes + 'attributes' : + { 'vert' : { 'type' : 'vec3' }, + 'normal' : { 'type' : 'vec3' }, + 'texcoord' : { 'type' : 'vec2' } }, + // parameters + 'params' :{ }, + // render states + 'states' : + { 'depthEnable' : true, + 'blendEnable' : false, + 'culling' : true, + 'cullFace' : "BACK"} + }] + +}}; + +/* + * capture normals in view space + */ +rdgeViewSpaceNormalsShader = { +'shaders': { + 'normalsVShader':"assets/shaders/norm_depth_vshader.glsl", + 'normalsFShader':"assets/shaders/norm_depth_fshader.glsl" + }, +'techniques': +{ + 'depthMapWNormal': + [{ + 'vshader' : 'normalsVShader', + 'fshader' : 'normalsFShader', + // attributes + 'attributes' : + { 'vert' : { 'type' : 'vec3' }, + 'normal' : { 'type' : 'vec3' }}, + // parameters + 'params' :{ }, + // render states + 'states' : + { 'depthEnable' : true, + 'blendEnable' : false, + 'culling' : true, + 'cullFace' : "BACK"} + }] + +}}; + +/* + * basic screen squad shader definition + */ +rdgeScreenQuadShaderDef = { + 'shaders': { + // Texture coordinates are setup so that the full texture + // is mapped completely onto the screen + 'screenQuadVShader': "\ + attribute vec3 a_pos;\ + attribute vec2 a_uv;\ + uniform float u_inv_viewport_width;\ + uniform float u_inv_viewport_height;\ + varying vec2 vTexcoord;\ + void main()\ + {\ + gl_Position = vec4(a_pos.xy, 0.0, 1.0);\ + \ + vTexcoord.x = 0.5 * (1.0 + a_pos.x + u_inv_viewport_width);\ + vTexcoord.y = 0.5 * (1.0 - a_pos.y + u_inv_viewport_height);\ + }", + 'screenQuadFShader': "\ + precision highp float;\ + uniform sampler2D u_mainRT;\ + uniform sampler2D u_glowFinal;\ + uniform sampler2D u_ssaoRT;\ + uniform sampler2D u_shadowMap;\ + varying vec2 vTexcoord;\ + void main()\ + {\ + vec2 tex = vec2(vTexcoord.x, 1.0 - vTexcoord.y);\ + vec4 glowTexel = texture2D(u_glowFinal, tex);\ + vec4 ssaoTexel = texture2D(u_ssaoRT, tex);\ + vec4 smapCoef = texture2D(u_shadowMap, tex);\ + ssaoTexel.a = 0.0;\ + vec4 texel = texture2D(u_mainRT, tex);\ + gl_FragColor = vec4(texel.r*((1.0 - glowTexel.r)*smapCoef.r), texel.g*((1.0 - glowTexel.g)*smapCoef.g), texel.b*((1.0 - glowTexel.b)*smapCoef.b), texel.a) + glowTexel - ssaoTexel;\ + }" + }, + 'techniques': { + // rendering control + 'screenQuad':[{ + 'vshader' : 'screenQuadVShader', + 'fshader' : 'screenQuadFShader', + + // attributes + 'attributes' :{ + 'a_pos' : { 'type' : 'vec3' }, + 'a_uv' : { 'type' : 'vec2' } }, + 'params' : { + 'u_mainRT' : {'type' : "tex2d"}, + 'u_glowFinal' : {'type' : "tex2d", 'data':"assets/images/black"}, + 'u_ssaoRT' : {'type' : "tex2d", 'data':"assets/images/black"}, + 'u_shadowMap' : {'type' : "tex2d", 'data':"assets/images/white"}}, + // render states + 'states' : { + 'blendEnabled' : true, + 'srcBlend' : 'SRC_ALPHA', + 'dstcBlend' : 'ONE_MINUS_SRC_ALPHA' } + }] + } +} + +/* + * creates the glow map + */ +rdgeGlowMapShader = { + 'shaders': { + 'createGlowVShader':"assets/shaders/glowMap_vshader.glsl", + 'createGlowFShader':"assets/shaders/glowMap_fshader.glsl" + }, + 'techniques': { + 'createGlowMap':[ + { + 'vshader' : 'createGlowVShader', + 'fshader' : 'createGlowFShader', + // attributes + 'attributes' : + { + 'vert' : { 'type' : 'vec3' }, + 'normal' : { 'type' : 'vec3' }, + 'texcoord' : { 'type' : 'vec2' } + }, + // parameters + 'params' : + { + }, + + // render states + 'states' : + { + 'depthEnable' : true, + 'blendEnable' : false, + 'culling' : true, + 'cullFace' : "BACK" + } + } + ]} +} + +/* +* Gaussian blur shader +*/ +rdgeGaussianBlurShader = { + 'shaders': { + 'blurVShader':"assets/shaders/separableBlur_vshader.glsl", + 'blurFShader':"assets/shaders/separableBlur_fshader.glsl" + }, + 'techniques': { + 'gaussianBlur':[ + { + 'vshader' : 'blurVShader', + 'fshader' : 'blurFShader', + // attributes + 'attributes' : + { + 'vert' : { 'type' : 'vec3' }, + 'texcoord' : { 'type' : 'vec2' } + }, + // parameters + 'params' : + { + 'vCoeffs' : {'type' :'vec3', 'data': [ 5.0 / 16.0, 6.0 / 16.0, 5.0 / 16.0 ]}, + 'vOffset' : {'type' : 'vec2', 'data': [0.00617, 0.00617]}, + 'u_weight' : {'type' : 'float', 'data': [1.0]}, + 'sTexture': {'type' : "tex2d"} + }, + // render states + 'states' : + { + 'culling' : false + } + } + ] +}} + +/* +* Screen space ambient occlusion shader +*/ +rdgeSSAOShader = { + 'shaders': { + 'blurVShader':"assets/shaders/ssao_vshader.glsl", + 'blurFShader':"assets/shaders/ssaohr_fshader.glsl" + }, + 'techniques': { + 'ssao':[ + { + 'vshader' : 'blurVShader', + 'fshader' : 'blurFShader', + // attributes + 'attributes' : + { + 'vert' : { 'type' : 'vec3' }, + 'texcoord' : { 'type' : 'vec2' } + }, + // parameters + 'params' : + { + 'u_normalsRT' : {'type' : "tex2d"}, + 'u_depthMap' : {'type' : "tex2d"}, + 'sRandMap' : {'type' : "tex2d", 'data':"assets/images/random_normal.png", 'wrap':"REPEAT", 'mips':false}, + 'u_cameraFTR' : {'type' :'vec3'}, + 'u_artVals' : {'type' :'vec4', 'data':[0.36, 0.75, 0.60, 0.05]}, // sample radius, intensity, distScale, bias + 'u_randMapSize' : {'type' :'float', 'data':[64.0]}, + 'u_screenSize' : {'type' :'vec2', 'data':[1024, 1024]} + }, + // render states + 'states' : + { + 'culling' : false + } + } + ] +}} + +/* + * Shadow map generation + */ +rdgeShadowMapShader = { + 'shaders': { + 'shadowMapVShader':"assets/shaders/shadowMap_vshader.glsl", + 'shadowMapFShader':"assets/shaders/shadowMap_fshader.glsl" + }, + 'techniques': { + 'shadowMap':[ + { + 'vshader' : 'shadowMapVShader', + 'fshader' : 'shadowMapFShader', + // attributes + 'attributes' : + { + 'a_pos' : { 'type' : 'vec3' }, + 'a_uv' : { 'type' : 'vec2' } + }, + // parameters + 'params' : + { + 'u_lightSize' : { 'type' : 'float', 'data' : [7.93]}, + // color is inverted, alpha represents intensity and is not inverted + 'u_shadowColor' : { 'type' : 'vec4', 'data' : [0.922, 0.7373, 0.4824, 0.5]} + }, + // render states + 'states' : + { + 'depthEnable' : true, + 'blendEnable' : false, + 'culling' : true, + 'cullFace' : "BACK" + } + } + ] +}} + +/* + * Noise blur filter + */ +rdgeNoiseBlurShader = { + 'shaders': { + 'blurVShader':"assets/shaders/noiseBlur_vshader.glsl", + 'blurFShader':"assets/shaders/noiseBlur_fshader.glsl" + }, + 'techniques': { + 'blur':[ + { + 'vshader' : 'blurVShader', + 'fshader' : 'blurFShader', + // attributes + 'attributes' : + { + 'a_pos' : { 'type' : 'vec3' }, + 'a_uv' : { 'type' : 'vec2' } + }, + // parameters + 'params' : + { + 'u_blurSourceMap': {'type' : "tex2d"} + }, + // render states + 'states' : + { + 'culling' : false + } + } + ] +}} + +/* +* defines a primitive using java script native types +*/ +function rdgePrimitiveDefinition() { + + /* + * The type of primitive + * supported types are + * renderer.POINTS + * renderer.LINES + * renderer.LINE_LOOP + * renderer.LINE_STRIP + * renderer.TRIANGLES + * renderer.TRIANGLE_STRIP + * renderer.TRIANGLE_FAN + */ + this.type = rdgeConstants.TRIANGLE_STRIP; + + /* + * Define vertex elements size in bytes and order the element appears in the stream + * Predefined size types: + * renderer.VS_ELEMENT_FLOAT4 + * renderer.VS_ELEMENT_FLOAT3 + * renderer.VS_ELEMENT_FLOAT2 + * renderer.VS_ELEMENT_FLOAT + * renderer.VS_ELEMENT_UINT16 + * renderer.VS_ELEMENT_UINT8 + */ + this.vertexDefinition= + { + // usage example: two ways of declaring a float 3 stream + //"vert" :{ 'type':renderer.VS_ELEMENT_POS, 'bufferIndex':indexIntoBufferStream, 'usage': renderer.BUFFER_STATIC } + //"a_pos" :{ 'type':renderer.VS_ELEMENT_POS, 'bufferIndex':indexIntoBufferStream, 'usage': renderer.BUFFER_STATIC } + }; + + /* + * Arrays of buffer data listed in the order given by the vertex definition + */ + this.bufferStreams= + [ + + ]; + + /* + * An array indicating the the stream usage listed in the order given by the vertex definition + * Valid usage values: renderer.BUFFER_STATIC The data store contents will be specified once by the application, and used many times + * renderer.BUFFER_DYNAMIC The data store contents will be respecified repeatedly by the application, and used many times + * renderer.BUFFER_STREAM The data store contents will be specified once by the application, and used at most a few times + */ + this.streamUsage= + [ + + ]; + + /* + * indicates the the stream usage of the index buffer + * Valid usage values: renderer.BUFFER_STATIC The data store contents will be specified once by the application, and used many times + * renderer.BUFFER_DYNAMIC The data store contents will be respecified repeatedly by the application, and used many times + * renderer.BUFFER_STREAM The data store contents will be specified once by the application, and used at most a few times + */ + this.indexUsage = rdgeConstants.BUFFER_STREAM; + + /* + * a references to an array of indices + */ + this.indexBuffer= + [ + ]; + + /* + * the number of sets of geometry in this primitive + */ + this.setCount = 0; + + /* + * Offset of a primitive in an index buffer + * if the primitive represents a set each set array has a corresponding index offset + */ + this.indexOffsets = + [ + ]; + + ////////////////////////////////////////////////////////////// + // OUTPUT VALUES // + ////////////////////////////////////////////////////////////// + + /* + * the number of coordinates's that make this primitive + * auto populated with a call to renderer.createPrimitive + */ + this.posCount = 0; + + /* + * the number of triangle that make up this primitive + * auto populated with a call to renderer.createPrimitive + */ + this.triCount = 0; + + /* + * the number of indices in the primitive + * auto populated with a call to renderer.createPrimitive + */ + this.indexCount = 0; + + /* + * size of an index value in bytes + */ + this.indexElementSize = rdgeConstants.UNSIGNED_SHORT; + + /* + * bufferHanldes are created when passing a primitive to renderer.createPrimitive + * An array of handles to buffers in vram, listed in the order given by the vertex definition + */ + this.bufferHandles = + [ + ]; + + /* + * An index into the buffers table for the render context that created the buffer + */ + this.buffersID = -1; + + /* + * Handle to index buffer object + */ + this.indexHandle = null; + + + /* + * ------------------- Double buffer Setup----------------------------- + */ + + /* + * user flag used to create a double buffered primitive + * Double buffer flag - when double buffered a .front() and .back() buffer + * are available as well as a call .flip() to flip the buffers + */ + this.useDoubleBuffer = false; + + /* + * The double buffer offset tells the renderer where in its 'bufferID' array for this primitive the 'doubled' buffers begin + */ + this.doubleBufferOffset = 0; + + /* + * Keeps track of which buffer is the front buffer or active buffer + */ + this.frontBufferIndex = 0; + + /* + * Helper function for retrieving the buffer for editing - successfully calling this makes the buffer dirty and will trigger a buffer swap + * @param bufIndex - buffer stream index + * @return buffer stream requested, or null if invalid index is given + */ + this.update = function( bufIndex ) + { + if(!this.bufferStreams[bufIndex]) + return null; + + this.bufferStreams[bufIndex].dirty = true; + return this.bufferStreams[bufIndex]; + } + + + /* + * Flips the front and back buffers + */ + this.flip = function( renderer ) + { + if(this.useDoubleBuffer === true) + { + // if a back buffer is dirty update it + for(var i = 0, len = this.bufferStreams.length; i < len; ++i) + { + if(this.bufferStreams[i].dirty) + { + this.bufferStreams[i].dirty = false; + renderer.updateBuffer(renderer.buffers[this.buffersID][this.frontBufferIndex*this.doubleBufferOffset + i], this.bufferStreams[i], this.streamUsage[i]); + this.frontBufferIndex = 1 - this.frontBufferIndex; + } + } + } + } +} + +/* +* @param bufferSizeOrData: an array of indices, or the size in bytes to preallocate +* @param bufferUsage: BUFFER_STATIC The data store contents will be specified once by the application, and used many times +* BUFFER_DYNAMIC The data store contents will be respecified repeatedly by the application, and used many times +* BUFFER_STREAM The data store contents will be specified once by the application, and used at most a few times +* @return an unsigned short index buffer object +*/ +_renderer.prototype.createIndexBufferUINT16 = function( bufferSizeOrData, bufferUsage ) +{ + var bufferObject = this.ctx.createBuffer(); + bufferObject.type = bufferSizeOrData.type; + this.ctx.bindBuffer(this.ctx.ELEMENT_ARRAY_BUFFER, bufferObject); + this.ctx.bufferData(this.ctx.ELEMENT_ARRAY_BUFFER, (typeof k == "number") + ? bufferSizeOrData + : new Uint16Array(bufferSizeOrData), bufferUsage); + return bufferObject; +} + +/* +* @param bufferSizeOrData: an array of indices, or the size in bytes to preallocate +* @param bufferUsage: BUFFER_STATIC The data store contents will be specified once by the application, and used many times +* BUFFER_DYNAMIC The data store contents will be respecified repeatedly by the application, and used many times +* BUFFER_STREAM The data store contents will be specified once by the application, and used at most a few times +* @return an unsigned byte index buffer object +*/ +_renderer.prototype.createIndexBufferUINT8 = function( bufferSizeOrData, bufferUsage ) +{ + var bufferObject = this.ctx.createBuffer(); + bufferObject.type = bufferSizeOrData.type; + this.ctx.bindBuffer(this.ctx.ELEMENT_ARRAY_BUFFER, bufferObject); + this.ctx.bufferData(this.ctx.ELEMENT_ARRAY_BUFFER, (typeof k == "number") + ? bufferSizeOrData + : new Uint8Array(bufferSizeOrData), bufferUsage); + return bufferObject; +} + +/* +* @param bufferSizeOrData: a buffer of data the represents a stream in a vertex, or the size in bytes to preallocate +* @param bufferUsage: BUFFER_STATIC The data store contents will be specified once by the application, and used many times +* BUFFER_DYNAMIC The data store contents will be respecified repeatedly by the application, and used many times +* BUFFER_STREAM The data store contents will be specified once by the application, and used at most a few times +* @return an unsigned byte index buffer object +*/ +_renderer.prototype.createBufferFLOAT32 = function( bufferSizeOrData, bufferUsage ) +{ + var bufferObject = this.ctx.createBuffer(); + bufferObject.type = bufferSizeOrData.type; + this.ctx.bindBuffer(this.ctx.ARRAY_BUFFER, bufferObject); + this.ctx.bufferData(this.ctx.ARRAY_BUFFER, (typeof k == "number") + ? bufferSizeOrData + : new Float32Array(bufferSizeOrData), bufferUsage); + return bufferObject; +} + +/* +* @param bufferSizeOrData: a buffer of data the represents a stream in a vertex, or the size in bytes to preallocate +* @param bufferUsage: BUFFER_STATIC The data store contents will be specified once by the application, and used many times +* BUFFER_DYNAMIC The data store contents will be respecified repeatedly by the application, and used many times +* BUFFER_STREAM The data store contents will be specified once by the application, and used at most a few times +* @return an unsigned byte index buffer object +*/ +_renderer.prototype.createBufferINT32 = function(bufferSizeOrData,bufferUsage) { + var bufferObject=this.ctx.createBuffer(); + bufferObject.type=bufferSizeOrData.type; + this.ctx.bindBuffer(this.ctx.ARRAY_BUFFER, bufferObject); + this.ctx.bufferData(this.ctx.ARRAY_BUFFER, (typeof k == "number") + ? bufferSizeOrData + : new Int32Array(bufferSizeOrData), bufferUsage); + return bufferObject; +} + +/* +* @param bufferSizeOrData: a buffer of data the represents a stream in a vertex, or the size in bytes to preallocate +* @param bufferUsage: BUFFER_STATIC The data store contents will be specified once by the application, and used many times +* BUFFER_DYNAMIC The data store contents will be respecified repeatedly by the application, and used many times +* BUFFER_STREAM The data store contents will be specified once by the application, and used at most a few times +* @return an unsigned byte index buffer object +*/ +_renderer.prototype.createBufferINT16 = function(bufferSizeOrData,bufferUsage) { + var bufferObject=this.ctx.createBuffer(); + bufferObject.type=bufferSizeOrData.type; + this.ctx.bindBuffer(this.ctx.ARRAY_BUFFER, bufferObject); + this.ctx.bufferData(this.ctx.ARRAY_BUFFER, (typeof k == "number") + ? bufferSizeOrData + : new Int16Array(bufferSizeOrData), bufferUsage); + return bufferObject; +} + +_renderer.prototype.updateBuffer = function( dstBuffer, srcBuffer, bufferUsage, vertexOffset ) +{ + this.ctx.bindBuffer(this.ctx.ARRAY_BUFFER, dstBuffer); + if(bufferUsage === rdgeConstants.BUFFER_DYNAMIC) + { + // use bufferSubData + this.ctx.bufferSubData(this.ctx.ARRAY_BUFFER, vertexOffset || 0, new Float32Array(srcBuffer)); + } + else + { + // re-create the buffer + this.ctx.bufferData(this.ctx.ARRAY_BUFFER, new Float32Array(srcBuffer), bufferUsage); + } +} + +/* + * @param primitiveDef defines a primitive using java script types, creates the video ram objects and attaches them to the primitive passed in + */ +_renderer.prototype.createPrimitive = function( primitiveDef ) +{ + if(!primitiveDef.built) + { + // store the buffer handle with the renderer as it is context specific, creating an ID to look up the buffer at render time + primitiveDef.buffersID = getBufferID(); + primitiveDef.built = true; + } + else if(this.buffers[primitiveDef.buffersID]) + { + // already created + return; + } + + // this mapping in the array holds an array of buffers + this.buffers[primitiveDef.buffersID] = []; + this.buffers[primitiveDef.buffersID].ctxId = this.id; + + // set up buffers + this.updatePrimitive(primitiveDef); +} + +/* + * @param primitiveDef defines a primitive using java script types, creates the video ram objects and attaches them to the primitive passed in + */ + _renderer.prototype.updatePrimitive = function( prim ) +{ + if(!prim.built) + { + this.createPrimitive(prim); + return; + } + + var bufIdxVisited = []; + + for(var e in prim.vertexDefinition) + { + var vert_element = prim.vertexDefinition[e]; + + if(bufIdxVisited.indexOf(vert_element.bufferIndex) > -1) + continue; + bufIdxVisited.push(vert_element.bufferIndex); + + vert_element.debugName = e + " buffer"; + + // flag the positional data + if(vert_element.type == this.VS_ELEMENT_POS) + { + prim.posCount = prim.bufferStreams[vert_element.bufferIndex].length; + + // save a reference to the coordinates for later + prim.positions = prim.bufferStreams[vert_element.bufferIndex]; + } + + // if we have not already created the buffer - do so now + if(this.buffers[prim.buffersID][vert_element.bufferIndex] == undefined) + { + prim.bufferStreams[vert_element.bufferIndex].type = e + " PrimaryBuffer"; + + if(prim.forceVertexCount) + { + this.buffers[prim.buffersID][vert_element.bufferIndex] = this.createBufferFLOAT32( 4 * prim.forceVertexCount, vert_element.bufferUsage ); + this.ctx.bufferSubData(this.ctx.ARRAY_BUFFER, 0, new Float32Array(prim.bufferStreams[vert_element.bufferIndex]), vert_element.bufferUsage ); + } + else + { + this.buffers[prim.buffersID][vert_element.bufferIndex] = this.createBufferFLOAT32( prim.bufferStreams[vert_element.bufferIndex], vert_element.bufferUsage ); + } + } + else + { + this.ctx.bindBuffer(this.ctx.ARRAY_BUFFER, this.buffers[prim.buffersID][vert_element.bufferIndex]); + this.ctx.bufferSubData(this.ctx.ARRAY_BUFFER, 0, new Float32Array(prim.bufferStreams[vert_element.bufferIndex]), vert_element.bufferUsage ); + } + + // double up the buffer + if(prim.useDoubleBuffer === true) + { + prim.doubleBufferOffset = prim.bufferStreams.length + + // debug data + prim.bufferStreams[vert_element.bufferIndex].type = e + " SecondaryBuffer"; + + // store double buffer at the doubleBuffer offset + if(this.buffers[prim.buffersID][prim.doubleBufferOffset + vert_element.bufferIndex] == undefined) + { + if(prim.forceVertexCount) + { + this.buffers[prim.buffersID][prim.doubleBufferOffset + vert_element.bufferIndex] = this.createBufferFLOAT32( 4 * prim.prim.forceVertexCount, vert_element.bufferUsage ); + this.ctx.bufferSubData(this.ctx.ARRAY_BUFFER, 0, new Float32Array(prim.bufferStreams[vert_element.bufferIndex]), vert_element.bufferUsage ); + } + else + { + this.buffers[prim.buffersID][prim.doubleBufferOffset + vert_element.bufferIndex] = this.createBufferFLOAT32( prim.bufferStreams[vert_element.bufferIndex], vert_element.bufferUsage ); + } + } + else + { + this.ctx.bindBuffer(this.ctx.ARRAY_BUFFER, this.buffers[prim.buffersID][prim.doubleBufferOffset + vert_element.bufferIndex]); + this.ctx.bufferSubData(this.ctx.ARRAY_BUFFER, 0, new Float32Array(prim.bufferStreams[vert_element.bufferIndex]), vert_element.bufferUsage ); + } + } + } + + if(prim.indexBuffer.length > 0) + { + var indexBufLength = prim.indexBuffer.length; + prim.indexBuffer.debugName="index Buffer"; + + if(this.buffers[prim.buffersID].indexHandle == undefined) + { + if(prim.forceIndexCount) + { + this.buffers[prim.buffersID].indexHandle = this.createIndexBufferUINT16( 2 * prim.forceIndexCount, prim.indexUsage ); + this.ctx.bufferSubData(this.ctx.ELEMENT_ARRAY_BUFFER, 0, new Float32Array(prim.indexBuffer), prim.indexUsage ); + } + else + { + this.buffers[prim.buffersID].indexHandle = this.createIndexBufferUINT16(prim.indexBuffer,prim.indexUsage); + } + } + else + { + this.ctx.bindBuffer(this.ctx.ELEMENT_ARRAY_BUFFER, this.buffers[prim.buffersID].indexHandle); + this.ctx.bufferSubData(this.ctx.ELEMENT_ARRAY_BUFFER, 0, new Float32Array(prim.indexBuffer), prim.indexUsage ); + } + + prim.indexCount=indexBufLength; + prim.triCount=indexBufLength/3; + } + else + { + prim.triCount=prim.posCount/3; + } +} + +/* + * @param prim the primitive to delete from the GL context + */ +_renderer.prototype.deletePrimitive = function( prim ) +{ + var buffers = this.buffers[prim.buffersID]; + + if (buffers) + { + var self = this; + + buffers.forEach(function(thisBuffer) { + self.ctx.deleteBuffer(thisBuffer); + }); + + delete this.buffers[prim.buffersID]; + } +} + +/* + * @param prim the primitive for which to retrieve the GL VBO handle + * @param bufferIndex which buffer name to retrieve + */ +_renderer.prototype.getPrimitiveBuffer = function( prim, bufferIndex ) +{ + return this.buffers[prim.buffersID][bufferIndex]; +} + +_renderer.prototype.drawPrimitive = function( prim, program, attribs ) +{ + g_renderStats.numDrawCalls.value++; + g_renderStats.numTriangles.value+=Math.floor(prim.triCount); + g_renderStats.numVerts.value+=Math.floor(prim.coordCount/3); + + if(prim.indexCount) + { + this.drawIndexedPrimitive( prim, program, attribs ) + } + else + { + this.drawNonIndexedPrimitive( prim, program, attribs ) + } + + if(prim.useDoubleBuffer === true) + { + // after drawing flip the buffer + prim.flip(this); + } +} + +/* + * Draws a single primitive using indices + * @param: prim a single primitive + */ +_renderer.prototype.drawIndexedPrimitive = function(prim, program, attribs) { + var bufferIndex = 0; + var loc = 0; + var buffersId = prim.buffersID; + var name = ""; + var attrCount = attribs.length + var attrIdx = 0; + var dbOffset = prim.frontBufferIndex * prim.doubleBufferOffset; + + var ctx = g_Engine.getContext(); + + for (; attrIdx < attrCount; ++attrIdx) { + loc = attribs[attrIdx].loc; + name = attribs[attrIdx].name; + + if (!prim.vertexDefinition[name]) + continue; + + bufferIndex = prim.vertexDefinition[name].bufferIndex; + + this.ctx.enableVertexAttribArray(loc); + this.ctx.bindBuffer(this.ctx.ARRAY_BUFFER, this.buffers[buffersId][dbOffset + bufferIndex]); + this.ctx.vertexAttribPointer(loc, prim.vertexDefinition[name].type, this.FLOAT, false, 0, 0); + } + + this.ctx.bindBuffer(this.ctx.ELEMENT_ARRAY_BUFFER, this.buffers[buffersId].indexHandle); + + this.ctx.drawElements(prim.type, prim.indexCount, prim.indexElementSize, 0); + + for (attrIdx = 0; attrIdx < attrCount; ++attrIdx) { + this.ctx.disableVertexAttribArray(attribs[attrIdx].loc); + } +} + +/* + * Draws a single primitive using indices in wireframe mode + * @param: prim a single primitive + */ +_renderer.prototype.drawIndexedPrimitiveWireFrame = function( prim, program, attribs ) +{ + var bufferIndex = 0; + var loc = 0; + var buffersId = prim.buffersID; + var name =""; + var attrCount = attribs.length + var attrIdx = 0; + var dbOffset = prim.frontBufferIndex*prim.doubleBufferOffset; + + for(; attrIdx < attrCount; ++attrIdx) + { + loc = attribs[attrIdx].loc; + name = attribs[attrIdx].name; + + if(!prim.vertexDefinition[name]) + continue; + + bufferIndex = prim.vertexDefinition[name].bufferIndex; + + this.ctx.enableVertexAttribArray(loc); + this.ctx.bindBuffer(this.ctx.ARRAY_BUFFER, this.buffers[buffersId][dbOffset + bufferIndex]); + this.ctx.vertexAttribPointer(loc, prim.vertexDefinition[name].type, this.FLOAT ,false, 0, 0); + } + + this.ctx.bindBuffer(this.ctx.ELEMENT_ARRAY_BUFFER, this.buffers[buffersId].indexHandle); + + this.ctx.drawElements( this.LINE_LOOP, prim.indexCount, prim.indexElementSize, 0); + + for(attrIdx = 0; attrIdx < attrCount; ++attrIdx) + { + this.ctx.disableVertexAttribArray(attribs[attrIdx].loc); + } + +} + +/* + * Draws a single primitive (non-indexed primitive) + * @param: prim a single primitive + */ +_renderer.prototype.drawNonIndexedPrimitive = function( prim, program, attribs ) +{ + var bufferIndex = 0; + var loc = 0; + var buffersId = prim.buffersID; + var name =""; + var attrCount = attribs.length + var attrIdx = 0; + var dbOffset = prim.frontBufferIndex*prim.doubleBufferOffset; + + for(; attrIdx < attrCount; ++attrIdx) + { + loc = attribs[attrIdx].loc; + name = attribs[attrIdx].name; + + bufferIndex = prim.vertexDefinition[name].bufferIndex; + + if(!prim.vertexDefinition[name]) + continue; + + this.ctx.enableVertexAttribArray(loc); + this.ctx.bindBuffer(this.ctx.ARRAY_BUFFER, this.buffers[buffersId][dbOffset + bufferIndex]); + this.ctx.vertexAttribPointer(loc, prim.vertexDefinition[name].type, this.FLOAT ,false, 0, 0); + } + + this.ctx.drawArrays( prim.type, 0, prim.triCount); + + for(attrIdx = 0; attrIdx < attrCount; ++attrIdx) + { + this.ctx.disableVertexAttribArray(attribs[attrIdx].loc); + } +} + +/* + * Not yet supported but stubbed out here + */ +_renderer.prototype.drawIndexedPrimitiveSet = function( prim ) +{ + window.alert("drawIndexedPrimitiveSet is not implemented"); + for(var i =0; i < prim.setCount; ++i) + { + this.ctx.drawElements(prim.type[i], mesh.numIndices[i], prim.indexElementSize[i], prim.indexOffsets[i]); + } +} + +renderDebug = function(maxLines) { + this.renderer = g_Engine.getContext().renderer; + this.ctx = g_Engine.getContext().renderer.ctx; + this.hidden = false; + this.maxLines = maxLines; + this.lineBuffer = []; + this.posBufferData = new Float32Array(3 * this.maxLines); + this.colorBufferData = new Float32Array(4 * this.maxLines); + this.posBufferObject = renderer.createBufferFLOAT32(this.posBufferData, this.renderer.BUFFER_DYNAMIC); + this.colorBufferObject = renderer.createBufferFLOAT32(this.colorBufferData, this.renderer.BUFFER_DYNAMIC); + this.shader = new jshader(); + this.shader.def = { + 'shaders': { + 'defaultVShader': "\ + uniform mat4 u_mvMatrix;\ + uniform mat4 u_projMatrix;\ + attribute vec3 a_pos;\ + attribute vec4 a_color;\ + varying vec4 v_color;\ + void main() {\ + gl_Position = u_projMatrix * u_mvMatrix * vec4(a_pos,1.0);\ + v_color = a_color;\ + }", + 'defaultFShader': "\ + precision mediump float;\ + varying vec4 v_color;\ + void main() {\ + gl_FragColor = v_color;\ + gl_FragColor.a = 1.0;\ + }" + }, + 'techniques': { + 'defaultTechnique': [{ + 'vshader' : 'defaultVShader', + 'fshader' : 'defaultFShader', + 'attributes' : { + 'a_pos' : { 'type' : 'vec3' }, + 'a_color' : { 'type' : 'vec4' } + }, + + 'params' : { + 'u_projMat' : { 'type' : 'mat4' }, + 'u_viewMat' : { 'type' : 'mat4' } + } + }] + } + } + this.shader.init(); +} + +renderDebug.prototype.hide = function() { + this.hidden = true; +} + +renderDebug.prototype.show = function() { + this.hidden = false; +} + +renderDebug.prototype.line = function(p0, p1, c0, c1 ) { + if( this.hidden ) { + return; + } + + if( c0 == undefined ) { + c0 = [1.0,1.0,1.0,1.0]; + } + if( c1 == undefined ) { + c1 = c0; + } + this.lineBuffer.push( [ p0, p1, c0, c1 ] ); +} + +renderDebug.prototype.box = function(min, max, c) { + this.line([min[0],min[1],min[2]], [max[0],min[1],min[2]], c, c); + this.line([max[0],min[1],min[2]], [max[0],max[1],min[2]], c, c); + this.line([max[0],max[1],min[2]], [min[0],max[1],min[2]], c, c); + this.line([min[0],max[1],min[2]], [min[0],min[1],min[2]], c, c); + this.line([min[0],min[1],max[2]], [max[0],min[1],max[2]], c, c); + this.line([max[0],min[1],max[2]], [max[0],max[1],max[2]], c, c); + this.line([max[0],max[1],max[2]], [min[0],max[1],max[2]], c, c); + this.line([min[0],max[1],max[2]], [min[0],min[1],max[2]], c, c); + + this.line([max[0],min[1],min[2]], [max[0],min[1],max[2]], c, c); + this.line([max[0],max[1],min[2]], [max[0],max[1],max[2]], c, c); + this.line([min[0],max[1],min[2]], [min[0],max[1],max[2]], c, c); + this.line([min[0],min[1],min[2]], [min[0],min[1],max[2]], c, c); +} + +renderDebug.prototype.frustum = function(p, c) { + this.line(p[0], p[1], c, c); + this.line(p[1], p[2], c, c); + this.line(p[2], p[3], c, c); + this.line(p[3], p[4], c, c); + this.line(p[4], p[5], c, c); + this.line(p[5], p[6], c, c); + this.line(p[6], p[7], c, c); +} + +renderDebug.prototype.sphere = function(p, r, c) { + var rho = 0.0; + var rho_step = Math.PI / 8.0; + + var phi = 0.0; + var phi_step = 2.0 * Math.PI / 8.0; + while( rho < Math.PI ) { + var srho = Math.sin( rho ); + var crho = Math.cos( rho ); + while( phi < 2.0 * Math.PI ) { + var sphi = Math.sin(phi); + var cphi = Math.cos(phi); + + var x0 = p[0] + cphi * srho * r; + var y0 = p[1] + crho * r; + var z0 = p[2] + sphi * srho * r; + phi += phi_step; + + sphi = Math.sin(phi); + cphi = Math.cos(phi); + var x1 = p[0] + cphi * srho * r; + var y1 = p[1] + crho * r; + var z1 = p[2] + sphi * srho * r; + phi += phi_step; + + this.line([x0,y0,z0], + [x1,y1,z1], c); + } + rho += rho_step; + } +} + +renderDebug.prototype.flush = function() +{ + var drawCalls = 0; + var activeCam = this.renderer.cameraManager().getActiveCamera(); + + mat4.inplace_copy(this.ctx.projectionMatrix, activeCam.proj); + mat4.inplace_copy(this.ctx.mvMatrix, activeCam.view); + while( this.lineBuffer.length > 0 ) { + var count = Math.min( this.lineBuffer.length, this.maxLines ); + var index = 0; + while( count > 0 ) { + var line = this.lineBuffer.shift(); + var i6 = index * 6; + var i8 = index * 8; + this.posBufferData[i6+0] = line[0][0]; + this.posBufferData[i6+1] = line[0][1]; + this.posBufferData[i6+2] = line[0][2]; + this.posBufferData[i6+3] = line[1][0]; + this.posBufferData[i6+4] = line[1][1]; + this.posBufferData[i6+5] = line[1][2]; + this.colorBufferData[i8+0] = line[2][0]; + this.colorBufferData[i8+1] = line[2][1]; + this.colorBufferData[i8+2] = line[2][2]; + this.colorBufferData[i8+3] = line[2][3]; + this.colorBufferData[i8+4] = line[3][0]; + this.colorBufferData[i8+5] = line[3][1]; + this.colorBufferData[i8+6] = line[3][2]; + this.colorBufferData[i8+7] = line[3][3]; + count--; + index++; + if( count <= 0 ) { + this.ctx.bindBuffer(this.ctx.ARRAY_BUFFER, this.posBufferObject); + this.ctx.bufferSubData(this.ctx.ARRAY_BUFFER, 0, null); + this.ctx.bufferSubData(this.ctx.ARRAY_BUFFER, 0, this.posBufferData); + + this.ctx.bindBuffer(this.ctx.ARRAY_BUFFER, this.colorBufferObject); + this.ctx.bufferSubData(this.ctx.ARRAY_BUFFER, 0, null); + this.ctx.bufferSubData(this.ctx.ARRAY_BUFFER, 0, this.colorBufferData); + + this.ctx.disable(this.ctx.DEPTH_TEST); + this.shader.begin(); + this.shader.beginPass(0); + this.ctx.enableVertexAttribArray(0); + this.ctx.enableVertexAttribArray(1); + + this.ctx.bindBuffer(this.ctx.ARRAY_BUFFER, this.posBufferObject); + this.ctx.vertexAttribPointer(0, 3, this.ctx.FLOAT, false, 0, 0); + + this.ctx.bindBuffer(this.ctx.ARRAY_BUFFER, this.colorBufferObject); + this.ctx.vertexAttribPointer(1, 4, this.ctx.FLOAT, false, 0, 0); + + this.ctx.drawArrays(this.ctx.LINES, 0, index * 2); + this.shader.endPass(); + this.shader.end(); + this.ctx.enable(this.ctx.DEPTH_TEST); + drawCalls++; + this.ctx.finish(); + this.ctx.flush(); + break; + } + } + } +} -- cgit v1.2.3