Skip to content

Commit 2ac9884

Browse files
committed
[#1172] enable batch drawing for primitive shapes
Changes: - use g.LINES when possible/applicable - split the WebGLCompositor into two classes, `QuadCompositor` for Quad (Sprite) drawing, and `PrimitiveCompositor` to draw vertices - fixed binding of active shader when switching - color for drawing primitive is now a vertex attributes (as opposed to an uniform previously) TODO : - Optimize the `arcTo` function to use gl.LINES and enable batching for circle/ellipse and rounded rectangles - Cache of optimize triangulation for filling operations. currently the bottleneck when drawing large amount (> 1000) of shapes
1 parent 63fad7e commit 2ac9884

File tree

8 files changed

+157
-115
lines changed

8 files changed

+157
-115
lines changed

src/geometries/path2d.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -242,9 +242,6 @@ import earcut from "earcut";
242242
points.push(pool.pull("Point", _x2, _y2));
243243
angle += direction * dangle;
244244
}
245-
//var x1 = radiusX * Math.cos(endAngle);
246-
//var y1 = radiusY * Math.sin(endAngle);
247-
//points.push(pool.pull("Point", x + x1 * cos_rotation - y1 * sin_rotation, y + x1 * sin_rotation + y1 * cos_rotation));
248245
}
249246

250247
/**
@@ -257,8 +254,11 @@ import earcut from "earcut";
257254
rect(x, y, width, height) {
258255
this.moveTo(x, y);
259256
this.lineTo(x + width, y);
257+
this.moveTo(x + width, y);
260258
this.lineTo(x + width, y + height);
259+
this.moveTo(x + width, y + height);
261260
this.lineTo(x, y + height);
261+
this.moveTo(x, y + height);
262262
this.lineTo(x, y);
263263
}
264264

src/index.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@ import Body from "./physics/body.js";
2020
import Bounds from "./physics/bounds.js";
2121
import Tween from "./tweens/tween.js";
2222
import GLShader from "./video/webgl/glshader.js";
23-
import WebGLCompositor from "./video/webgl/compositors/webgl_compositor.js";
23+
import Compositor from "./video/webgl/compositors/compositor.js";
24+
import PrimitiveCompositor from "./video/webgl/compositors/primitive_compositor.js";
25+
import QuadCompositor from "./video/webgl/compositors/quad_compositor.js";
2426
import Renderer from "./video/renderer.js";
2527
import WebGLRenderer from "./video/webgl/webgl_renderer.js";
2628
import CanvasRenderer from "./video/canvas/canvas_renderer.js";
@@ -127,7 +129,9 @@ export {
127129
Tween,
128130
QuadTree,
129131
GLShader,
130-
WebGLCompositor,
132+
Compositor,
133+
PrimitiveCompositor,
134+
QuadCompositor,
131135
Renderer,
132136
WebGLRenderer,
133137
CanvasRenderer,

src/video/webgl/compositors/compositor.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,19 @@ import * as event from "../../../system/event.js";
9797
this.clearColor(0.0, 0.0, 0.0, 0.0);
9898
}
9999

100+
/**
101+
* @ignore
102+
* called by the WebGL renderer when a compositor become the current one
103+
*/
104+
bind() {
105+
if (this.activeShader !== null) {
106+
this.activeShader.bind();
107+
this.activeShader.setUniform("uProjectionMatrix", this.renderer.projectionMatrix);
108+
this.activeShader.setVertexAttributes(this.gl, this.attributes, this.vertexByteSize);
109+
}
110+
this.gl.bufferData(this.gl.ARRAY_BUFFER, this.vertexBuffer.buffer, this.gl.STREAM_DRAW);
111+
}
112+
100113
/**
101114
* add vertex attribute property definition to the compositor
102115
* @param {string} name - name of the attribute in the vertex shader
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
import GLShader from "../glshader.js";
2+
import VertexArrayBuffer from "../buffer/vertex.js";
3+
import primitiveVertex from "./../shaders/primitive.vert";
4+
import primitiveFragment from "./../shaders/primitive.frag";
5+
import Compositor from "./compositor.js";
6+
7+
/**
8+
* @classdesc
9+
* A WebGL Compositor object. This class handles all of the WebGL state<br>
10+
* Pushes texture regions or shape geometry into WebGL buffers, automatically flushes to GPU
11+
* @augments Compositor
12+
*/
13+
export default class PrimitiveCompositor extends Compositor {
14+
15+
/**
16+
* Initialize the compositor
17+
* @ignore
18+
*/
19+
init (renderer) {
20+
super.init(renderer);
21+
22+
// Load and create shader programs
23+
this.primitiveShader = new GLShader(this.gl, primitiveVertex, primitiveFragment);
24+
25+
/// define all vertex attributes
26+
this.addAttribute("aVertex", 2, this.gl.FLOAT, false, 0 * Float32Array.BYTES_PER_ELEMENT); // 0
27+
this.addAttribute("aColor", 4, this.gl.UNSIGNED_BYTE, true, 2 * Float32Array.BYTES_PER_ELEMENT); // 1
28+
29+
this.vertexBuffer = new VertexArrayBuffer(this.vertexSize, 6);
30+
31+
// vertex buffer
32+
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.gl.createBuffer());
33+
this.gl.bufferData(this.gl.ARRAY_BUFFER, this.vertexBuffer.buffer, this.gl.STREAM_DRAW);
34+
}
35+
36+
/**
37+
* Reset compositor internal state
38+
* @ignore
39+
*/
40+
reset() {
41+
super.reset();
42+
43+
// set the quad shader as the default program
44+
this.useShader(this.primitiveShader);
45+
}
46+
47+
/**
48+
* Draw an array of vertices
49+
* @param {GLenum} mode - primitive type to render (gl.POINTS, gl.LINE_STRIP, gl.LINE_LOOP, gl.LINES, gl.TRIANGLE_STRIP, gl.TRIANGLE_FAN, gl.TRIANGLES)
50+
* @param {Point[]} verts - an array of vertices
51+
* @param {number} [vertexCount=verts.length] - amount of points defined in the points array
52+
*/
53+
drawVertices(mode, verts, vertexCount = verts.length) {
54+
var viewMatrix = this.viewMatrix;
55+
var vertexBuffer = this.vertexBuffer;
56+
var color = this.renderer.currentColor;
57+
var alpha = this.renderer.getGlobalAlpha();
58+
59+
if (vertexBuffer.isFull(vertexCount)) {
60+
// is the vertex buffer full if we add more vertices
61+
this.flush();
62+
}
63+
64+
// flush if drawing vertices with a different drawing mode
65+
if (mode !== this.mode) {
66+
this.flush(this.mode);
67+
this.mode = mode;
68+
}
69+
70+
if (!viewMatrix.isIdentity()) {
71+
verts.forEach((vert) => {
72+
viewMatrix.apply(vert);
73+
vertexBuffer.push(vert.x, vert.y, undefined, undefined, color.toUint32(alpha));
74+
});
75+
} else {
76+
verts.forEach((vert) => {
77+
vertexBuffer.push(vert.x, vert.y, undefined, undefined, color.toUint32(alpha));
78+
});
79+
}
80+
81+
// disable batching for primitive using LINE_STRIP or LINE_LOOP
82+
if (this.mode === this.gl.LINE_STRIP || this.mode === this.gl.LINE_LOOP) {
83+
this.flush(this.mode);
84+
}
85+
}
86+
}

