littlejsengine 1.14.16 → 1.14.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/engineDraw.js CHANGED
@@ -173,16 +173,15 @@ class TileInfo
173
173
  }
174
174
 
175
175
  /**
176
- * Set this tile to use a full image
177
- * @param {HTMLImageElement|OffscreenCanvas} image
178
- * @param {WebGLTexture} [glTexture] - WebGL texture
176
+ * Set this tile to use a full image in a texture info
177
+ * @param {TextureInfo} textureInfo
179
178
  * @return {TileInfo}
180
179
  */
181
- setFullImage(image, glTexture)
180
+ setFullImage(textureInfo)
182
181
  {
183
182
  this.pos = new Vector2;
184
- this.size = new Vector2(image.width, image.height);
185
- this.textureInfo = new TextureInfo(image, glTexture);
183
+ this.size = textureInfo.size.copy();
184
+ this.textureInfo = textureInfo;
186
185
  // do not use padding or bleed
187
186
  this.bleedScale = this.padding = 0;
188
187
  return this;
@@ -198,26 +197,30 @@ class TextureInfo
198
197
  /**
199
198
  * Create a TextureInfo, called automatically by the engine
200
199
  * @param {HTMLImageElement|OffscreenCanvas} image
201
- * @param {WebGLTexture} [glTexture] - WebGL texture
200
+ * @param {boolean} [useWebGL] - Should use WebGL if available?
202
201
  */
203
- constructor(image, glTexture)
202
+ constructor(image, useWebGL=true)
204
203
  {
205
- /** @property {HTMLImageElement} - image source */
204
+ /** @property {HTMLImageElement|OffscreenCanvas} - image source */
206
205
  this.image = image;
207
206
  /** @property {Vector2} - size of the image */
208
- this.size = vec2(image.width, image.height);
207
+ this.size = image ? vec2(image.width, image.height) : vec2();
209
208
  /** @property {Vector2} - inverse of the size, cached for rendering */
210
- this.sizeInverse = vec2(1/image.width, 1/image.height);
209
+ this.sizeInverse = image ? vec2(1/image.width, 1/image.height) : vec2();
211
210
  /** @property {WebGLTexture} - WebGL texture */
212
- this.glTexture = glTexture;
211
+ this.glTexture = undefined;
212
+ useWebGL && this.createWebGLTexture();
213
213
  }
214
214
 
215
- createWebGLTexture()
216
- {
217
- ASSERT(!this.glTexture);
218
- if (glEnable)
219
- this.glTexture = glCreateTexture(this.image);
220
- }
215
+ /** Creates the WebGL texture, updates if already created */
216
+ createWebGLTexture() { glRegisterTextureInfo(this); }
217
+
218
+ /** Destroys the WebGL texture */
219
+ destroyWebGLTexture() { glUnregisterTextureInfo(this); }
220
+
221
+ /** Check if the texture is webgl enabled
222
+ * @return {boolean} */
223
+ hasWebGL() { return !!this.glTexture; }
221
224
  }
222
225
 
223
226
  ///////////////////////////////////////////////////////////////////////////////
@@ -650,12 +653,13 @@ function drawCanvas2D(pos, size, angle=0, mirror=false, drawFunction, screenSpac
650
653
  * @param {Color} [lineColor=(0,0,0,1)]
651
654
  * @param {CanvasTextAlign} [textAlign='center']
652
655
  * @param {string} [font=fontDefault]
656
+ * @param {string} [fontStyle]
653
657
  * @param {number} [maxWidth]
654
658
  * @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} [context=drawContext]
655
659
  * @memberof Draw */
656
- function drawText(text, pos, size=1, color, lineWidth=0, lineColor, textAlign, font, maxWidth, context=drawContext)
660
+ function drawText(text, pos, size=1, color, lineWidth=0, lineColor, textAlign, font, fontStyle, maxWidth, context=drawContext)
657
661
  {
658
- drawTextScreen(text, worldToScreen(pos), size*cameraScale, color, lineWidth*cameraScale, lineColor, textAlign, font, maxWidth, context);
662
+ drawTextScreen(text, worldToScreen(pos), size*cameraScale, color, lineWidth*cameraScale, lineColor, textAlign, font, fontStyle, maxWidth, context);
659
663
  }
660
664
 
