Project

General

Profile

index.html

Hynek Cihlar, 10/19/2020 04:27 AM

Download (18.1 KB)

 
1
<html>
2
    <head>
3
        <script>
4
            /* eslint no-console:0 consistent-return:0 */
5
            "use strict";
6

7
            var vertexShaderSource = `
8
// this will receive data from a buffer
9
attribute vec4 a_position;
10

11
void main() {
12

13
  // shader must set the special variable gl_Position
14
  gl_Position = a_position;
15
}
16
`;
17

18
            var fragmentShaderSource = `
19
// set precision, this is needed as fragment shaders don't have default precision
20
precision mediump float;
21

22
void main() {
23
  // shader must set the special variable gl_FragColor
24
  gl_FragColor = vec4(0, 0, 0, 1); // black
25
}
26
`;
27

28
            function createShader(gl, type, source)
29
            {
30
                var shader = gl.createShader(type);
31
                gl.shaderSource(shader, source);
32
                gl.compileShader(shader);
33
                var success = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
34
                if (success)
35
                {
36
                    return shader;
37
                }
38

39
                console.log(gl.getShaderInfoLog(shader));
40
                gl.deleteShader(shader);
41
            }
42

43
            function createProgram(gl, vertexShader, fragmentShader)
44
            {
45
                var program = gl.createProgram();
46
                gl.attachShader(program, vertexShader);
47
                gl.attachShader(program, fragmentShader);
48
                gl.linkProgram(program);
49
                var success = gl.getProgramParameter(program, gl.LINK_STATUS);
50
                if (success)
51
                {
52
                    return program;
53
                }
54

55
                console.log(gl.getProgramInfoLog(program));
56
                gl.deleteProgram(program);
57
            }
58

59
            var gl;
60
            var canvas;
61
            var program;
62
            var positionAttributeLocation;
63
            var positionBuffer;
64

65
            function oneTimeInitGL(canvasSelector)
66
            {
67
                // get WebGL context
68
                canvas = document.querySelector(canvasSelector);
69
                gl = canvas.getContext("webgl", {antialias: false});
70
                if (!gl)
71
                {
72
                    return;
73
                }
74

75
                var vertexShader = createShader(gl, gl.VERTEX_SHADER, vertexShaderSource);
76
                var fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fragmentShaderSource);
77

78
                // set the two shaders into a program
79
                program = createProgram(gl, vertexShader, fragmentShader);
80

81
                // look up where the vertex data will be assigned
82
                positionAttributeLocation = gl.getAttribLocation(program, "a_position");
83

84
                // create buffer
85
                positionBuffer = gl.createBuffer();
86
            }
87

88
            function clear()
89
            {
90
                // init viewport to convert clip space to pixels
91
                gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
92

93
                gl.clearColor(0, 0, 0, 0);
94
                gl.clear(gl.COLOR_BUFFER_BIT);
95
            }
96

97
            function drawLinesWithTriangles(vertices)
98
            {
99
                // bind it to ARRAY_BUFFER
100
                gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
101

102
                var linesNum = vertices.length / 4;
103
                var pos = new Float32Array(linesNum * 12);
104
                for (var i = 0; i < linesNum; i++)
105
                {
106
                    var j = i * 4;
107

108
                    var x1 = vertices[j];
109
                    var y1 = vertices[j + 1];
110
                    var x2 = vertices[j + 2];
111
                    var y2 = vertices[j + 3];
112

113
                    j = i * 12;
114
                    pos[j] = xtogl(x1, canvas);
115
                    pos[j + 1] = ytogl(y1, canvas);
116
                    pos[j + 2] = xtogl(x1 + 1, canvas);
117
                    pos[j + 3] = ytogl(y1 + 1, canvas);
118
                    pos[j + 4] = xtogl(x2, canvas);
119
                    pos[j + 5] = ytogl(y2, canvas);
120
                    pos[j + 6] = xtogl(x2, canvas);
121
                    pos[j + 7] = ytogl(y2, canvas);
122
                    pos[j + 8] = xtogl(x2 + 1, canvas);
123
                    pos[j + 9] = ytogl(y2 + 1, canvas);
124
                    pos[j + 10] = xtogl(x1 + 1, canvas);
125
                    pos[j + 11] = ytogl(y1 + 1, canvas);
126
                }
127

128
                gl.bufferData(gl.ARRAY_BUFFER, pos, gl.STATIC_DRAW);
129

130
                // which program (with assigned shaders) to use
131
                gl.useProgram(program);
132

133
                // enable the attribute
134
                gl.enableVertexAttribArray(positionAttributeLocation);
135

136
                // set up the attribute how to get data out of positionBuffer (ARRAY_BUFFER)
137
                var size = 2;          // 2 components per iteration
138
                var type = gl.FLOAT;   // the data is 32bit floats
139
                var normalize = false; // don't normalize the data
140
                var stride = 0;        // 0 = move forward size * sizeof(type) each iteration to get the next position
141
                var offset = 0;        // start at the beginning of the buffer
142
                gl.vertexAttribPointer(positionAttributeLocation, size, type, normalize, stride, offset);
143

144
                // draw
145
                var primitiveType = gl.TRIANGLES;
146
                var offset = 0;
147
                var count = 6 * linesNum;
148
                gl.drawArrays(primitiveType, offset, count);
149
            }
