@@ -75,42 +75,84 @@ class PenSkin extends Skin {
75
75
// tw: keep track of native size
76
76
this . _nativeSize = renderer . getNativeSize ( ) ;
77
77
78
- // tw: create the extra data structures needed to buffer pen
79
- this . _resetAttributeIndex ( ) ;
80
- this . attribute_data = new Float32Array ( PEN_ATTRIBUTE_BUFFER_SIZE ) ;
81
-
82
78
const NO_EFFECTS = 0 ;
83
79
/** @type {twgl.ProgramInfo } */
84
80
this . _lineShader = this . _renderer . _shaderManager . getShader ( ShaderManager . DRAW_MODE . line , NO_EFFECTS ) ;
85
81
86
- // tw: draw region used to preserve texture when resizing
82
+ // Draw region used to preserve texture when resizing
87
83
this . _drawTextureShader = this . _renderer . _shaderManager . getShader ( ShaderManager . DRAW_MODE . default , NO_EFFECTS ) ;
88
84
/** @type {object } */
89
85
this . _drawTextureRegionId = {
90
86
enter : ( ) => this . _enterDrawTexture ( ) ,
91
87
exit : ( ) => this . _exitDrawTexture ( )
92
88
} ;
93
89
90
+ this . a_position_glbuffer = gl . createBuffer ( ) ;
94
91
this . a_position_loc = gl . getAttribLocation ( this . _lineShader . program , 'a_position' ) ;
95
- gl . bindBuffer ( gl . ARRAY_BUFFER , this . a_position_glbuffer = gl . createBuffer ( ) ) ;
96
- gl . bufferData ( gl . ARRAY_BUFFER , new Float32Array ( [
97
- 1 , 0 ,
98
- 0 , 0 ,
99
- 1 , 1 ,
100
- 1 , 1 ,
101
- 0 , 0 ,
102
- 0 , 1
103
- ] ) , gl . STATIC_DRAW ) ;
104
92
93
+ this . attribute_glbuffer = gl . createBuffer ( ) ;
94
+ this . attribute_index = 0 ;
105
95
this . a_lineColor_loc = gl . getAttribLocation ( this . _lineShader . program , 'a_lineColor' ) ;
106
96
this . a_lineThicknessAndLength_loc = gl . getAttribLocation ( this . _lineShader . program , 'a_lineThicknessAndLength' ) ;
107
97
this . a_penPoints_loc = gl . getAttribLocation ( this . _lineShader . program , 'a_penPoints' ) ;
108
- gl . bindBuffer ( gl . ARRAY_BUFFER , this . attribute_buffer = gl . createBuffer ( ) ) ;
109
- gl . bufferData ( gl . ARRAY_BUFFER , this . attribute_data . length * 4 , gl . STREAM_DRAW ) ;
110
98
111
- if ( ! gl . drawArraysInstanced ) {
112
- // Fallback to ANGLE_instanced_arrays
113
- this . instanced_arrays_ext = gl . getExtension ( 'ANGLE_instanced_arrays' ) ;
99
+ if ( gl . drawArraysInstanced ) {
100
+ // WebGL2 has native instanced rendering
101
+ this . instancedRendering = true ;
102
+ this . glDrawArraysInstanced = gl . drawArraysInstanced . bind ( gl ) ;
103
+ this . glVertexAttribDivisor = gl . vertexAttribDivisor . bind ( gl ) ;
104
+ } else {
105
+ // WebGL1 may have instanced rendering through the ANGLE_instanced_arrays extension
106
+ const instancedArraysExtension = gl . getExtension ( 'ANGLE_instanced_arrays' ) ;
107
+ if ( instancedArraysExtension ) {
108
+ this . instancedRendering = true ;
109
+ this . glDrawArraysInstanced = instancedArraysExtension . drawElementsInstancedANGLE . bind (
110
+ instancedArraysExtension
111
+ ) ;
112
+ this . glVertexAttribDivisor = instancedArraysExtension . vertexAttribDivisorANGLE . bind (
113
+ instancedArraysExtension
114
+ ) ;
115
+ } else {
116
+ this . instancedRendering = false ;
117
+ }
118
+ }
119
+
120
+ if ( this . instancedRendering ) {
121
+ gl . bindBuffer ( gl . ARRAY_BUFFER , this . a_position_glbuffer ) ;
122
+ gl . bufferData ( gl . ARRAY_BUFFER , new Float32Array ( [
123
+ 1 , 0 ,
124
+ 0 , 0 ,
125
+ 1 , 1 ,
126
+ 1 , 1 ,
127
+ 0 , 0 ,
128
+ 0 , 1
129
+ ] ) , gl . STATIC_DRAW ) ;
130
+
131
+ this . attribute_data = new Float32Array ( PEN_ATTRIBUTE_BUFFER_SIZE ) ;
132
+ gl . bindBuffer ( gl . ARRAY_BUFFER , this . attribute_glbuffer ) ;
133
+ gl . bufferData ( gl . ARRAY_BUFFER , this . attribute_data . length * 4 , gl . STREAM_DRAW ) ;
134
+ } else {
135
+ const positionBuffer = new Float32Array ( PEN_ATTRIBUTE_BUFFER_SIZE / PEN_ATTRIBUTE_STRIDE * 2 ) ;
136
+ for ( let i = 0 ; i < positionBuffer . length ; i += 12 ) {
137
+ positionBuffer [ i + 0 ] = 1 ;
138
+ positionBuffer [ i + 1 ] = 0 ;
139
+ positionBuffer [ i + 2 ] = 0 ;
140
+ positionBuffer [ i + 3 ] = 0 ;
141
+ positionBuffer [ i + 4 ] = 1 ;
142
+ positionBuffer [ i + 5 ] = 1 ;
143
+ positionBuffer [ i + 6 ] = 1 ;
144
+ positionBuffer [ i + 7 ] = 1 ;
145
+ positionBuffer [ i + 8 ] = 0 ;
146
+ positionBuffer [ i + 9 ] = 0 ;
147
+ positionBuffer [ i + 10 ] = 0 ;
148
+ positionBuffer [ i + 11 ] = 1 ;
149
+ }
150
+ gl . bindBuffer ( gl . ARRAY_BUFFER , this . a_position_glbuffer ) ;
151
+ gl . bufferData ( gl . ARRAY_BUFFER , positionBuffer , gl . STATIC_DRAW ) ;
152
+
153
+ this . attribute_data = new Float32Array ( PEN_ATTRIBUTE_BUFFER_SIZE ) ;
154
+ gl . bindBuffer ( gl . ARRAY_BUFFER , this . attribute_glbuffer ) ;
155
+ gl . bufferData ( gl . ARRAY_BUFFER , this . attribute_data . length * 4 , gl . STREAM_DRAW ) ;
114
156
}
115
157
116
158
this . onNativeSizeChanged = this . onNativeSizeChanged . bind ( this ) ;
@@ -203,8 +245,6 @@ class PenSkin extends Skin {
203
245
* Prepare to draw lines in the _lineOnBufferDrawRegionId region.
204
246
*/
205
247
_enterDrawLineOnBuffer ( ) {
206
- // tw: reset attributes when starting pen drawing
207
- this . _resetAttributeIndex ( ) ;
208
248
const gl = this . _renderer . gl ;
209
249
210
250
twgl . bindFramebufferInfo ( gl , this . _framebuffer ) ;
@@ -224,6 +264,8 @@ class PenSkin extends Skin {
224
264
gl . bindBuffer ( gl . ARRAY_BUFFER , this . a_position_glbuffer ) ;
225
265
gl . enableVertexAttribArray ( this . a_position_loc ) ;
226
266
gl . vertexAttribPointer ( this . a_position_loc , 2 , gl . FLOAT , false , 2 * 4 , 0 ) ;
267
+
268
+ this . attribute_index = 0 ;
227
269
}
228
270
229
271
/**
@@ -310,10 +352,11 @@ class PenSkin extends Skin {
310
352
_drawLineOnBuffer ( penAttributes , x0 , y0 , x1 , y1 ) {
311
353
this . _renderer . enterDrawRegion ( this . _lineOnBufferDrawRegionId ) ;
312
354
313
- // tw: flush if this line would overflow buffers
314
- // For some reason, looking up the size of a_lineColor with .length is very slow in some browsers.
315
- // We see measurable performance improvements by comparing to a constant instead.
316
- if ( this . attribute_index + PEN_ATTRIBUTE_STRIDE > PEN_ATTRIBUTE_BUFFER_SIZE ) {
355
+ const iters = this . instancedRendering ? 1 : 6 ;
356
+
357
+ // For some reason, looking up the size of a buffer through .length can be slow,
358
+ // so use a constant instead.
359
+ if ( this . attribute_index + ( PEN_ATTRIBUTE_STRIDE * iters ) > PEN_ATTRIBUTE_BUFFER_SIZE ) {
317
360
this . _flushLines ( ) ;
318
361
}
319
362
@@ -336,45 +379,40 @@ class PenSkin extends Skin {
336
379
337
380
// tw: apply renderQuality
338
381
const lineThickness = ( penAttributes . diameter || DefaultPenAttributes . diameter ) * this . renderQuality ;
339
- // tw: write pen draws to buffers where they will be flushed later
340
-
341
- // Premultiply pen color by pen transparency
342
- this . attribute_data [ this . attribute_index ] = penColor [ 0 ] * penColor [ 3 ] ;
343
- this . attribute_index ++ ;
344
- this . attribute_data [ this . attribute_index ] = penColor [ 1 ] * penColor [ 3 ] ;
345
- this . attribute_index ++ ;
346
- this . attribute_data [ this . attribute_index ] = penColor [ 2 ] * penColor [ 3 ] ;
347
- this . attribute_index ++ ;
348
- this . attribute_data [ this . attribute_index ] = penColor [ 3 ] ;
349
- this . attribute_index ++ ;
350
-
351
- this . attribute_data [ this . attribute_index ] = lineThickness ;
352
- this . attribute_index ++ ;
353
-
354
- this . attribute_data [ this . attribute_index ] = lineLength ;
355
- this . attribute_index ++ ;
356
-
357
- this . attribute_data [ this . attribute_index ] = x0 ;
358
- this . attribute_index ++ ;
359
- this . attribute_data [ this . attribute_index ] = - y0 ;
360
- this . attribute_index ++ ;
361
- this . attribute_data [ this . attribute_index ] = lineDiffX ;
362
- this . attribute_index ++ ;
363
- this . attribute_data [ this . attribute_index ] = - lineDiffY ;
364
- this . attribute_index ++ ;
365
- }
366
382
367
- // tw: resets indexes in the pen drawing buffers
368
- _resetAttributeIndex ( ) {
369
- this . attribute_index = 0 ;
383
+ for ( let i = 0 ; i < iters ; i ++ ) {
384
+ // Pen color sent to the GPU is pre-multiplied by transparency
385
+ this . attribute_data [ this . attribute_index ] = penColor [ 0 ] * penColor [ 3 ] ;
386
+ this . attribute_index ++ ;
387
+ this . attribute_data [ this . attribute_index ] = penColor [ 1 ] * penColor [ 3 ] ;
388
+ this . attribute_index ++ ;
389
+ this . attribute_data [ this . attribute_index ] = penColor [ 2 ] * penColor [ 3 ] ;
390
+ this . attribute_index ++ ;
391
+ this . attribute_data [ this . attribute_index ] = penColor [ 3 ] ;
392
+ this . attribute_index ++ ;
393
+
394
+ this . attribute_data [ this . attribute_index ] = lineThickness ;
395
+ this . attribute_index ++ ;
396
+
397
+ this . attribute_data [ this . attribute_index ] = lineLength ;
398
+ this . attribute_index ++ ;
399
+
400
+ this . attribute_data [ this . attribute_index ] = x0 ;
401
+ this . attribute_index ++ ;
402
+ this . attribute_data [ this . attribute_index ] = - y0 ;
403
+ this . attribute_index ++ ;
404
+ this . attribute_data [ this . attribute_index ] = lineDiffX ;
405
+ this . attribute_index ++ ;
406
+ this . attribute_data [ this . attribute_index ] = - lineDiffY ;
407
+ this . attribute_index ++ ;
408
+ }
370
409
}
371
410
372
- // tw: flushes buffered pen lines to the GPU
373
411
_flushLines ( ) {
374
412
/** @type {WebGLRenderingContext } */
375
413
const gl = this . _renderer . gl ;
376
414
377
- gl . bindBuffer ( gl . ARRAY_BUFFER , this . attribute_buffer ) ;
415
+ gl . bindBuffer ( gl . ARRAY_BUFFER , this . attribute_glbuffer ) ;
378
416
gl . bufferSubData ( gl . ARRAY_BUFFER , 0 , new Float32Array ( this . attribute_data . buffer , 0 , this . attribute_index ) ) ;
379
417
380
418
gl . enableVertexAttribArray ( this . a_lineColor_loc ) ;
@@ -398,39 +436,25 @@ class PenSkin extends Skin {
398
436
PEN_ATTRIBUTE_STRIDE_BYTES , 6 * 4
399
437
) ;
400
438
401
- if ( this . instanced_arrays_ext ) {
402
- // ANGLE_instanced_arrays fallback
403
- this . instanced_arrays_ext . vertexAttribDivisorANGLE ( this . a_lineColor_loc , 1 ) ;
404
- this . instanced_arrays_ext . vertexAttribDivisorANGLE ( this . a_lineThicknessAndLength_loc , 1 ) ;
405
- this . instanced_arrays_ext . vertexAttribDivisorANGLE ( this . a_penPoints_loc , 1 ) ;
406
-
407
- this . instanced_arrays_ext . drawArraysInstancedANGLE (
439
+ if ( this . instancedRendering ) {
440
+ this . glVertexAttribDivisor ( this . a_lineColor_loc , 1 ) ;
441
+ this . glVertexAttribDivisor ( this . a_lineThicknessAndLength_loc , 1 ) ;
442
+ this . glVertexAttribDivisor ( this . a_penPoints_loc , 1 ) ;
443
+
444
+ this . glDrawArraysInstanced (
408
445
gl . TRIANGLES ,
409
446
0 , 6 ,
410
447
this . attribute_index / PEN_ATTRIBUTE_STRIDE
411
448
) ;
412
-
413
- this . instanced_arrays_ext . vertexAttribDivisorANGLE ( this . a_lineColor_loc , 0 ) ;
414
- this . instanced_arrays_ext . vertexAttribDivisorANGLE ( this . a_lineThicknessAndLength_loc , 0 ) ;
415
- this . instanced_arrays_ext . vertexAttribDivisorANGLE ( this . a_penPoints_loc , 0 ) ;
449
+
450
+ this . glVertexAttribDivisor ( this . a_lineColor_loc , 0 ) ;
451
+ this . glVertexAttribDivisor ( this . a_lineThicknessAndLength_loc , 0 ) ;
452
+ this . glVertexAttribDivisor ( this . a_penPoints_loc , 0 ) ;
416
453
} else {
417
- gl . vertexAttribDivisor ( this . a_lineColor_loc , 1 ) ;
418
- gl . vertexAttribDivisor ( this . a_lineThicknessAndLength_loc , 1 ) ;
419
- gl . vertexAttribDivisor ( this . a_penPoints_loc , 1 ) ;
420
-
421
- gl . drawArraysInstanced (
422
- gl . TRIANGLES ,
423
- 0 , 6 ,
424
- this . attribute_index / PEN_ATTRIBUTE_STRIDE
425
- ) ;
426
-
427
- gl . vertexAttribDivisor ( this . a_lineColor_loc , 0 ) ;
428
- gl . vertexAttribDivisor ( this . a_lineThicknessAndLength_loc , 0 ) ;
429
- gl . vertexAttribDivisor ( this . a_penPoints_loc , 0 ) ;
454
+ gl . drawArrays ( gl . TRIANGLES , 0 , this . attribute_index / PEN_ATTRIBUTE_STRIDE ) ;
430
455
}
431
456
432
- this . _resetAttributeIndex ( ) ;
433
-
457
+ this . attribute_index = 0 ;
434
458
this . _silhouetteDirty = true ;
435
459
}
436
460
0 commit comments