examples/pacman-unicode/unicodetiles/ut.WebGLRenderer.js
File `ut.WebGLRenderer.js` has 267 lines of code (exceeds 250 allowed). Consider refactoring./*global ut */ /// Class: WebGLRenderer/// Renders the <Viewport> with WebGL./// Given decent GPU drivers and browser support, this is the fastest renderer.////// *Note:* This is an internal class used by <Viewport>Function `WebGLRenderer` has 113 lines of code (exceeds 25 allowed). Consider refactoring.
Function `WebGLRenderer` has a Cognitive Complexity of 20 (exceeds 5 allowed). Consider refactoring.ut.WebGLRenderer = function(view) { "use strict"; this.view = view; this.canvas = document.createElement("canvas"); // Try to fetch the context if (!this.canvas.getContext) throw("Canvas not supported"); this.gl = this.canvas.getContext("experimental-webgl"); if (!this.gl) throw("WebGL not supported"); var gl = this.gl; view.elem.appendChild(this.canvas); this.charMap = {}; this.charArray = []; this.defaultColors = { r: 1.0, g: 1.0, b: 1.0, br: 0.0, bg: 0.0, bb: 0.0 }; this.attribs = { position: { buffer: null, data: null, itemSize: 2, location: null, hint: gl.STATIC_DRAW }, texCoord: { buffer: null, data: null, itemSize: 2, location: null, hint: gl.STATIC_DRAW }, color: { buffer: null, data: null, itemSize: 3, location: null, hint: gl.DYNAMIC_DRAW }, bgColor: { buffer: null, data: null, itemSize: 3, location: null, hint: gl.DYNAMIC_DRAW }, charIndex: { buffer: null, data: null, itemSize: 1, location: null, hint: gl.DYNAMIC_DRAW } }; Function `insertQuad` has 6 arguments (exceeds 4 allowed). Consider refactoring. function insertQuad(arr, i, x, y, w, h) { var x1 = x, y1 = y, x2 = x + w, y2 = y + h; arr[ i] = x1; arr[++i] = y1; arr[++i] = x2; arr[++i] = y1; arr[++i] = x1; arr[++i] = y2; arr[++i] = x1; arr[++i] = y2; arr[++i] = x2; arr[++i] = y1; arr[++i] = x2; arr[++i] = y2; } this.initBuffers = function() { var a, attrib, attribs = this.attribs; var w = this.view.w, h = this.view.h; // Allocate data arrays for (a in this.attribs) { attrib = attribs[a]; attrib.data = new Float32Array(attrib.itemSize * 6 * w * h); } // Generate static data for (var j = 0; j < h; ++j) { for (var i = 0; i < w; ++i) { // Position & texCoords var k = attribs.position.itemSize * 6 * (j * w + i); insertQuad(attribs.position.data, k, i * this.tw, j * this.th, this.tw, this.th); insertQuad(attribs.texCoord.data, k, 0.0, 0.0, 1.0, 1.0); } } // Upload for (a in this.attribs) { attrib = attribs[a]; if (attrib.buffer) gl.deleteBuffer(attrib.buffer); attrib.buffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, attrib.buffer); gl.bufferData(gl.ARRAY_BUFFER, attrib.data, attrib.hint); gl.enableVertexAttribArray(attrib.location); gl.vertexAttribPointer(attrib.location, attrib.itemSize, gl.FLOAT, false, 0, 0); } }; // Create an offscreen canvas for rendering text to texture if (!this.offscreen) this.offscreen = document.createElement("canvas"); this.offscreen.style.position = "absolute"; this.offscreen.style.top = "0px"; this.offscreen.style.left = "0px"; this.ctx = this.offscreen.getContext("2d"); if (!this.ctx) throw "Failed to acquire offscreen canvas drawing context"; // WebGL drawing canvas this.updateStyle(); this.canvas.width = (view.squarify ? this.th : this.tw) * view.w; this.canvas.height = this.th * view.h; this.offscreen.width = 0; this.offscreen.height = 0; // Doing this again since setting canvas w/h resets the state this.updateStyle(); gl.viewport(0, 0, this.canvas.width, this.canvas.height); // Setup GLSL function compileShader(type, source) { var shader = gl.createShader(type); gl.shaderSource(shader, source); gl.compileShader(shader); var ok = gl.getShaderParameter(shader, gl.COMPILE_STATUS); if (!ok) { var msg = "Error compiling shader: " + gl.getShaderInfoLog(shader); gl.deleteShader(shader); throw msg; } return shader; } var vertexShader = compileShader(gl.VERTEX_SHADER, ut.WebGLRenderer.VERTEX_SHADER); var fragmentShader = compileShader(gl.FRAGMENT_SHADER, ut.WebGLRenderer.FRAGMENT_SHADER); var program = gl.createProgram(); gl.attachShader(program, vertexShader); gl.attachShader(program, fragmentShader); gl.linkProgram(program); gl.deleteShader(vertexShader); gl.deleteShader(fragmentShader); var ok = gl.getProgramParameter(program, gl.LINK_STATUS); if (!ok) { var msg = "Error linking program: " + gl.getProgramInfoLog(program); gl.deleteProgram(program); throw msg; } gl.useProgram(program); // Get attribute locations this.attribs.position.location = gl.getAttribLocation(program, "position"); this.attribs.texCoord.location = gl.getAttribLocation(program, "texCoord"); this.attribs.color.location = gl.getAttribLocation(program, "color"); this.attribs.bgColor.location = gl.getAttribLocation(program, "bgColor"); this.attribs.charIndex.location = gl.getAttribLocation(program, "charIndex"); // Setup buffers and uniforms this.initBuffers(); var resolutionLocation = gl.getUniformLocation(program, "uResolution"); gl.uniform2f(resolutionLocation, this.canvas.width, this.canvas.height); this.tileCountsLocation = gl.getUniformLocation(program, "uTileCounts"); gl.uniform2f(this.tileCountsLocation, this.view.w, this.view.h); this.paddingLocation = gl.getUniformLocation(program, "uPadding"); gl.uniform2f(this.paddingLocation, 0.0, 0.0); // Setup texture //view.elem.appendChild(this.offscreen); // Debug offscreen var texture = gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D, texture); this.cacheChars(" !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); gl.activeTexture(gl.TEXTURE0); var _this = this; setTimeout(function() { _this.updateStyle(); _this.buildTexture(); _this.render(); }, 100);}; /////////////////// Build textureFunction `buildTexture` has 32 lines of code (exceeds 25 allowed). Consider refactoring.
Function `buildTexture` has a Cognitive Complexity of 9 (exceeds 5 allowed). Consider refactoring.ut.WebGLRenderer.prototype.buildTexture = function() { "use strict"; var gl = this.gl; var w = this.offscreen.width / (this.tw + this.pad), h = this.offscreen.height / (this.th + this.pad); // Check if need to resize the canvas var charCount = this.charArray.length; if (charCount > Math.floor(w) * Math.floor(h)) { w = Math.ceil(Math.sqrt(charCount)); h = w + 2; // Allocate some extra space too this.offscreen.width = w * (this.tw + this.pad); this.offscreen.height = h * (this.th + this.pad); this.updateStyle(); gl.uniform2f(this.tileCountsLocation, w, h); } gl.uniform2f(this.paddingLocation, this.pad / this.offscreen.width, this.pad / this.offscreen.height); var c = 0, ch; var halfGap = 0.5 * this.gap; // Squarification this.ctx.fillStyle = "#000000"; this.ctx.fillRect(0, 0, this.offscreen.width, this.offscreen.height); this.ctx.fillStyle = "#ffffff"; var tw = this.tw + this.pad; var th = this.th + this.pad; var y = 0.5 * th; // Half because textBaseline is middle for (var j = 0; j < h; ++j) { var x = this.pad * 0.5; for (var i = 0; i < w; ++i, ++c) { ch = this.charArray[c]; if (ch === undefined) break; this.ctx.fillText(ch, x + halfGap, y); x += tw; } if (!ch) break; y += th; } gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, this.offscreen);}; ///////////////// Cache charsFunction `cacheChars` has a Cognitive Complexity of 6 (exceeds 5 allowed). Consider refactoring.ut.WebGLRenderer.prototype.cacheChars = function(chars, build) { "use strict"; if (!this.gl) return; // Nothing to do if not using WebGL renderer var changed = false; for (var i = 0; i < chars.length; ++i) { if (!this.charMap[chars[i]]) { changed = true; this.charArray.push(chars[i]); this.charMap[chars[i]] = this.charArray.length-1; } } if (changed && build !== false) this.buildTexture();}; ////////////////// Update styleut.WebGLRenderer.prototype.updateStyle = function(s) { "use strict"; s = s || window.getComputedStyle(this.view.elem, null); this.ctx.font = s.fontSize + "/" + s.lineHeight + " " + s.fontFamily; this.ctx.textBaseline = "middle"; this.ctx.fillStyle = "#ffffff"; this.tw = this.ctx.measureText("M").width; this.th = parseInt(s.fontSize, 10); this.gap = this.view.squarify ? (this.th - this.tw) : 0; if (this.view.squarify) this.tw = this.th; this.pad = Math.ceil(this.th * 0.2) * 2.0; // Must be even number var color = s.color.match(/\d+/g); var bgColor = s.backgroundColor.match(/\d+/g); this.defaultColors.r = parseInt(color[0], 10) / 255; this.defaultColors.g = parseInt(color[1], 10) / 255; this.defaultColors.b = parseInt(color[2], 10) / 255; this.defaultColors.br = parseInt(bgColor[0], 10) / 255; this.defaultColors.bg = parseInt(bgColor[1], 10) / 255; this.defaultColors.bb = parseInt(bgColor[2], 10) / 255;}; ut.WebGLRenderer.prototype.clear = function() { /* No op */ }; //////////// RenderFunction `render` has a Cognitive Complexity of 28 (exceeds 5 allowed). Consider refactoring.
Function `render` has 46 lines of code (exceeds 25 allowed). Consider refactoring.ut.WebGLRenderer.prototype.render = function() { "use strict"; var gl = this.gl; gl.clear(gl.COLOR_BUFFER_BIT); var attribs = this.attribs; var w = this.view.w, h = this.view.h; // Create new tile data var tiles = this.view.buffer; var defaultColor = this.view.defaultColor; var defaultBgColor = this.view.defaultBackground; var newChars = false; for (var j = 0; j < h; ++j) { for (var i = 0; i < w; ++i) { var tile = tiles[j][i]; var ch = this.charMap[tile.ch]; if (ch === undefined) { // Auto-cache new characters this.cacheChars(tile.ch, false); newChars = true; ch = this.charMap[tile.ch]; } var k = attribs.color.itemSize * 6 * (j * w + i); var kk = attribs.charIndex.itemSize * 6 * (j * w + i); var r = tile.r === undefined ? this.defaultColors.r : tile.r / 255; var g = tile.g === undefined ? this.defaultColors.g : tile.g / 255; var b = tile.b === undefined ? this.defaultColors.b : tile.b / 255; var br = tile.br === undefined ? this.defaultColors.br : tile.br / 255; var bg = tile.bg === undefined ? this.defaultColors.bg : tile.bg / 255; var bb = tile.bb === undefined ? this.defaultColors.bb : tile.bb / 255; for (var m = 0; m < 6; ++m) { var n = k + m * attribs.color.itemSize; attribs.color.data[n+0] = r; attribs.color.data[n+1] = g; attribs.color.data[n+2] = b; attribs.bgColor.data[n+0] = br; attribs.bgColor.data[n+1] = bg; attribs.bgColor.data[n+2] = bb; attribs.charIndex.data[kk+m] = ch; } } } // Upload if (newChars) this.buildTexture(); gl.bindBuffer(gl.ARRAY_BUFFER, attribs.color.buffer); gl.bufferData(gl.ARRAY_BUFFER, attribs.color.data, attribs.color.hint); gl.bindBuffer(gl.ARRAY_BUFFER, attribs.bgColor.buffer); gl.bufferData(gl.ARRAY_BUFFER, attribs.bgColor.data, attribs.bgColor.hint); gl.bindBuffer(gl.ARRAY_BUFFER, attribs.charIndex.buffer); gl.bufferData(gl.ARRAY_BUFFER, attribs.charIndex.data, attribs.charIndex.hint); var attrib = this.attribs.position; gl.drawArrays(gl.TRIANGLES, 0, attrib.data.length / attrib.itemSize);}; ut.WebGLRenderer.VERTEX_SHADER = [ "attribute vec2 position;", "attribute vec2 texCoord;", "attribute vec3 color;", "attribute vec3 bgColor;", "attribute float charIndex;", "uniform vec2 uResolution;", "uniform vec2 uTileCounts;", "uniform vec2 uPadding;", "varying vec2 vTexCoord;", "varying vec3 vColor;", "varying vec3 vBgColor;", "void main() {", "vec2 tileCoords = floor(vec2(mod(charIndex, uTileCounts.x), charIndex / uTileCounts.x));", "vTexCoord = (texCoord + tileCoords) / uTileCounts;", "vTexCoord += (0.5 - texCoord) * uPadding;", "vColor = color;", "vBgColor = bgColor;", "vec2 pos = position / uResolution * 2.0 - 1.0;", "gl_Position = vec4(pos.x, -pos.y, 0.0, 1.0);", "}"].join('\n'); ut.WebGLRenderer.FRAGMENT_SHADER = [ "precision mediump float;", "uniform sampler2D uFont;", "varying vec2 vTexCoord;", "varying vec3 vColor;", "varying vec3 vBgColor;", "void main() {", "vec4 color = texture2D(uFont, vTexCoord);", "color.rgb = mix(vBgColor, vColor, color.rgb);", "gl_FragColor = color;", "}"].join('\n');