;(function() { 'use strict'; sigma.utils.pkg('sigma.webgl.nodes'); /** * This node renderer will display nodes as discs, shaped in triangles with * the gl.TRIANGLES display mode. So, to be more precise, to draw one node, * it will store three times the center of node, with the color and the size, * and an angle indicating which "corner" of the triangle to draw. * * The fragment shader does not deal with anti-aliasing, so make sure that * you deal with it somewhere else in the code (by default, the WebGL * renderer will oversample the rendering through the webglOversamplingRatio * value). */ sigma.webgl.nodes.def = { POINTS: 3, ATTRIBUTES: 5, addNode: function(node, data, i, prefix, settings) { var color = sigma.utils.floatColor( node.color || settings('defaultNodeColor') ); data[i++] = node[prefix + 'x']; data[i++] = node[prefix + 'y']; data[i++] = node[prefix + 'size']; data[i++] = color; data[i++] = 0; data[i++] = node[prefix + 'x']; data[i++] = node[prefix + 'y']; data[i++] = node[prefix + 'size']; data[i++] = color; data[i++] = 2 * Math.PI / 3; data[i++] = node[prefix + 'x']; data[i++] = node[prefix + 'y']; data[i++] = node[prefix + 'size']; data[i++] = color; data[i++] = 4 * Math.PI / 3; }, render: function(gl, program, data, params) { var buffer; // Define attributes: var positionLocation = gl.getAttribLocation(program, 'a_position'), sizeLocation = gl.getAttribLocation(program, 'a_size'), colorLocation = gl.getAttribLocation(program, 'a_color'), angleLocation = gl.getAttribLocation(program, 'a_angle'), resolutionLocation = gl.getUniformLocation(program, 'u_resolution'), matrixLocation = gl.getUniformLocation(program, 'u_matrix'), ratioLocation = gl.getUniformLocation(program, 'u_ratio'), scaleLocation = gl.getUniformLocation(program, 'u_scale'); buffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, buffer); gl.bufferData(gl.ARRAY_BUFFER, data, gl.DYNAMIC_DRAW); gl.uniform2f(resolutionLocation, params.width, params.height); gl.uniform1f( ratioLocation, 1 / Math.pow(params.ratio, params.settings('nodesPowRatio')) ); gl.uniform1f(scaleLocation, params.scalingRatio); gl.uniformMatrix3fv(matrixLocation, false, params.matrix); gl.enableVertexAttribArray(positionLocation); gl.enableVertexAttribArray(sizeLocation); gl.enableVertexAttribArray(colorLocation); gl.enableVertexAttribArray(angleLocation); gl.vertexAttribPointer( positionLocation, 2, gl.FLOAT, false, this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT, 0 ); gl.vertexAttribPointer( sizeLocation, 1, gl.FLOAT, false, this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT, 8 ); gl.vertexAttribPointer( colorLocation, 1, gl.FLOAT, false, this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT, 12 ); gl.vertexAttribPointer( angleLocation, 1, gl.FLOAT, false, this.ATTRIBUTES * Float32Array.BYTES_PER_ELEMENT, 16 ); gl.drawArrays( gl.TRIANGLES, params.start || 0, params.count || (data.length / this.ATTRIBUTES) ); }, initProgram: function(gl) { var vertexShader, fragmentShader, program; vertexShader = sigma.utils.loadShader( gl, [ 'attribute vec2 a_position;', 'attribute float a_size;', 'attribute float a_color;', 'attribute float a_angle;', 'uniform vec2 u_resolution;', 'uniform float u_ratio;', 'uniform float u_scale;', 'uniform mat3 u_matrix;', 'varying vec4 color;', 'varying vec2 center;', 'varying float radius;', 'void main() {', // Multiply the point size twice: 'radius = a_size * u_ratio;', // Scale from [[-1 1] [-1 1]] to the container: 'vec2 position = (u_matrix * vec3(a_position, 1)).xy;', // 'center = (position / u_resolution * 2.0 - 1.0) * vec2(1, -1);', 'center = position * u_scale;', 'center = vec2(center.x, u_scale * u_resolution.y - center.y);', 'position = position +', '2.0 * radius * vec2(cos(a_angle), sin(a_angle));', 'position = (position / u_resolution * 2.0 - 1.0) * vec2(1, -1);', 'radius = radius * u_scale;', 'gl_Position = vec4(position, 0, 1);', // Extract the color: 'float c = a_color;', 'color.b = mod(c, 256.0); c = floor(c / 256.0);', 'color.g = mod(c, 256.0); c = floor(c / 256.0);', 'color.r = mod(c, 256.0); c = floor(c / 256.0); color /= 255.0;', 'color.a = 1.0;', '}' ].join('\n'), gl.VERTEX_SHADER ); fragmentShader = sigma.utils.loadShader( gl, [ 'precision mediump float;', 'varying vec4 color;', 'varying vec2 center;', 'varying float radius;', 'void main(void) {', 'vec4 color0 = vec4(0.0, 0.0, 0.0, 0.0);', 'vec2 m = gl_FragCoord.xy - center;', 'float diff = radius - sqrt(m.x * m.x + m.y * m.y);', // Here is how we draw a disc instead of a square: 'if (diff > 0.0)', 'gl_FragColor = color;', 'else', 'gl_FragColor = color0;', '}' ].join('\n'), gl.FRAGMENT_SHADER ); program = sigma.utils.loadProgram(gl, [vertexShader, fragmentShader]); return program; } }; })();