661
665
  /** Draw text on overlay canvas in world space
@@ -668,11 +672,12 @@ function drawText(text, pos, size=1, color, lineWidth=0, lineColor, textAlign, f
668
672
  * @param {Color} [lineColor=(0,0,0,1)]
669
673
  * @param {CanvasTextAlign} [textAlign='center']
670
674
  * @param {string} [font=fontDefault]
675
+ * @param {string} [fontStyle]
671
676
  * @param {number} [maxWidth]
672
677
  * @memberof Draw */
673
- function drawTextOverlay(text, pos, size=1, color, lineWidth=0, lineColor, textAlign, font, maxWidth)
678
+ function drawTextOverlay(text, pos, size=1, color, lineWidth=0, lineColor, textAlign, font, fontStyle, maxWidth)
674
679
  {
675
- drawText(text, pos, size, color, lineWidth, lineColor, textAlign, font, maxWidth, overlayContext);
680
+ drawText(text, pos, size, color, lineWidth, lineColor, textAlign, font, fontStyle, maxWidth, overlayContext);
676
681
  }
677
682
 
678
683
  /** Draw text on overlay canvas in screen space
@@ -685,10 +690,11 @@ function drawTextOverlay(text, pos, size=1, color, lineWidth=0, lineColor, textA
685
690
  * @param {Color} [lineColor=(0,0,0,1)]
686
691
  * @param {CanvasTextAlign} [textAlign]
687
692
  * @param {string} [font=fontDefault]
693
+ * @param {string} [fontStyle]
688
694
  * @param {number} [maxWidth]
689
695
  * @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} [context=overlayContext]
690
696
  * @memberof Draw */