150

151
            function drawLinesWithLines(vertices)
152
            {
153
                // bind it to ARRAY_BUFFER
154
                gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
155

156
                var positions = [
157
                    xtogl(20, canvas), ytogl(20, canvas),
158
                    xtogl(100, canvas), ytogl(20, canvas)
159
                ];
160
                gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
161

162
                // which program to use
163
                gl.useProgram(program);
164

165
                // enable the attribute
166
                gl.enableVertexAttribArray(positionAttributeLocation);
167

168
                // set up the attribute how to get data out of positionBuffer (ARRAY_BUFFER)
169
                var size = 2;          // 2 components per iteration
170
                var type = gl.FLOAT;   // the data is 32bit floats
171
                var normalize = false; // don't normalize the data
172
                var stride = 0;        // 0 = move forward size * sizeof(type) each iteration to get the next position
173
                var offset = 0;        // start at the beginning of the buffer
174
                gl.vertexAttribPointer(
175
                        positionAttributeLocation, size, type, normalize, stride, offset);
176

177
                // draw
178
                var primitiveType = gl.LINES;
179
                var offset = 0;
180
                var count = 2;
181
                gl.drawArrays(primitiveType, offset, count);
182
            }
183

184
            function drawRectanglesWithTriangles(vertices)
185
            {
186
                // bind it to ARRAY_BUFFER
187
                gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
188

189
                var positions = [
190
                    xtogl(20, canvas), ytogl(30, canvas),
191
                    xtogl(20, canvas), ytogl(30 + 30, canvas),
192
                    xtogl(100, canvas), ytogl(30, canvas),
193
                    xtogl(100, canvas), ytogl(30, canvas),
194
                    xtogl(100, canvas), ytogl(30 + 30, canvas),
195
                    xtogl(20, canvas), ytogl(30 + 30, canvas)
196

197
                ];
198
                gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
199

200
                // which program to use
201
                gl.useProgram(program);
202

203
                // enable the attribute
204
                gl.enableVertexAttribArray(positionAttributeLocation);
205

206
                // set up the attribute how to get data out of positionBuffer (ARRAY_BUFFER)
207
                var size = 2;          // 2 components per iteration
208
                var type = gl.FLOAT;   // the data is 32bit floats
209
                var normalize = false; // don't normalize the data
210
                var stride = 0;        // 0 = move forward size * sizeof(type) each iteration to get the next position
211
                var offset = 0;        // start at the beginning of the buffer
212
                gl.vertexAttribPointer(
213
                        positionAttributeLocation, size, type, normalize, stride, offset);
214

215
                // draw
216
                var primitiveType = gl.TRIANGLES;
217
                var offset = 0;
218
                var count = 6;
219
                gl.drawArrays(primitiveType, offset, count);
220
            }
221

222
            // convert x from pixel to clip space
223
            function xtogl(x, canvas)
224
            {
225
                var dx = 2 / canvas.width;
226
                return (x - (canvas.width / 2)) * dx;
227
            }
228

229
            // convert y from pixel to clip space
230
            function ytogl(y, canvas)
231
            {
232
                var dy = 2 / canvas.height;
233
                return ((canvas.height - y) - (canvas.height / 2)) * dy;
234
            }
235

236
            function drawLines2DLineTo(lines, screenCtx, ctx, offcanvas)