src/video/webgl/compositors/webgl_compositor.js renamed to src/video/webgl/compositors/quad_compositor.js

Lines changed: 10 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@ import Vector2d from "../../../math/vector2.js";
22
import GLShader from "../glshader.js";
33
import VertexArrayBuffer from "../buffer/vertex.js";
44
import { isPowerOfTwo } from "../../../math/math.js";
5-
import primitiveVertex from "./../shaders/primitive.vert";
6-
import primitiveFragment from "./../shaders/primitive.frag";
75
import quadVertex from "./../shaders/quad.vert";
86
import quadFragment from "./../shaders/quad.frag";
97
import Compositor from "./compositor.js";
@@ -22,7 +20,7 @@ var V_ARRAY = [
2220
* Pushes texture regions or shape geometry into WebGL buffers, automatically flushes to GPU
2321
* @augments Compositor
2422
*/
25-
export default class WebGLCompositor extends Compositor {
23+
export default class QuadCompositor extends Compositor {
2624

2725
/**
2826
* Initialize the compositor
@@ -36,15 +34,14 @@ var V_ARRAY = [
3634
this.boundTextures = [];
3735

3836
// Load and create shader programs
39-
this.primitiveShader = new GLShader(this.gl, primitiveVertex, primitiveFragment);
4037
this.quadShader = new GLShader(this.gl, quadVertex, quadFragment);
4138

4239
/// define all vertex attributes
4340
this.addAttribute("aVertex", 2, this.gl.FLOAT, false, 0 * Float32Array.BYTES_PER_ELEMENT); // 0
4441
this.addAttribute("aRegion", 2, this.gl.FLOAT, false, 2 * Float32Array.BYTES_PER_ELEMENT); // 1
4542
this.addAttribute("aColor", 4, this.gl.UNSIGNED_BYTE, true, 4 * Float32Array.BYTES_PER_ELEMENT); // 2
4643

47-
this.vertexBuffer = new VertexArrayBuffer(this.vertexSize, 6); // 6 vertices per quad
44+
this.vertexBuffer = new VertexArrayBuffer(this.vertexSize, 6);
4845

4946
// vertex buffer
5047
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.gl.createBuffer());
@@ -201,22 +198,6 @@ var V_ARRAY = [
201198
return this.currentTextureUnit;
202199
}
203200

204-
205-
/**
206-
* Select the shader to use for compositing
207-
* @see GLShader
208-
* @param {GLShader} shader - a reference to a GLShader instance
209-
*/
210-
useShader(shader) {
211-
if (this.activeShader !== shader) {
212-
this.flush();
213-
this.activeShader = shader;
214-
this.activeShader.bind();
215-
this.activeShader.setUniform("uProjectionMatrix", this.renderer.projectionMatrix);
216-
this.activeShader.setVertexAttributes(this.gl, this.attributes, this.vertexByteSize);
217-
}
218-
}
219-
220201
/**
221202
* Add a textured quad
222203
* @param {TextureAtlas} texture - Source texture atlas
@@ -231,15 +212,9 @@ var V_ARRAY = [
231212
* @param {number} tint - tint color to be applied to the texture in UINT32 (argb) format
232213
*/
233214
addQuad(texture, x, y, w, h, u0, v0, u1, v1, tint) {
215+
var vertexBuffer = this.vertexBuffer;
234216

235-
if (this.color.alpha < 1 / 255) {
236-
// Fast path: don't send fully transparent quads
237-
return;
238-
}
239-
240-
this.useShader(this.quadShader);
241-
242-
if (this.vertexBuffer.isFull(6)) {
217+
if (vertexBuffer.isFull(6)) {
243218
// is the vertex buffer full if we add 6 more vertices
244219
this.flush();
245220
}
@@ -263,38 +238,11 @@ var V_ARRAY = [
263238
m.apply(vec3);
264239
}
265240

266-
this.vertexBuffer.push(vec0.x, vec0.y, u0, v0, tint);
267-
this.vertexBuffer.push(vec1.x, vec1.y, u1, v0, tint);
268-
this.vertexBuffer.push(vec2.x, vec2.y, u0, v1, tint);
269-
this.vertexBuffer.push(vec2.x, vec2.y, u0, v1, tint);
270-
this.vertexBuffer.push(vec1.x, vec1.y, u1, v0, tint);
271-
this.vertexBuffer.push(vec3.x, vec3.y, u1, v1, tint);
272-
}
273-
274-
/**
275-
* Draw an array of vertices
276-
* @param {GLenum} mode - primitive type to render (gl.POINTS, gl.LINE_STRIP, gl.LINE_LOOP, gl.LINES, gl.TRIANGLE_STRIP, gl.TRIANGLE_FAN, gl.TRIANGLES)
277-
* @param {Point[]} verts - an array of vertices
278-
* @param {number} [vertexCount=verts.length] - amount of points defined in the points array
279-
*/
280-
drawVertices(mode, verts, vertexCount = verts.length) {
281-
// use the primitive shader
282-
this.useShader(this.primitiveShader);
283-
// Set the line color
284-
this.primitiveShader.setUniform("uColor", this.color);
285-
286-
var m = this.viewMatrix;
287-
var vertex = this.vertexBuffer;
288-
var m_isIdentity = m.isIdentity();
289-
290-
for (var i = 0; i < vertexCount; i++) {
291-
if (!m_isIdentity) {
292-
m.apply(verts[i]);
293-
}
294-
vertex.push(verts[i].x, verts[i].y);
295-
}
296-
297-
// flush
298-
this.flush(mode);
241+
vertexBuffer.push(vec0.x, vec0.y, u0, v0, tint);
242+
vertexBuffer.push(vec1.x, vec1.y, u1, v0, tint);
243+
vertexBuffer.push(vec2.x, vec2.y, u0, v1, tint);
244+
vertexBuffer.push(vec2.x, vec2.y, u0, v1, tint);
245+
vertexBuffer.push(vec1.x, vec1.y, u1, v0, tint);
246+
vertexBuffer.push(vec3.x, vec3.y, u1, v1, tint);
299247
}
300248
}
Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,15 @@
11
// Current vertex point
22
attribute vec2 aVertex;
3+
attribute vec4 aColor;
34

45
// Projection matrix
56
uniform mat4 uProjectionMatrix;
67

7-
// Vertex color
8-
uniform vec4 uColor;
9-
10-
// Fragment color
118
varying vec4 vColor;
129

1310
void main(void) {
1411
// Transform the vertex position by the projection matrix
1512
gl_Position = uProjectionMatrix * vec4(aVertex, 0.0, 1.0);
1613
// Pass the remaining attributes to the fragment shader
17-
vColor = vec4(uColor.rgb * uColor.a, uColor.a);
14+
vColor = vec4(aColor.bgr * aColor.a, aColor.a);
1815
}

src/video/webgl/shaders/quad.vert

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
1+
// Current vertex point
12
attribute vec2 aVertex;
23
attribute vec2 aRegion;
34
attribute vec4 aColor;
45

6+
// Projection matrix
57
uniform mat4 uProjectionMatrix;
68

79
varying vec2 vRegion;
810
varying vec4 vColor;
911

1012
void main(void) {
1113
// Transform the vertex position by the projection matrix
12-
gl_Position = uProjectionMatrix * vec4(aVertex, 0.0, 1.0);
14+
gl_Position = uProjectionMatrix * vec4(aVertex, 0.0, 1.0);
1315
// Pass the remaining attributes to the fragment shader
1416
vColor = vec4(aColor.bgr * aColor.a, aColor.a);
1517
vRegion = aRegion;

0 commit comments

Comments
 (0)