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/dist/littlejs.d.ts +55 -32
- package/dist/littlejs.esm.js +393 -227
- package/dist/littlejs.esm.min.js +1 -1
- package/dist/littlejs.js +393 -227
- package/dist/littlejs.min.js +1 -1
- package/dist/littlejs.release.js +393 -227
- package/examples/box2d/game.js +3 -2
- package/examples/box2d/tiles.png +0 -0
- package/examples/breakout/game.js +5 -5
- package/examples/electron/game.js +2 -2
- package/examples/electron/index.html +2 -2
- package/examples/index.html +57 -49
- package/examples/module/game.js +2 -2
- package/examples/platformer/gameEffects.js +1 -1
- package/examples/shorts/base.html +1 -1
- package/examples/shorts/musicPlayer.js +1 -0
- package/examples/shorts/parallax.js +1 -1
- package/examples/shorts/sequencer.js +2 -2
- package/examples/shorts/shader.js +29 -0
- package/examples/shorts/tileLayer.js +1 -1
- package/examples/shorts/tiltedView.js +14 -6
- package/examples/shorts/topDown.js +1 -1
- package/examples/starter/game.js +2 -2
- package/examples/starter/index.html +2 -2
- package/examples/style.css +1 -0
- package/examples/typescript/game.js +2 -2
- package/examples/typescript/game.ts +1 -1
- package/examples/uiSystem/game.js +1 -0
- package/package.json +1 -1
- package/plugins/postProcess.js +71 -51
- package/plugins/uiSystem.js +76 -23
- package/src/engine.js +28 -14
- package/src/engineAudio.js +20 -10
- package/src/engineDraw.js +35 -29
- package/src/engineParticles.js +1 -1
- package/src/engineTileLayer.js +31 -39
- package/src/engineWebGL.js +134 -63
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 {
|
|
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(
|
|
180
|
+
setFullImage(textureInfo)
|
|
182
181
|
{
|
|
183
182
|
this.pos = new Vector2;
|
|
184
|
-
this.size =
|
|
185
|
-
this.textureInfo =
|
|
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 {
|
|
200
|
+
* @param {boolean} [useWebGL] - Should use WebGL if available?
|
|
202
201
|
*/
|
|
203
|
-
constructor(image,
|
|
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 =
|
|
211
|
+
this.glTexture = undefined;
|
|
212
|
+
useWebGL && this.createWebGLTexture();
|
|
213
213
|
}
|
|
214
214
|
|
|
215
|
-
|
|
216
|
-
{
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
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]
|
|
916
|
-
* @param {Vector2} [tileSize=(8,8)]
|
|
917
|
-
* @param {Vector2} [paddingSize=(0,1)] - How much
|
|
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)
|
|
925
|
+
constructor(image, tileSize=vec2(8), paddingSize=vec2(0,1))
|
|
920
926
|
{
|
|
921
927
|
// load default font image
|
|
922
928
|
if (!engineFontImage)
|
package/src/engineParticles.js
CHANGED
|
@@ -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
|
-
*
|
|
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
|
* );
|
package/src/engineTileLayer.js
CHANGED
|
@@ -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 =
|
|
201
|
-
/** @property {
|
|
202
|
-
|
|
203
|
-
this.
|
|
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
|
-
|
|
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.
|
|
238
|
-
const tileInfo = new TileInfo().setFullImage(this.
|
|
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 (
|
|
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.
|
|
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
|
|
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
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
this.
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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
|
|
506
|
+
constructor(position, size, tileInfo=tile(), renderOrder=0)
|
|
515
507
|
{
|
|
516
|
-
super(position, size.floor(), tileInfo, renderOrder
|
|
508
|
+
super(position, size.floor(), tileInfo, renderOrder);
|
|
517
509
|
|
|
518
510
|
/** @property {Array<number>} - The tile collision grid */
|
|
519
511
|
this.collisionData = [];
|
package/src/engineWebGL.js
CHANGED
|
@@ -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
|
|
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
|
-
|
|
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
|
|
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()
|