237
            {
238
                var linesCount = lines.length / 4;
239
                for (var i = 0; i < linesCount; i++)
240
                {
241
                    var curLine = i * 4;
242
                    ctx.beginPath();
243
                    ctx.moveTo(lines[curLine], lines[curLine + 1]);
244
                    ctx.lineTo(lines[curLine + 2], lines[curLine + 3]);
245
                    ctx.closePath();
246
                    ctx.stroke();
247
                }
248

249
                screenCtx.drawImage(offcanvas, 0, 0);
250
            }
251

252
            function drawLines2DPixels(lines, screenCtx, ctx, offcanvas)
253
            {
254
                var linesCount = lines.length / 4;
255
                for (var m = 0; m < linesCount; m++)
256
                {
257
                    var curLine = m * 4;
258
                    var x1 = lines[curLine];
259
                    var y1 = lines[curLine + 1];
260
                    var x2 = lines[curLine + 2];
261
                    var y2 = lines[curLine + 3];
262

263
                    var image = ctx.createImageData(1, 1);
264
                    var imageData = image.data;
265

266
                    for (var i = 0; i < 4; i += 4)
267
                    {
268
                        imageData[i] = 0;
269
                        imageData[i + 1] = 0;
270
                        imageData[i + 2] = 0;
271
                        imageData[i + 3] = 255;
272
                    }
273

274
                    var lineWidth = x2 - x1 + 1;
275
                    var lineHeight = y2 - y1 + 1;
276
                    // Create a line image
277
                    var screenImage = ctx.createImageData(lineWidth, lineHeight);
278
                    var data = screenImage.data;
279
                    var length = 4 * lineWidth * lineHeight;
280

281
                    // Fill a line image with the given stroke color
282
                    data[0] = 0;
283
                    data[1] = 0;
284
                    data[2] = 0;
285
                    data[3] = 255;
286

287
                    var pos = 4;
288
                    var seqLen = 4;
289
                    while (pos < length)
290
                    {
291
                        data.copyWithin(pos, 0, seqLen);
292
                        // increment position by the length of the current segment
293
                        pos += seqLen;
294
                        // double the length of the next segment
295
                        seqLen <<= 1;
296
                    }
297

298
                    ctx.putImageData(screenImage, x1, y1);
299
                }
300

301
                screenCtx.drawImage(offcanvas, 0, 0);
302
            }
303

304
            var two;
305

306
            function initTwo()
307
            {
308
                // var elem = document.getElementById('two_container');
309
                // var params = {width: 1280, height: 720, type: Two.Types.webgl};
310
                // two = new Two(params).appendTo(elem);
311
            }
312

313
            function drawLinesWithTwo(lines)
314
            {
315
                var linesCount = lines.length / 4;
316
                for (var m = 0; m < linesCount; m++)
317
                {
318
                    var curLine = m * 4;
319
                    var x1 = lines[curLine];
320
                    var y1 = lines[curLine + 1];
321
                    var x2 = lines[curLine + 2];
322
                    var y2 = lines[curLine + 3];
323
                    two.makeLine(x1, y1, x2, y2);
324
                }
325

326
                two.update();
327
            }
328

329
            function createOffscreenCanvas()
330
            {
331
                var isChrome = navigator.userAgent.toLowerCase().indexOf('chrome') > -1;
332

333
                /**
334
                 *  The off screen canvas to be used to make batch drawing.
335
                 *
336
                 *  Canvas created with document.createElement is very slow in Chrome, use OffscreenCanvas instead.
337
                 *  Chrome version 79 is known to have drawing issues with OffscreenCanvas, see #4473.
338
                 */
339
                var offcanvas;
340
                if (isChrome && typeof OffscreenCanvas != "undefined")
341
                {
342
                    offcanvas = new OffscreenCanvas(1280, 720);
343
                }
344
                else
345
                {
346
                    offcanvas = document.createElement('canvas');
347
                    offcanvas.width = 1280;
348
                    offcanvas.height = 720;
349
                }
350

351
                return offcanvas;
352
            }
353

354

355
            function main(iterations, linesPerIteration)