691
- function drawTextScreen(text, pos, size=1, color=WHITE, lineWidth=0, lineColor=BLACK, textAlign='center', font=fontDefault, maxWidth, context=overlayContext)
697
+ function drawTextScreen(text, pos, size=1, color=WHITE, lineWidth=0, lineColor=BLACK, textAlign='center', font=fontDefault, fontStyle='', maxWidth, context=overlayContext)
692
698
  {
693
699
  ASSERT(isString(text), 'text must be a string');
694
700
  ASSERT(isVector2(pos), 'pos must be a vec2');
@@ -696,15 +702,15 @@ function drawTextScreen(text, pos, size=1, color=WHITE, lineWidth=0, lineColor=B
696
702
  ASSERT(isColor(color), 'color must be a color');
697
703
  ASSERT(isNumber(lineWidth), 'lineWidth must be a number');
698
704
  ASSERT(isColor(lineColor), 'lineColor must be a color');
699
- ASSERT(isColor(lineColor), 'lineColor must be a color');
700
705
  ASSERT(['left','center','right'].includes(textAlign), 'align must be left, center, or right');
701
706
  ASSERT(isString(font), 'font must be a string');
707
+ ASSERT(isString(fontStyle), 'fontStyle must be a string');
702
708
 
703
709
  context.fillStyle = color.toString();
704
710
  context.strokeStyle = lineColor.toString();
705
711
  context.lineWidth = lineWidth;
706
712
  context.textAlign = textAlign;
707
- context.font = size + 'px '+ font;
713
+ context.font = fontStyle + ' ' + size + 'px '+ font;
708
714
  context.textBaseline = 'middle';
709
715
 
710
716
  const lines = (text+'').split('\n');
@@ -912,11 +918,11 @@ let engineFontImage;
912
918
  class FontImage
913
919
  {
914
920
  /** Create an image font
915
- * @param {HTMLImageElement} [image] - Image for the font, if undefined default font is used
916
- * @param {Vector2} [tileSize=(8,8)] - Size of the font source tiles
917
- * @param {Vector2} [paddingSize=(0,1)] - How much extra space to add between characters
921
+ * @param {HTMLImageElement} [image] - Image for the font, default if undefined
922
+ * @param {Vector2} [tileSize=(8,8)] - Size of the font source tiles
923
+ * @param {Vector2} [paddingSize=(0,1)] - How much space between characters
918
924
  */
919
- constructor(image, tileSize=vec2(8), paddingSize=vec2(0,1), context=overlayContext)
925
+ constructor(image, tileSize=vec2(8), paddingSize=vec2(0,1))
920
926
  {
921
927
  // load default font image
922
928
  if (!engineFontImage)
@@ -23,7 +23,7 @@
23
23
  * tile(0, 16), // tileInfo
24
24
  * rgb(1,1,1,1), rgb(0,0,0,1), // colorStartA, colorStartB
25
25
  * rgb(1,1,1,0), rgb(0,0,0,0), // colorEndA, colorEndB
26
- * 2, .2, .2, .1, .05, // particleTime, sizeStart, sizeEnd, particleSpeed, particleAngleSpeed
26
+ * 1, .2, .2, .1, .05, // particleTime, sizeStart, sizeEnd, particleSpeed, particleAngleSpeed
27
27
  * .99, 1, 1, PI, .05, // damping, angleDamping, gravityScale, particleCone, fadeRate,
28
28
  * .5, 1 // randomness, collide, additive, randomColorLinear, renderOrder
29
29
  * );
@@ -197,10 +197,13 @@ class CanvasLayer extends EngineObject
197
197
  /** @property {HTMLCanvasElement} - The canvas used by this layer */
198
198
  this.canvas = headlessMode ? undefined : new OffscreenCanvas(canvasSize.x, canvasSize.y);
199
199
  /** @property {OffscreenCanvasRenderingContext2D} - The 2D canvas context used by this layer */
200
- this.context = headlessMode ? undefined : this.canvas.getContext('2d');
201
- /** @property {WebGLTexture} - Texture if using WebGL for this layer, call useWebGL to enable */
202
- this.glTexture = undefined;
203
- this.gravityScale = 0; // disable gravity by default for canvas layers
200
+ this.context = this.canvas?.getContext('2d');
201
+ /** @property {TextureInfo} - Texture info to use for this object rendering */
202
+ const useWebGL = false; // do not use webgl by default
203
+ this.textureInfo = new TextureInfo(this.canvas, useWebGL);
204
+
205
+ // disable physics by default
206
+ this.mass = this.gravityScale = this.friction = this.restitution = 0;
204
207
  }
205
208
 
206
209
  /** Destroy this canvas layer */
@@ -209,9 +212,7 @@ class CanvasLayer extends EngineObject
209
212
  if (this.destroyed)
210
213
  return;
211
214
 
212
- // free up the WebGL texture
213
- if (this.glTexture)
214
- glDeleteTexture(this.glTexture);
215
+ this.textureInfo.destroyWebGLTexture();
215
216
  super.destroy();
216
217
  }
217
218
 
@@ -234,8 +235,8 @@ class CanvasLayer extends EngineObject
234
235
  draw(pos, size, angle=0, color=WHITE, mirror=false, additiveColor, screenSpace=false, context)
235
236
  {
236
237
  // draw the canvas layer as a single tile that uses the whole texture
237
- const useWebGL = glEnable && this.glTexture !== undefined;
238
- const tileInfo = new TileInfo().setFullImage(this.canvas, this.glTexture);
238
+ const useWebGL = glEnable && this.textureInfo.hasWebGL();
239
+ const tileInfo = new TileInfo().setFullImage(this.textureInfo);
239
240
  drawTile(pos, size, tileInfo, color, angle, mirror, additiveColor, useWebGL, screenSpace, context);
240
241
  }
241
242
 
@@ -253,6 +254,8 @@ class CanvasLayer extends EngineObject
253
254
  * @param {Canvas2DDrawCallback} drawFunction */
254
255
  drawCanvas2D(pos, size, angle, mirror, drawFunction)
255
256
  {
257
+ if (!this.context) return;
258
+
256
259
  const context = this.context;
257
260
  context.save();
258
261
  pos = pos.subtract(this.pos).multiply(this.tileInfo.size);
@@ -305,15 +308,10 @@ class CanvasLayer extends EngineObject
305
308
  * @param {boolean} [enable] - enable WebGL rendering and update the texture */
306
309
  useWebGL(enable=true)
307
310
  {
308
- if (glEnable && enable)
309
- {
310
- if (this.glTexture)
311
- glSetTextureData(this.glTexture, this.canvas);
312
- else
313
- this.glTexture = glCreateTexture(this.canvas);
314
- }
311
+ if (enable)
312
+ this.textureInfo.createWebGLTexture();
315
313
  else
316
- this.glTexture = undefined;
314
+ this.textureInfo.destroyWebGLTexture();
317
315
  }
318
316
  }
319
317
 
@@ -337,24 +335,14 @@ class TileLayer extends CanvasLayer
337
335
  * @param {Vector2} size - World space size
338
336
  * @param {TileInfo} [tileInfo] - Default tile info for layer (used for size and texture)
339
337
  * @param {number} [renderOrder] - Objects are sorted by renderOrder
340
- * @param {boolean} [useWebGL=glEnable] - Use accelerated WebGL rendering
341
338
  */
342
- constructor(position, size, tileInfo=tile(), renderOrder=0, useWebGL=glEnable)
339
+ constructor(position, size, tileInfo=tile(), renderOrder=0)
343
340
  {
344
- super(position, size, 0, renderOrder, size);
345
-
346
- this.tileInfo = tileInfo;
347
341
  const canvasSize = size.multiply(tileInfo.size);
348
- /** @property {HTMLCanvasElement} - The canvas used by this tile layer */
349
- this.canvas = new OffscreenCanvas(canvasSize.x, canvasSize.y);
350
- /** @property {OffscreenCanvasRenderingContext2D} - The 2D canvas context used by this tile layer */
351
- this.context = this.canvas.getContext('2d');
352
- /** @property {WebGLTexture} - Texture if using WebGL for this layer */
353
- this.glTexture = useWebGL ? glCreateTexture(this.canvas) : undefined;
354
- // set no friction by default, applied friction is max of both objects
355
- this.friction = 0;
356
- // set no restitution by default, applied restitution is max of both objects
357
- this.restitution = 0;
342
+ super(position, size, 0, renderOrder, canvasSize);
343
+
344
+ // set tile info
345
+ this.tileInfo = tileInfo;
358
346
 
359
347
  // init tile data
360
348
  this.data = [];
@@ -404,10 +392,10 @@ class TileLayer extends CanvasLayer
404
392
  ASSERT(drawContext !== this.context, 'must call redrawEnd() after drawing tiles!');
405
393
 
406
394
  // draw the tile layer as a single tile
407
- const tileInfo = new TileInfo().setFullImage(this.canvas, this.glTexture);
395
+ const tileInfo = new TileInfo().setFullImage(this.textureInfo);
408
396
  const size = this.drawSize || this.size;
409
397
  const pos = this.pos.add(size.scale(.5));
410
- const useWebGL = glEnable && this.glTexture !== undefined;
398
+ const useWebGL = glEnable && this.textureInfo.hasWebGL();
411
399
  drawTile(pos, size, tileInfo, WHITE, 0, false, CLEAR_BLACK, useWebGL);
412
400
  }
413
401
 
@@ -420,8 +408,7 @@ class TileLayer extends CanvasLayer
420
408
  for (let y = this.size.y; y--;)
421
409
  this.drawTileData(vec2(x,y), false);
422
410
  this.redrawEnd();
423
- if (this.glTexture)
424
- this.useWebGL(); // update WebGL texture
411
+ this.useWebGL();
425
412
  }
