forked from anvaka/VivaGraphJS
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathwebglLinkProgram.js
More file actions
156 lines (128 loc) · 5.3 KB
/
Copy pathwebglLinkProgram.js
File metadata and controls
156 lines (128 loc) · 5.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
/**
* @fileOverview Defines a naive form of links for webglGraphics class.
* This form allows to change color of links.
**/
var glUtils = require('./webgl.js');
module.exports = webglLinkProgram;
/**
* Defines UI for links in webgl renderer.
*/
function webglLinkProgram() {
var ATTRIBUTES_PER_PRIMITIVE = 6, // primitive is Line with two points. Each has x,y and color = 3 * 2 attributes.
BYTES_PER_LINK = 2 * (2 * Float32Array.BYTES_PER_ELEMENT + Uint32Array.BYTES_PER_ELEMENT), // two nodes * (x, y + color)
linksFS = [
'precision mediump float;',
'varying vec4 color;',
'void main(void) {',
' gl_FragColor = color;',
'}'
].join('\n'),
linksVS = [
'attribute vec2 a_vertexPos;',
'attribute vec4 a_color;',
'uniform vec2 u_screenSize;',
'uniform mat4 u_transform;',
'varying vec4 color;',
'void main(void) {',
' gl_Position = u_transform * vec4(a_vertexPos/u_screenSize, 0.0, 1.0);',
' color = a_color.abgr;',
'}'
].join('\n'),
program,
gl,
buffer,
utils,
locations,
linksCount = 0,
frontLinkId, // used to track z-index of links.
storage = new ArrayBuffer(16 * BYTES_PER_LINK),
positions = new Float32Array(storage),
colors = new Uint32Array(storage),
width,
height,
transform,
sizeDirty,
ensureEnoughStorage = function () {
// TODO: this is a duplicate of webglNodeProgram code. Extract it to webgl.js
if ((linksCount+1)*BYTES_PER_LINK > storage.byteLength) {
// Every time we run out of space create new array twice bigger.
// TODO: it seems buffer size is limited. Consider using multiple arrays for huge graphs
var extendedStorage = new ArrayBuffer(storage.byteLength * 2),
extendedPositions = new Float32Array(extendedStorage),
extendedColors = new Uint32Array(extendedStorage);
extendedColors.set(colors); // should be enough to copy just one view.
positions = extendedPositions;
colors = extendedColors;
storage = extendedStorage;
}
};
return {
load : function (glContext) {
gl = glContext;
utils = glUtils(glContext);
program = utils.createProgram(linksVS, linksFS);
gl.useProgram(program);
locations = utils.getLocations(program, ['a_vertexPos', 'a_color', 'u_screenSize', 'u_transform']);
gl.enableVertexAttribArray(locations.vertexPos);
gl.enableVertexAttribArray(locations.color);
buffer = gl.createBuffer();
},
position: function (linkUi, fromPos, toPos) {
var linkIdx = linkUi.id,
offset = linkIdx * ATTRIBUTES_PER_PRIMITIVE;
positions[offset] = fromPos.x;
positions[offset + 1] = fromPos.y;
colors[offset + 2] = linkUi.color;
positions[offset + 3] = toPos.x;
positions[offset + 4] = toPos.y;
colors[offset + 5] = linkUi.color;
},
createLink : function (ui) {
ensureEnoughStorage();
linksCount += 1;
frontLinkId = ui.id;
},
removeLink : function (ui) {
if (linksCount > 0) { linksCount -= 1; }
// swap removed link with the last link. This will give us O(1) performance for links removal:
if (ui.id < linksCount && linksCount > 0) {
// using colors as a view to array buffer is okay here.
utils.copyArrayPart(colors, ui.id * ATTRIBUTES_PER_PRIMITIVE, linksCount * ATTRIBUTES_PER_PRIMITIVE, ATTRIBUTES_PER_PRIMITIVE);
}
},
updateTransform : function (newTransform) {
sizeDirty = true;
transform = newTransform;
},
updateSize : function (w, h) {
width = w;
height = h;
sizeDirty = true;
},
render : function () {
gl.useProgram(program);
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, storage, gl.DYNAMIC_DRAW);
if (sizeDirty) {
sizeDirty = false;
gl.uniformMatrix4fv(locations.transform, false, transform);
gl.uniform2f(locations.screenSize, width, height);
}
gl.vertexAttribPointer(locations.vertexPos, 2, gl.FLOAT, false, 3 * Float32Array.BYTES_PER_ELEMENT, 0);
gl.vertexAttribPointer(locations.color, 4, gl.UNSIGNED_BYTE, true, 3 * Float32Array.BYTES_PER_ELEMENT, 2 * 4);
gl.drawArrays(gl.LINES, 0, linksCount * 2);
frontLinkId = linksCount - 1;
},
bringToFront : function (link) {
if (frontLinkId > link.id) {
utils.swapArrayPart(positions, link.id * ATTRIBUTES_PER_PRIMITIVE, frontLinkId * ATTRIBUTES_PER_PRIMITIVE, ATTRIBUTES_PER_PRIMITIVE);
}
if (frontLinkId > 0) {
frontLinkId -= 1;
}
},
getFrontLinkId : function () {
return frontLinkId;
}
};
}