356
            {
357
                var offcanvas2 = createOffscreenCanvas();
358
                var offcanvas3 = createOffscreenCanvas();
359

360
                var canvas2 = document.querySelector("#mycanvas2");
361
                var screenCtx2 = canvas2.getContext("2d");
362
                var ctx2 = offcanvas2.getContext("2d");
363
                screenCtx2.imageSmoothingEnabled = false;
364
                ctx2.imageSmoothingEnabled = false;
365

366
                var canvas3 = document.querySelector("#mycanvas3");
367
                var screenCtx3 = canvas3.getContext("2d");
368
                var ctx3 = offcanvas3.getContext("2d");
369
                screenCtx3.imageSmoothingEnabled = false;
370
                ctx3.imageSmoothingEnabled = false;
371

372
                oneTimeInitGL("#mycanvas");
373
                initTwo();
374

375
                var res = [];
376
                var headers = ["Number of lines", "Web GL", "2D lineTo", "2D pixel"];
377
                res.push(headers);
378

379
                for (var j = 1; j <= iterations; j++)
380
                {
381
                    var oneRes = [];
382
                    oneRes.push(linesPerIteration * j);
383
                    var lines = [];
384
                    for (var i = 0; i < (linesPerIteration * j); i++)
385
                    {
386
                        var x1 = Math.round(1280 * Math.random());
387
                        var x2 = Math.round(1280 * Math.random());
388
                        if (x1 > x2)
389
                        {
390
                            var x = x2;
391
                            x2 = x1;
392
                            x1 = x;
393
                        }
394

395
                        var y1 = Math.round(720 * Math.random());
396
                        var y2 = Math.round(720 * Math.random());
397
                        if (y1 > y2)
398
                        {
399
                            var y = y2;
400
                            y2 = y1;
401
                            y1 = y;
402
                        }
403

404
                        var dir = Math.random();
405
                        if (dir <= 0.5)
406
                        {
407
                            // horizontal
408
                            y2 = y1;
409
                        } else
410
                        {
411
                            // vertical
412
                            x2 = x1;
413
                        }
414

415
                        lines.push(x1);
416
                        lines.push(y1);
417
                        lines.push(x2);
418
                        lines.push(y2);
419
                    }
420

421
                    var t1 = window.performance.now();
422
                    drawLinesWithTriangles(lines);
423
                    var t2 = window.performance.now();
424
                    console.log("WebGL took " + (t2 - t1) + " ms");
425
                    oneRes.push(t2 - t1);
426
                    // drawLinesWithLines();
427
                    // drawRectanglesWithTriangles();
428

429
                    t1 = window.performance.now();
430
                    drawLines2DLineTo(lines, screenCtx2, ctx2, offcanvas2);
431
                    t2 = window.performance.now();
432
                    console.log("2D lineTo took " + (t2 - t1) + " ms");
433
                    oneRes.push(t2 - t1);
434

435
                    t1 = window.performance.now();
436
                    drawLines2DPixels(lines, screenCtx3, ctx3, offcanvas3);
437
                    t2 = window.performance.now();
438
                    console.log("2D pixels took " + (t2 - t1) + " ms");
439
                    oneRes.push(t2 - t1);
440

441
                    //t1 = window.performance.now();
442
                    //drawLinesWithTwo(lines);
443
                    //t2 = window.performance.now();
444
                    //console.log("Two took " + (t2 - t1) + " ms");
445
                    //oneRes.push(t2 - t1);
446

447
                    res.push(oneRes);
448
                }
449

450
                var results = document.querySelector("#results");
451
                var tbl = document.createElement('table');
452
                tbl.style.width = '100%';
453
                tbl.setAttribute('border', '1');
454
                var tbdy = document.createElement('tbody');
455
                for (var i = 0; i < res[0].length; i++)
456
                {
457
                    var tr = document.createElement('tr');
458
                    for (var j = 0; j < res.length; j++)
459
                    {
460
                        var td = document.createElement('td');
461
                        td.appendChild(document.createTextNode("" + res[j][i]))
462
                        tr.appendChild(td)
463
                    }
464
                    tbdy.appendChild(tr);
465
                }
466
                tbl.appendChild(tbdy);
467
                results.appendChild(tbl)
468
            }
469
        </script>
470
    </head>
471

    
472
    <body onload="main(10, 2000);">
473
        <div>Two.js:</div>
474
        <div id="two_container"></div>
475
        <div>Web GL:</div>
476
        <canvas id="mycanvas" width="1280" height="720" style="width:1280px; height: 720px"></canvas>
477
        <div>2D lineTo:</div>
478
        <canvas id="mycanvas2" width="1280" height="720" style="width:1280px; height: 720px"></canvas>
479
        <div>2D pixel:</div>
480
        <canvas id="mycanvas3" width="1280" height="720" style="width:1280px; height: 720px"></canvas>
481
        <div id="results">Results</div>
482
    </body>
483
</html>