426
413
 
427
414
  /** Call to start the redraw process
@@ -429,6 +416,8 @@ class TileLayer extends CanvasLayer
429
416
  * @param {boolean} [clear] - Should it clear the canvas before drawing */
430
417
  redrawStart(clear=false)
431
418
  {
419
+ if (!this.context) return;
420
+
432
421
  // save current render settings
433
422
  /** @type {[HTMLCanvasElement|OffscreenCanvas, CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D, Vector2, Vector2, number]} */
434
423
  this.savedRenderSettings = [drawCanvas, drawContext, mainCanvasSize, cameraPos, cameraScale];
@@ -457,6 +446,8 @@ class TileLayer extends CanvasLayer
457
446
  /** Call to end the redraw process */
458
447
  redrawEnd()
459
448
  {
449
+ if (!this.context) return;
450
+
460
451
  ASSERT(drawContext === this.context, 'must call redrawStart() before drawing tiles');
461
452
  glCopyToContext(drawContext);
462
453
  //debugSaveCanvas(this.canvas);
@@ -473,6 +464,8 @@ class TileLayer extends CanvasLayer
473
464
  */
474
465
  drawTileData(layerPos, clear=true)
475
466
  {
467
+ if (!this.context) return;
468
+
476
469
  // clear out where the tile was, for full opaque tiles this can be skipped
477
470
  const s = this.tileInfo.size;
478
471
  if (clear)
@@ -509,11 +502,10 @@ class TileCollisionLayer extends TileLayer
509
502
  * @param {Vector2} size - World space size
510
503
  * @param {TileInfo} [tileInfo] - Tile info for layer
511
504
  * @param {number} [renderOrder] - Objects are sorted by renderOrder
512
- * @param {boolean} [useWebGL=glEnable] - Use accelerated WebGL rendering
513
505
  */
514
- constructor(position, size, tileInfo=tile(), renderOrder=0, useWebGL=glEnable)
506
+ constructor(position, size, tileInfo=tile(), renderOrder=0)
515
507
  {
516
- super(position, size.floor(), tileInfo, renderOrder, useWebGL);
508
+ super(position, size.floor(), tileInfo, renderOrder);
517
509
 
518
510
  /** @property {Array<number>} - The tile collision grid */
519
511
  this.collisionData = [];
@@ -29,7 +29,7 @@ let glContext;
29
29
  let glAntialias = true;
30
30
 
31
31
  // WebGL internal variables not exposed to documentation
32
- let glShader, glPolyShader, glPolyMode, glAdditive, glBatchAdditive, glActiveTexture, glArrayBuffer, glGeometryBuffer, glPositionData, glColorData, glBatchCount;
32
+ let glShader, glPolyShader, glPolyMode, glAdditive, glBatchAdditive, glActiveTexture, glArrayBuffer, glGeometryBuffer, glPositionData, glColorData, glBatchCount, glTextureInfos;
33
33
 
34
34
  // WebGL internal constants
35
35
  const gl_ARRAY_BUFFER_SIZE = 5e5;
@@ -45,6 +45,9 @@ const gl_MAX_POLY_VERTEXES = gl_ARRAY_BUFFER_SIZE / gl_POLY_VERTEX_BYTE_STRIDE |
45
45
  // Initialize WebGL, called automatically by the engine
46
46
  function glInit()
47
47
  {
48
+ // keep set of texture infos so they can be restored if context is lost
49
+ glTextureInfos = new Set;
50
+
48
51
  if (!glEnable || headlessMode) return;
49
52
 
50
53
  // create the canvas and textures
@@ -62,68 +65,101 @@ function glInit()
62
65
  // create the WebGL canvas
63
66
  const rootElement = mainCanvas.parentElement;
64
67
  rootElement.appendChild(glCanvas);
68
+
69
+ // startup webgl
70
+ initWebGL();
65
71
 
66
- // setup instanced rendering shader program
67
- glShader = glCreateProgram(
68
- '#version 300 es\n' + // specify GLSL ES version
69
- 'precision highp float;'+ // use highp for better accuracy
70
- 'uniform mat4 m;'+ // transform matrix
71
- 'in vec2 g;'+ // in: geometry
72
- 'in vec4 p,u,c,a;'+ // in: position/size, uvs, color, additiveColor
73
- 'in float r;'+ // in: rotation
74
- 'out vec2 v;'+ // out: uv
75
- 'out vec4 d,e;'+ // out: color, additiveColor
76
- 'void main(){'+ // shader entry point
77
- 'vec2 s=(g-.5)*p.zw;'+ // get size offset
78
- 'gl_Position=m*vec4(p.xy+s*cos(r)-vec2(-s.y,s)*sin(r),1,1);'+ // transform position
79
- 'v=mix(u.xw,u.zy,g);'+ // pass uv to fragment shader
80
- 'd=c;e=a;'+ // pass colors to fragment shader
81
- '}' // end of shader
82
- ,
83
- '#version 300 es\n' + // specify GLSL ES version
84
- 'precision highp float;'+ // use highp for better accuracy
85
- 'uniform sampler2D s;'+ // texture
86
- 'in vec2 v;'+ // in: uv
87
- 'in vec4 d,e;'+ // in: color, additiveColor
88
- 'out vec4 c;'+ // out: color
89
- 'void main(){'+ // shader entry point
90
- 'c=texture(s,v)*d+e;'+ // modulate texture by color plus additive
91
- '}' // end of shader
92
- );
93
-
94
- // setup poly rendering shaders
95
- glPolyShader = glCreateProgram(
96
- '#version 300 es\n' + // specify GLSL ES version
97
- 'precision highp float;'+ // use highp for better accuracy
98
- 'uniform mat4 m;'+ // transform matrix
99
- 'in vec2 p;'+ // in: position
100
- 'in vec4 c;'+ // in: color
101
- 'out vec4 d;'+ // out: color
102
- 'void main(){'+ // shader entry point
103
- 'gl_Position=m*vec4(p,1,1);'+ // transform position
104
- 'd=c;'+ // pass color to fragment shader
105
- '}' // end of shader
106
- ,
107
- '#version 300 es\n' + // specify GLSL ES version
108
- 'precision highp float;'+ // use highp for better accuracy
109
- 'in vec4 d;'+ // in: color
110
- 'out vec4 c;'+ // out: color
111
- 'void main(){'+ // shader entry point
112
- 'c=d;'+ // set color
113
- '}' // end of shader
114
- );
115
-
116
- // init buffers
117
- const glInstanceData = new ArrayBuffer(gl_ARRAY_BUFFER_SIZE);
118
- glPositionData = new Float32Array(glInstanceData);
119
- glColorData = new Uint32Array(glInstanceData);
120
- glArrayBuffer = glContext.createBuffer();
121
- glGeometryBuffer = glContext.createBuffer();
122
-
123
- // create the geometry buffer, triangle strip square
124
- const geometry = new Float32Array([glBatchCount=0,0,1,0,0,1,1,1]);
125
- glContext.bindBuffer(glContext.ARRAY_BUFFER, glGeometryBuffer);
126
- glContext.bufferData(glContext.ARRAY_BUFFER, geometry, glContext.STATIC_DRAW);
72
+ // setup context lost and restore handlers
73
+ glCanvas.addEventListener('webglcontextlost', (e)=>
74
+ {
75
+ glEnable = false; // disable WebGL rendering
76
+ glCanvas.style.display = 'none'; // hide the gl canvas
77
+ e.preventDefault(); // prevent default to allow restoration
78
+ LOG('WebGL context lost! Switching to Canvas2d rendering.');
79
+
80
+ // remove WebGL textures
81
+ for (const info of glTextureInfos)
82
+ info.glTexture = undefined;
83
+ glActiveTexture = undefined;
84
+ pluginList.forEach(plugin=>plugin.glContextLost?.());
85
+ });
86
+ glCanvas.addEventListener('webglcontextrestored', ()=>
87
+ {
88
+ glEnable = true; // disable WebGL rendering
89
+ glCanvas.style.display = ''; // show the gl canvas
90
+ LOG('WebGL context restored, reinitializing...');
91
+
92
+ // reinit WebGL and restore textures
93
+ initWebGL();
94
+ for (const info of glTextureInfos)
95
+ info.glTexture = glCreateTexture(info.image);
96
+ pluginList.forEach(plugin=>plugin.glContextRestored?.());
97
+ });
98
+
99
+ function initWebGL()
100
+ {
101
+ // setup instanced rendering shader program
102
+ glShader = glCreateProgram(
103
+ '#version 300 es\n' + // specify GLSL ES version
104
+ 'precision highp float;'+ // use highp for better accuracy
105
+ 'uniform mat4 m;'+ // transform matrix
106
+ 'in vec2 g;'+ // in: geometry
107
+ 'in vec4 p,u,c,a;'+ // in: position/size, uvs, color, additiveColor
108
+ 'in float r;'+ // in: rotation
109
+ 'out vec2 v;'+ // out: uv
110
+ 'out vec4 d,e;'+ // out: color, additiveColor
111
+ 'void main(){'+ // shader entry point
112
+ 'vec2 s=(g-.5)*p.zw;'+ // get size offset
113
+ 'gl_Position=m*vec4(p.xy+s*cos(r)-vec2(-s.y,s)*sin(r),1,1);'+ // transform position
114
+ 'v=mix(u.xw,u.zy,g);'+ // pass uv to fragment shader
115
+ 'd=c;e=a;'+ // pass colors to fragment shader
116
+ '}' // end of shader
117
+ ,
118
+ '#version 300 es\n' + // specify GLSL ES version
119
+ 'precision highp float;'+ // use highp for better accuracy
120
+ 'uniform sampler2D s;'+ // texture
121
+ 'in vec2 v;'+ // in: uv
122
+ 'in vec4 d,e;'+ // in: color, additiveColor
123
+ 'out vec4 c;'+ // out: color
124
+ 'void main(){'+ // shader entry point
125
+ 'c=texture(s,v)*d+e;'+ // modulate texture by color plus additive
126
+ '}' // end of shader
127
+ );
128
+
129
+ // setup poly rendering shaders
130
+ glPolyShader = glCreateProgram(
131
+ '#version 300 es\n' + // specify GLSL ES version
132
+ 'precision highp float;'+ // use highp for better accuracy
133
+ 'uniform mat4 m;'+ // transform matrix
134
+ 'in vec2 p;'+ // in: position
135
+ 'in vec4 c;'+ // in: color
136
+ 'out vec4 d;'+ // out: color
137
+ 'void main(){'+ // shader entry point
138
+ 'gl_Position=m*vec4(p,1,1);'+ // transform position
139
+ 'd=c;'+ // pass color to fragment shader
140
+ '}' // end of shader
141
+ ,
142
+ '#version 300 es\n' + // specify GLSL ES version
143
+ 'precision highp float;'+ // use highp for better accuracy
144
+ 'in vec4 d;'+ // in: color
145
+ 'out vec4 c;'+ // out: color
146
+ 'void main(){'+ // shader entry point
147
+ 'c=d;'+ // set color
148
+ '}' // end of shader
149
+ );
150
+
151
+ // init buffers
152
+ const glInstanceData = new ArrayBuffer(gl_ARRAY_BUFFER_SIZE);
153
+ glPositionData = new Float32Array(glInstanceData);
154
+ glColorData = new Uint32Array(glInstanceData);
155
+ glArrayBuffer = glContext.createBuffer();
156
+ glGeometryBuffer = glContext.createBuffer();
157
+
158
+ // create the geometry buffer, triangle strip square
159
+ const geometry = new Float32Array([glBatchCount=0,0,1,0,0,1,1,1]);
160
+ glContext.bindBuffer(glContext.ARRAY_BUFFER, glGeometryBuffer);
161
+ glContext.bufferData(glContext.ARRAY_BUFFER, geometry, glContext.STATIC_DRAW);
162
+ }
127
163
  }
128
164
 
129
165
  function glSetInstancedMode()
@@ -230,7 +266,7 @@ function glPreRender()
230
266
  // start with additive blending off
231
267
  glAdditive = glBatchAdditive = false;
232
268
 
233
- // force it to enter instanced mode
269
+ // force it to set instanced mode by first setting poly mode true
234
270
  glPolyMode = true;
235
271
  glSetInstancedMode();
236
272
  }
@@ -371,6 +407,41 @@ function glSetTextureData(texture, image)
371
407
  glContext.bindTexture(glContext.TEXTURE_2D, glActiveTexture); // rebind active texture
372
408
  }
373
409
 
410
+ /** Tells WebGL to create or update the glTexture and start tracking it
411
+ * @param {TextureInfo} textureInfo
412
+ * @memberof WebGL */
413
+ function glRegisterTextureInfo(textureInfo)
414
+ {
415
+ if (headlessMode) return;
416
+
417
+ // add texture info to tracking list even if gl is not enabled
418
+ glTextureInfos.add(textureInfo);
419
+
420
+ if (!glContext) return;
421
+
422
+ // create or set the texture data
423
+ if (textureInfo.glTexture)
424
+ glSetTextureData(textureInfo.glTexture, textureInfo.image);
425
+ else
426
+ textureInfo.glTexture = glCreateTexture(textureInfo.image);
427
+ }
428
+
429
+ /** Tells WebGL to destroy the glTexture and stop tracking it
430
+ * @param {TextureInfo} textureInfo
431
+ * @memberof WebGL */
432
+ function glUnregisterTextureInfo(textureInfo)
433
+ {
434
+ if (headlessMode) return;
435
+
436
+ // delete texture info from tracking list even if gl is not enabled
437
+ glTextureInfos.delete(textureInfo);
438
+
439
+ // unset and destroy the texture
440
+ const glTexture = textureInfo.glTexture;
441
+ textureInfo.glTexture = undefined;
442
+ glDeleteTexture(glTexture);
443
+ }
444
+
374
445
  /** Draw all sprites and clear out the buffer, called automatically by the system whenever necessary
375
446
  * @memberof WebGL */
376
447
  function glFlush()