UNPKG

odin

Version:

Node.js Canvas/WebGL Javascript Game Framework

1,237 lines (927 loc) 42.5 kB
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>JSDoc: Source: core/rendering/webgl_renderer_2d.js</title> <script src="scripts/prettify/prettify.js"> </script> <script src="scripts/prettify/lang-css.js"> </script> <!--[if lt IE 9]> <script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script> <![endif]--> <link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css"> <link type="text/css" rel="stylesheet" href="styles/jsdoc-default.css"> </head> <body> <div id="main"> <h1 class="page-title">Source: core/rendering/webgl_renderer_2d.js</h1> <section> <article> <pre class="prettyprint source"><code>if (typeof(define) !== "function") { var define = require("amdefine")(module); } define([ "odin/base/event_emitter", "odin/base/device", "odin/base/dom", "odin/math/mathf", "odin/math/vec2", "odin/math/mat32", "odin/math/mat4", "odin/math/color", "odin/core/game/log", "odin/core/enums" ], function(EventEmitter, Device, Dom, Mathf, Vec2, Mat32, Mat4, Color, Log, Enums) { "use strict"; var FontStyle = Enums.FontStyle, TextClipping = Enums.TextClipping, TextAnchor = Enums.TextAnchor, Blending = Enums.Blending, getWebGLContext = Dom.getWebGLContext, createProgram = Dom.createProgram, parseUniformsAttributes = Dom.parseUniformsAttributes, addEvent = Dom.addEvent, removeEvent = Dom.removeEvent, max = Math.max, clamp = Mathf.clamp, isPowerOfTwo = Mathf.isPowerOfTwo, WHITE_TEXTURE = new Uint8Array([255, 255, 255, 255]), ENUM_WHITE_TEXTURE = -1, SPRITE_VERTICES = [ new Vec2(-0.5, 0.5), new Vec2(-0.5, -0.5), new Vec2(0.5, 0.5), new Vec2(0.5, -0.5) ], SPRITE_UVS = [ new Vec2(0, 0), new Vec2(0, 1), new Vec2(1, 0), new Vec2(1, 1) ], ENUM_SPRITE_BUFFER = -1, SCREEN_VERTICES = [ new Vec2(0, 0), new Vec2(0, 1), new Vec2(1, 0), new Vec2(1, 1) ], SCREEN_UVS = [ new Vec2(0, 0), new Vec2(0, 1), new Vec2(1, 0), new Vec2(1, 1) ], ENUM_SCREEN_BUFFER = -2, ENUM_SPRITE_SHADER = -1, ENUM_BASIC_SHADER = -2, ENUM_PARTICLE_SHADER = -3, ENUM_CANVAS_SHADER = -4, EMPTY_ARRAY = [], MAT = new Mat32, MAT4 = new Mat4; /** * @class WebGLRenderer2D * @extends EventEmitter * @brief 2d webgl renderer * @param Object options */ function WebGLRenderer2D(opts) { opts || (opts = {}); EventEmitter.call(this); this.canvas = undefined; this.context = undefined; this._context = false; this.autoClear = opts.autoClear != undefined ? opts.autoClear : true; this.attributes = merge(opts.attributes || {}, { alpha: true, antialias: true, depth: true, premulipliedAlpha: true, preserveDrawingBuffer: false, stencil: true }); this._webgl = { gpu: { precision: "highp", maxAnisotropy: 16, maxTextures: 16, maxTextureSize: 16384, maxCubeTextureSize: 16384, maxRenderBufferSize: 16384 }, ext: { textureFilterAnisotropic: undefined, textureFloat: undefined, standardDerivatives: undefined, compressedTextureS3TC: undefined }, textures: {}, shaders: {}, buffers: {}, texts: {}, textsTextureCache: {}, lastTexture: undefined, lastShader: undefined, lastBuffer: undefined }; this._clearBytes = 17664; this._lastCamera = undefined; this._lastResizeFn = undefined; this._lastBackground = new Color; this._lastBlending = undefined; } EventEmitter.extend(WebGLRenderer2D); WebGLRenderer2D.prototype.init = function(canvas) { if (this.canvas) this.clear(); var element = canvas.element; this.canvas = canvas; this.context = getWebGLContext(element, this.attributes); if (!this.context) return this; this._context = true; addEvent(element, "webglcontextlost", this._handleWebGLContextLost, this); addEvent(element, "webglcontextrestored", this._handleWebGLContextRestored, this); this.setDefaults(); return this; }; WebGLRenderer2D.prototype.clear = function() { if (!this.canvas) return this; var canvas = this.canvas, element = canvas.element, webgl = this._webgl, ext = webgl.ext; this.canvas = undefined; this.context = undefined; this._context = false; removeEvent(element, "webglcontextlost", this._handleWebGLContextLost, this); removeEvent(element, "webglcontextrestored", this._handleWebGLContextRestored, this); this._clearBytes = 17664; this._lastCamera = undefined; this._lastBackground.setRGB(0, 0, 0); this._lastBlending = undefined; ext.compressedTextureS3TC = ext.standardDerivatives = ext.textureFilterAnisotropic = ext.textureFloat = undefined; webgl.lastBuffer = webgl.lastShader = webgl.lastTexture = undefined; clear(webgl.textures); clear(webgl.buffers); clear(webgl.shaders); clear(webgl.texts); clear(webgl.textsTextureCache); return this; }; /** * @method setDefaults * @memberof WebGLRenderer2D * @brief sets renderers defaults settings */ WebGLRenderer2D.prototype.setDefaults = function() { var gl = this.context, webgl = this._webgl, ext = webgl.ext, gpu = webgl.gpu, textureFilterAnisotropic = gl.getExtension("EXT_texture_filter_anisotropic") || gl.getExtension("MOZ_EXT_texture_filter_anisotropic") || gl.getExtension("WEBKIT_EXT_texture_filter_anisotropic"), compressedTextureS3TC = gl.getExtension("WEBGL_compressed_texture_s3tc") || gl.getExtension("MOZ_WEBGL_compressed_texture_s3tc") || gl.getExtension("WEBKIT_WEBGL_compressed_texture_s3tc"), standardDerivatives = gl.getExtension("OES_standard_derivatives"), textureFloat = gl.getExtension("OES_texture_float"); ext.textureFilterAnisotropic = textureFilterAnisotropic; ext.standardDerivatives = standardDerivatives; ext.textureFloat = textureFloat; ext.compressedTextureS3TC = compressedTextureS3TC; var VERTEX_SHADER = gl.VERTEX_SHADER, FRAGMENT_SHADER = gl.FRAGMENT_SHADER, HIGH_FLOAT = gl.HIGH_FLOAT, MEDIUM_FLOAT = gl.MEDIUM_FLOAT, shaderPrecision = typeof(gl.getShaderPrecisionFormat) !== "undefined", maxAnisotropy = ext.textureFilterAnisotropic ? gl.getParameter(ext.textureFilterAnisotropic.MAX_TEXTURE_MAX_ANISOTROPY_EXT) : 1, maxTextures = gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS), maxTextureSize = gl.getParameter(gl.MAX_TEXTURE_SIZE), maxCubeTextureSize = gl.getParameter(gl.MAX_CUBE_MAP_TEXTURE_SIZE), maxRenderBufferSize = gl.getParameter(gl.MAX_RENDERBUFFER_SIZE), vsHighpFloat = shaderPrecision ? gl.getShaderPrecisionFormat(VERTEX_SHADER, HIGH_FLOAT) : 0, vsMediumpFloat = shaderPrecision ? gl.getShaderPrecisionFormat(VERTEX_SHADER, MEDIUM_FLOAT) : 1, fsHighpFloat = shaderPrecision ? gl.getShaderPrecisionFormat(FRAGMENT_SHADER, HIGH_FLOAT) : 0, fsMediumpFloat = shaderPrecision ? gl.getShaderPrecisionFormat(FRAGMENT_SHADER, MEDIUM_FLOAT) : 1, highpAvailable = vsHighpFloat.precision > 0 && fsHighpFloat.precision > 0, mediumpAvailable = vsMediumpFloat.precision > 0 && fsMediumpFloat.precision > 0, precision = "highp"; if (!highpAvailable || Device.mobile) { if (mediumpAvailable) { precision = "mediump"; } else { precision = "lowp"; } } gpu.precision = precision; gpu.maxAnisotropy = maxAnisotropy; gpu.maxTextures = maxTextures; gpu.maxTextureSize = maxTextureSize; gpu.maxCubeTextureSize = maxCubeTextureSize; gpu.maxRenderBufferSize = maxRenderBufferSize; gl.clearColor(0, 0, 0, 1); gl.clearDepth(1); gl.clearStencil(0); //gl.enable(gl.DEPTH_TEST); //gl.depthFunc(gl.LEQUAL); gl.frontFace(gl.CCW); gl.cullFace(gl.BACK); gl.enable(gl.CULL_FACE); gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false); this.setBlending(Blending.Default); gl.clear(gl.COLOR_BUFFER_BIT | gl.STENCIL_BUFFER_BIT); var texture = gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D, texture); gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, 1, 1, 0, gl.RGB, gl.UNSIGNED_BYTE, WHITE_TEXTURE); gl.bindTexture(gl.TEXTURE_2D, null); webgl.textures[ENUM_WHITE_TEXTURE] = texture; buildBuffer(this, { _id: ENUM_SPRITE_BUFFER, vertices: SPRITE_VERTICES, uvs: SPRITE_UVS }); buildBuffer(this, { _id: ENUM_SCREEN_BUFFER, vertices: SCREEN_VERTICES, uvs: SCREEN_UVS }); buildShader(this, { _id: ENUM_SPRITE_SHADER, vertexShader: spriteVertexShader(precision), fragmentShader: spriteFragmentShader(precision) }); buildShader(this, { _id: ENUM_CANVAS_SHADER, vertexShader: guiVertexShader(precision), fragmentShader: spriteFragmentShader(precision) }); buildShader(this, { _id: ENUM_BASIC_SHADER, vertexShader: basicVertexShader(precision), fragmentShader: basicFragmentShader(precision) }); buildShader(this, { _id: ENUM_PARTICLE_SHADER, vertexShader: particleVertexShader(precision), fragmentShader: particleFragmentShader(precision) }); this._clearBytes = gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT; return this; }; /** * @method setBlending * @memberof WebGLRenderer2D * @param Number blending */ WebGLRenderer2D.prototype.setBlending = function(blending) { var gl = this.context; if (blending !== this._lastBlending) { switch (blending) { case Blending.None: gl.disable(gl.BLEND); break; case Blending.Additive: gl.enable(gl.BLEND); gl.blendEquation(gl.FUNC_ADD); gl.blendFunc(gl.SRC_ALPHA, gl.ONE); break; case Blending.Subtractive: gl.enable(gl.BLEND); gl.blendEquation(gl.FUNC_ADD); gl.blendFunc(gl.ZERO, gl.ONE_MINUS_SRC_COLOR); break; case Blending.Muliply: gl.enable(gl.BLEND); gl.blendEquation(gl.FUNC_ADD); gl.blendFunc(gl.ZERO, gl.SRC_COLOR); break; case Blending.Default: default: gl.enable(gl.BLEND); gl.blendEquationSeparate(gl.FUNC_ADD, gl.FUNC_ADD); gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA); break; } this._lastBlending = blending; } }; WebGLRenderer2D.prototype.preRender = function(camera) { if (!this._context) return; var gl = this.context, lastBackground = this._lastBackground, background = camera.background; if (lastBackground.r !== background.r || lastBackground.g !== background.g || lastBackground.b !== background.b) { lastBackground.copy(background); gl.clearColor(background.r, background.g, background.b, 1); if (!this.autoClear) gl.clear(this._clearBytes); } if (this._lastCamera !== camera) { var canvas = this.canvas, w = canvas.pixelWidth, h = canvas.pixelHeight; camera.set(w, h); gl.viewport(0, 0, w, h); if (this._lastResizeFn) canvas.off("resize", this._lastResizeFn); this._lastResizeFn = function() { var w = this.pixelWidth, h = this.pixelHeight; camera.set(w, h); gl.viewport(0, 0, w, h); }; canvas.on("resize", this._lastResizeFn); this._lastCamera = camera; } if (this.autoClear) gl.clear(this._clearBytes); }; WebGLRenderer2D.prototype.renderGUI = function(gui, camera) { if (!this._context) return; var gl = this.context, components = gui.components, GUIContent = components.GUIContent || EMPTY_ARRAY, content, transform, i; for (i = GUIContent.length; i--;) { content = GUIContent[i]; transform = content.guiTransform; if (!transform) continue; this.renderGUIContent(camera, transform, content); } }; WebGLRenderer2D.prototype.renderGUIContent = function(camera, transform, content) { var gl = this.context, webgl = this._webgl, position = transform.position, text = content.text, texture = content.texture, style = content.style, state = style[style._state], background = state.background, glShader = webgl.shaders[ENUM_BASIC_SHADER], glBuffer = webgl.buffers[ENUM_SCREEN_BUFFER], uniforms = glShader.uniforms, aspect = camera.aspect, width = position.width, height = position.height, glText, texture; MAT4.copy(SCREEN_MAT).translate(position); if (aspect >= 1) { width /= aspect; } else { height *= aspect; } if (webgl.lastShader !== glShader) { gl.useProgram(glShader.program); webgl.lastShader = glShader; } if (webgl.lastBuffer !== glBuffer) { bindBuffers(gl, glShader, glBuffer); webgl.lastBuffer = glBuffer; } gl.uniformMatrix4fv(uniforms.uMatrix.location, false, MAT4.elements); gl.uniform3f(uniforms.uColor.location, background.r, background.g, background.b); gl.uniform1f(uniforms.uAlpha.location, content.alpha); gl.uniform2f(uniforms.uSize.location, width, height); gl.drawArrays(gl.TRIANGLE_STRIP, 0, glBuffer.vertices); if (text) { glShader = webgl.shaders[ENUM_CANVAS_SHADER]; uniforms = glShader.uniforms; gl.useProgram(glShader.program); bindBuffers(gl, glShader, glBuffer); glText = buildText(this, camera, position, content, style, state, text); texture = glText.texture; if (texture) { if (webgl.lastTexture !== texture) { gl.activeTexture(gl.TEXTURE0); gl.bindTexture(gl.TEXTURE_2D, texture); gl.uniform1i(uniforms.uTexture.location, 0); webgl.lastTexture = texture; } gl.uniformMatrix4fv(uniforms.uMatrix.location, false, MAT4.elements); gl.uniform1f(uniforms.uAlpha.location, content.alpha); gl.uniform2f(uniforms.uSize.location, glText.width, glText.height); gl.drawArrays(gl.TRIANGLE_STRIP, 0, glBuffer.vertices); } } }; var SPLITTER = /[\r\n]+/, TOP = "top", LEFT = "left", CENTER = "center", RIGHT = "right"; function buildText(renderer, camera, position, content, style, state, text) { var gl = renderer.context, webgl = renderer._webgl, texts = webgl.texts, textsTextureCache = webgl.textsTextureCache, glText = texts[content._id]; if (glText && !content.needsUpdate) return glText; glText = glText || (texts[content._id] = {}); var canvas = glText.canvas || document.createElement("canvas"), ctx = glText.ctx || canvas.getContext("2d"), texture = textsTextureCache[content._id] || (textsTextureCache[content._id] = { _id: content._id, needsUpdate: true, raw: canvas }), font = style.fontStyle + " " + style.fontSize + "pt " + style.font, wordWrap = style.wordWrap, lineHeight = style.lineHeight, width = 0, height = 0, lines, lineWidth, i, il; lines = text.split(SPLITTER); for (i = 0, il = lines.length; i &lt; il; i++) { lineWidth = ctx.measureText(lines[i]).width; width = max(width, lineWidth); } height = lineHeight ? lineHeight * il : (lineHeight = determineFontHeight(font)) * il; canvas.width = width; canvas.height = height; ctx.fillStyle = state.text.toRGB(); ctx.font = font; ctx.textBaseline = TOP; switch (style.alignment) { case TextAnchor.Left: ctx.textAlign = LEFT; break; case TextAnchor.Center: ctx.textAlign = CENTER; break; case TextAnchor.Right: ctx.textAlign = RIGHT; break; } for (i = 0; i &lt; il; i++) ctx.fillText(lines[i], 0, lineHeight * i); glText.canvas = canvas; glText.ctx = ctx; glText.width = width * camera.invWidth; glText.height = height * camera.invHeight; texture.needsUpdate = true; glText.texture = buildTexture(renderer, texture); content.needsUpdate = false; return glText; } var HEIGHT_CACHE = {}; function determineFontHeight(font) { var result = HEIGHT_CACHE[font]; if (!result) { var body = document.getElementsByTagName("body")[0], dummy = document.createElement("div"), dummyText = document.createTextNode("M"); dummy.appendChild(dummyText); dummy.setAttribute("style", "font: " + font + ";position:absolute;top:0;left:0"); body.appendChild(dummy); result = dummy.offsetHeight; HEIGHT_CACHE[font] = result; body.removeChild(dummy); } return result; } /** * @method render * @memberof WebGLRenderer2D * @brief renderers scene from camera's perspective * @param Scene scene * @param Camera camera */ WebGLRenderer2D.prototype.render = function(scene, camera) { if (!this._context) return; var gl = this.context, components = scene.components, sprites = components.Sprite || EMPTY_ARRAY, particleSystems = components.ParticleSystem || EMPTY_ARRAY, guiTextures = components.GUITexture || EMPTY_ARRAY, sprite2d, particleSystem, guiTexture, transform2d, i; for (i = sprites.length; i--;) { sprite2d = sprites[i]; transform2d = sprite2d.transform2d; if (!transform2d || !sprite2d.visible) continue; transform2d.updateModelViewMat32(camera.view); this.renderSprite(camera, transform2d, sprite2d); } for (i = particleSystems.length; i--;) { particleSystem = particleSystems[i]; transform2d = particleSystem.transform2d; if (!transform2d) continue; transform2d.updateModelViewMat32(camera.view); this.renderParticleSystem(camera, transform2d, particleSystem); } for (i = guiTextures.length; i--;) { guiTexture = guiTextures[i]; transform2d = guiTexture.transform2d; if (!transform2d) continue; this.renderGUITexture(camera, transform2d, guiTexture); } }; var SCREEN_MAT = new Mat4().orthographic(0, 1, 0, 1, -1, 1); WebGLRenderer2D.prototype.renderGUITexture = function(camera, transform2d, guiTexture) { var gl = this.context, webgl = this._webgl, texture = guiTexture.texture, position = guiTexture.position, glShader = webgl.shaders[ENUM_SPRITE_SHADER], glBuffer = webgl.buffers[ENUM_SCREEN_BUFFER], glTexture = buildTexture(this, texture), uniforms = glShader.uniforms, aspect = camera.aspect, width = position.width, height = position.height, w, h; if (texture && texture.raw) { w = texture.invWidth; h = texture.invHeight; } else { return; } MAT4.copy(SCREEN_MAT).translate(position); if (aspect >= 1) { height *= aspect; } else { width /= aspect; } if (webgl.lastShader !== glShader) { gl.useProgram(glShader.program); webgl.lastShader = glShader; } if (webgl.lastBuffer !== glBuffer) { bindBuffers(gl, glShader, glBuffer); webgl.lastBuffer = glBuffer; } gl.uniformMatrix4fv(uniforms.uMatrix.location, false, MAT4.elements); gl.uniform4f(uniforms.uCrop.location, guiTexture.x * w, guiTexture.y * h, guiTexture.w * w, guiTexture.h * h); gl.uniform2f(uniforms.uSize.location, width, height); gl.uniform1f(uniforms.uAlpha.location, guiTexture.alpha); if (webgl.lastTexture !== glTexture) { gl.activeTexture(gl.TEXTURE0); gl.bindTexture(gl.TEXTURE_2D, glTexture); gl.uniform1i(uniforms.uTexture.location, 0); webgl.lastTexture = glTexture; } gl.drawArrays(gl.TRIANGLE_STRIP, 0, glBuffer.vertices); }; WebGLRenderer2D.prototype.renderSprite = function(camera, transform2d, sprite2d) { var gl = this.context, webgl = this._webgl, texture = sprite2d.texture, glShader = webgl.shaders[ENUM_SPRITE_SHADER], glBuffer = webgl.buffers[ENUM_SPRITE_BUFFER], glTexture = buildTexture(this, texture), uniforms = glShader.uniforms, w, h; if (texture && texture.raw) { w = texture.invWidth; h = texture.invHeight; } else { return; } MAT4.mmul(camera._projectionMat4, MAT4.fromMat32(transform2d.modelView)); if (webgl.lastShader !== glShader) { gl.useProgram(glShader.program); webgl.lastShader = glShader; } if (webgl.lastBuffer !== glBuffer) { bindBuffers(gl, glShader, glBuffer); webgl.lastBuffer = glBuffer; } gl.uniformMatrix4fv(uniforms.uMatrix.location, false, MAT4.elements); gl.uniform4f(uniforms.uCrop.location, sprite2d.x * w, sprite2d.y * h, sprite2d.w * w, sprite2d.h * h); gl.uniform2f(uniforms.uSize.location, sprite2d.width, sprite2d.height); gl.uniform1f(uniforms.uAlpha.location, sprite2d.alpha); if (webgl.lastTexture !== glTexture) { gl.activeTexture(gl.TEXTURE0); gl.bindTexture(gl.TEXTURE_2D, glTexture); gl.uniform1i(uniforms.uTexture.location, 0); webgl.lastTexture = glTexture; } gl.drawArrays(gl.TRIANGLE_STRIP, 0, glBuffer.vertices); }; WebGLRenderer2D.prototype.renderParticleSystem = function(camera, transform2d, particleSystem) { var gl = this.context, webgl = this._webgl, glShader = webgl.shaders[ENUM_PARTICLE_SHADER], glBuffer = webgl.buffers[ENUM_SPRITE_BUFFER], vertices = glBuffer.vertices, TRIANGLE_STRIP = gl.TRIANGLE_STRIP, uniforms = glShader.uniforms, uMatrix = uniforms.uMatrix.location, uPos = uniforms.uPos.location, uAngle = uniforms.uAngle.location, uSize = uniforms.uSize.location, uColor = uniforms.uColor.location, uAlpha = uniforms.uAlpha.location, elements = MAT4.elements, blending = this._lastBlending, emitters = particleSystem.emitters, emitter, particles, view, particle, pos, color, glTexture, i = emitters.length, j; if (!i) return; while (i--) { emitter = emitters[i]; particles = emitter.particles; view = emitter.worldSpace ? camera.view : transform2d.modelView; if (!(j = particles.length)) continue; glTexture = buildTexture(this, emitter.texture); if (webgl.lastShader !== glShader) { gl.useProgram(glShader.program); webgl.lastShader = glShader; } if (webgl.lastBuffer !== glBuffer) { bindBuffers(gl, glShader, glBuffer); webgl.lastBuffer = glBuffer; } this.setBlending(emitter.blending); MAT4.mmul(camera._projectionMat4, MAT4.fromMat32(view)); gl.uniformMatrix4fv(uMatrix, false, elements); if (webgl.lastTexture !== glTexture) { gl.activeTexture(gl.TEXTURE0); gl.bindTexture(gl.TEXTURE_2D, glTexture); gl.uniform1i(uniforms.uTexture.location, 0); webgl.lastTexture = glTexture; } for (; j--;) { particle = particles[j]; pos = particle.position; color = particle.color; gl.uniform2f(uPos, pos.x, pos.y); gl.uniform1f(uAngle, particle.angle); gl.uniform1f(uSize, particle.size); gl.uniform3f(uColor, color.r, color.g, color.b); gl.uniform1f(uAlpha, particle.alpha); gl.drawArrays(TRIANGLE_STRIP, 0, vertices); } } this.setBlending(blending); }; WebGLRenderer2D.prototype._handleWebGLContextLost = function(e) { e.preventDefault(); Log.warn("WebGLRenderer2D: webgl context was lost"); this._context = false; this.emit("webglcontextlost", e); }; WebGLRenderer2D.prototype._handleWebGLContextRestored = function(e) { Log.log("WebGLRenderer2D: webgl context was restored"); this.setDefaults(); this._context = true; this.emit("webglcontextrestored", e); }; function bindBuffers(gl, glShader, glBuffer) { var attributes = glShader.attributes, FLOAT = gl.FLOAT, ARRAY_BUFFER = gl.ARRAY_BUFFER; if (glBuffer.vertex && attributes.aVertexPosition > -1) { gl.bindBuffer(ARRAY_BUFFER, glBuffer.vertex); gl.enableVertexAttribArray(attributes.aVertexPosition); gl.vertexAttribPointer(attributes.aVertexPosition, 2, FLOAT, false, 0, 0); } if (glBuffer.color && attributes.aVertexColor > -1) { gl.bindBuffer(ARRAY_BUFFER, glBuffer.color); gl.enableVertexAttribArray(attributes.aVertexColor); gl.vertexAttribPointer(attributes.aVertexColor, 2, FLOAT, false, 0, 0); } if (glBuffer.uv && attributes.aVertexUv > -1) { gl.bindBuffer(ARRAY_BUFFER, glBuffer.uv); gl.enableVertexAttribArray(attributes.aVertexUv); gl.vertexAttribPointer(attributes.aVertexUv, 2, FLOAT, false, 0, 0); } if (glBuffer.index) gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, glBuffer.index); } var COMPILE_ARRAY = []; function buildBuffer(renderer, buffer) { if (!buffer) return undefined; var gl = renderer.context, webgl = renderer._webgl, buffers = webgl.buffers, glBuffer = buffers[buffer._id]; if (glBuffer && !buffer.needsUpdate) return glBuffer; glBuffer = glBuffer || (buffers[buffer._id] = {}); var compileArray = COMPILE_ARRAY, DRAW = buffer.dynamic ? gl.DYNAMIC_DRAW : gl.STATIC_DRAW, ARRAY_BUFFER = gl.ARRAY_BUFFER, ELEMENT_ARRAY_BUFFER = gl.ELEMENT_ARRAY_BUFFER, items, item, i, il; items = buffer.vertices; if (items && items.length) { compileArray.length = 0; for (i = 0, il = items.length; i &lt; il; i++) { item = items[i]; compileArray.push(item.x, item.y); } if (compileArray.length) { glBuffer.vertex = glBuffer.vertex || gl.createBuffer(); gl.bindBuffer(ARRAY_BUFFER, glBuffer.vertex); gl.bufferData(ARRAY_BUFFER, new Float32Array(compileArray), DRAW); } glBuffer.vertices = items.length; } items = buffer.uvs; if (items && items.length) { compileArray.length = 0; for (i = 0, il = items.length; i &lt; il; i++) { item = items[i]; compileArray.push(item.x, item.y); } if (compileArray.length) { glBuffer.uv = glBuffer.uv || gl.createBuffer(); gl.bindBuffer(ARRAY_BUFFER, glBuffer.uv); gl.bufferData(ARRAY_BUFFER, new Float32Array(compileArray), DRAW); } } items = buffer.indices || buffer.faces; if (items && items.length) { glBuffer.index = glBuffer.index || gl.createBuffer(); gl.bindBuffer(ELEMENT_ARRAY_BUFFER, glBuffer.index); gl.bufferData(ELEMENT_ARRAY_BUFFER, new Int16Array(items), DRAW); glBuffer.indices = items.length; } return glBuffer; } function buildShader(renderer, shader) { var gl = renderer.context, webgl = renderer._webgl, shaders = webgl.shaders, glShader = shaders[shader._id], vertex, fragment; if (glShader && !shader.needsUpdate) return glShader; glShader = glShader || (shaders[shader._id] = {}); vertex = shader.vertex || shader.vertexShader; fragment = shader.fragment || shader.fragmentShader; var program = glShader.program = createProgram(gl, vertex, fragment); glShader.vertex = vertex; glShader.fragment = fragment; parseUniformsAttributes(gl, program, vertex, fragment, glShader.attributes || (glShader.attributes = {}), glShader.uniforms || (glShader.uniforms = {}) ); return glShader; } function buildTexture(renderer, texture) { if (!texture || !texture.raw) return renderer._webgl.textures[ENUM_WHITE_TEXTURE]; var gl = renderer.context, webgl = renderer._webgl, textures = webgl.textures, glTexture = textures[texture._id], raw = texture.raw; if (glTexture && !texture.needsUpdate) return glTexture; glTexture = glTexture || (textures[texture._id] = gl.createTexture()); var ext = webgl.ext, gpu = webgl.gpu, TFA = ext.textureFilterAnisotropic, isPOT = isPowerOfTwo(raw.width) && isPowerOfTwo(raw.height), anisotropy = texture.anisotropy != undefined ? clamp(texture.anisotropy, 1, gpu.maxAnisotropy) : 1, TEXTURE_2D = gl.TEXTURE_2D, WRAP = isPOT ? gl.REPEAT : gl.CLAMP_TO_EDGE, MAG_FILTER = gl[texture.magFilter] || gl.LINEAR, MIN_FILTER = gl[texture.minFilter] || gl.LINEAR, FORMAT = gl[texture.format]; FORMAT = FORMAT ? FORMAT : gl.RGBA; if (isPOT) { MIN_FILTER = MIN_FILTER === gl.NEAREST || MIN_FILTER === gl.LINEAR ? gl.LINEAR_MIPMAP_NEAREST : MIN_FILTER; } else { MIN_FILTER = MIN_FILTER === gl.NEAREST ? gl.NEAREST : gl.LINEAR; } gl.bindTexture(TEXTURE_2D, glTexture); gl.texImage2D(TEXTURE_2D, 0, FORMAT, FORMAT, gl.UNSIGNED_BYTE, raw); gl.texParameteri(TEXTURE_2D, gl.TEXTURE_MAG_FILTER, MAG_FILTER); gl.texParameteri(TEXTURE_2D, gl.TEXTURE_MIN_FILTER, MIN_FILTER); gl.texParameteri(TEXTURE_2D, gl.TEXTURE_WRAP_S, WRAP); gl.texParameteri(TEXTURE_2D, gl.TEXTURE_WRAP_T, WRAP); if (TFA) gl.texParameterf(TEXTURE_2D, TFA.TEXTURE_MAX_ANISOTROPY_EXT, anisotropy); if (isPOT) gl.generateMipmap(TEXTURE_2D); webgl.lastTexture = glTexture; texture.needsUpdate = false; return glTexture; } function particleVertexShader(precision) { return [ "precision " + precision + " float;", "uniform mat4 uMatrix;", "uniform vec2 uPos;", "uniform float uAngle;", "uniform float uSize;", "attribute vec2 aVertexPosition;", "attribute vec2 aVertexUv;", "varying vec2 vVertexUv;", "void main() {", " float c, s, vx, vy, x, y;", " c = cos(uAngle);", " s = sin(uAngle);", " vx = aVertexPosition.x;", " vy = aVertexPosition.y;", " x = vx * c - vy * s;", " y = vx * s + vy * c;", " vVertexUv = aVertexUv;", " gl_Position = uMatrix * vec4(uPos.x + x * uSize, uPos.y + y * uSize, 0.0, 1.0);", "}" ].join("\n"); } function particleFragmentShader(precision) { return [ "precision " + precision + " float;", "uniform float uAlpha;", "uniform vec3 uColor;", "uniform sampler2D uTexture;", "varying vec2 vVertexUv;", "void main() {", " vec4 finalColor = texture2D(uTexture, vVertexUv);", " finalColor.xyz *= uColor;", " finalColor.w *= uAlpha;", " gl_FragColor = finalColor;", "}" ].join("\n"); } function basicVertexShader(precision) { return [ "precision " + precision + " float;", "uniform mat4 uMatrix;", "uniform vec2 uSize;", "attribute vec2 aVertexPosition;", "void main() {", " gl_Position = uMatrix * vec4(aVertexPosition * uSize, 0.0, 1.0);", "}" ].join("\n"); } function basicFragmentShader(precision) { return [ "precision " + precision + " float;", "uniform float uAlpha;", "uniform vec3 uColor;", "void main() {", " gl_FragColor = vec4(uColor, uAlpha);", "}" ].join("\n"); } function guiVertexShader(precision) { return [ "precision " + precision + " float;", "uniform mat4 uMatrix;", "uniform vec2 uSize;", "attribute vec2 aVertexPosition;", "attribute vec2 aVertexUv;", "varying vec2 vVertexUv;", "void main() {", " vVertexUv = vec2(aVertexUv.x, aVertexUv.y);", " gl_Position = uMatrix * vec4(aVertexPosition * uSize, 0.0, 1.0);", "}" ].join("\n"); } function spriteVertexShader(precision) { return [ "precision " + precision + " float;", "uniform mat4 uMatrix;", "uniform vec4 uCrop;", "uniform vec2 uSize;", "attribute vec2 aVertexPosition;", "attribute vec2 aVertexUv;", "varying vec2 vVertexUv;", "void main() {", " vVertexUv = vec2(aVertexUv.x * uCrop.z, aVertexUv.y * uCrop.w) + uCrop.xy;", " gl_Position = uMatrix * vec4(aVertexPosition * uSize, 0.0, 1.0);", "}" ].join("\n"); } function spriteFragmentShader(precision) { return [ "precision " + precision + " float;", "uniform float uAlpha;", "uniform sampler2D uTexture;", "varying vec2 vVertexUv;", "void main() {", " vec4 finalColor = texture2D(uTexture, vVertexUv);", " finalColor.w *= uAlpha;", " gl_FragColor = finalColor;", "}" ].join("\n"); } function merge(obj, add) { var key; for (key in add) if (obj[key] == undefined) obj[key] = add[key]; return obj; } function clear(obj) { var key; for (key in obj) delete obj[key]; return obj; } return WebGLRenderer2D; } ); </code></pre> </article> </section> </div> <nav> <h2><a href="index.html">Index</a></h2><h3>Classes</h3><ul><li><a href="Canvas.html">Canvas</a></li><li><a href="GUIObject.html">GUIObject</a></li><li><a href="MeshFilter.html">MeshFilter</a></li><li><a href="Odin.html">Odin</a></li><li><a href="Odin.Class.html">Class</a></li><li><a href="Odin.EventEmitter.html">EventEmitter</a></li><li><a href="Odin.GameObject.html">GameObject</a></li><li><a href="Odin.Scene.html">Scene</a></li><li><a href="P2Contact.html">P2Contact</a></li><li><a href="P2Equation.html">P2Equation</a></li><li><a href="P2Friction.html">P2Friction</a></li><li><a href="P2Solver.html">P2Solver</a></li><li><a href="ParticleSystem.html">ParticleSystem</a></li><li><a href="Renderer.html">Renderer</a></li><li><a href="SpriteAnimation.html">SpriteAnimation</a></li><li><a href="WebGLRenderer.html">WebGLRenderer</a></li><li><a href="WebGLRenderer2D.html">WebGLRenderer2D</a></li></ul> </nav> <br clear="both"> <footer> Documentation generated by <a href="https://github.com/jsdoc3/jsdoc">JSDoc 3.2.2</a> on Mon Feb 24 2014 16:15:46 GMT-0600 (CST) </footer> <script> prettyPrint(); </script> <script src="scripts/linenumber.js"> </script> </body> </html>