littlejsengine 1.13.4 → 1.14.2

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.
Files changed (53) hide show
  1. package/README.md +2 -1
  2. package/copyToGithub.bat +28 -0
  3. package/dist/littlejs.d.ts +346 -240
  4. package/dist/littlejs.esm.js +1370 -723
  5. package/dist/littlejs.esm.min.js +1 -1
  6. package/dist/littlejs.js +1350 -709
  7. package/dist/littlejs.min.js +1 -1
  8. package/dist/littlejs.release.js +1333 -692
  9. package/examples/box2d/game.js +1 -1
  10. package/examples/box2d/gameObjects.js +1 -1
  11. package/examples/breakout/game.js +30 -25
  12. package/examples/electron/index.html +2 -2
  13. package/examples/index.html +207 -96
  14. package/examples/platformer/gameEffects.js +19 -18
  15. package/examples/platformer/gameLevel.js +6 -1
  16. package/examples/shorts/base.html +1 -1
  17. package/examples/shorts/flappyGame.js +2 -1
  18. package/examples/shorts/helloWorld.js +1 -1
  19. package/examples/shorts/music.js +106 -0
  20. package/examples/shorts/parallax.js +71 -0
  21. package/examples/shorts/piano.js +7 -8
  22. package/examples/shorts/postProcess.js +25 -8
  23. package/examples/shorts/shapes.js +1 -9
  24. package/examples/shorts/song.mp3 +0 -0
  25. package/examples/shorts/uiSystem.js +15 -8
  26. package/examples/starter/index.html +2 -2
  27. package/examples/stress/index.html +8 -3
  28. package/examples/style.css +14 -4
  29. package/examples/uiSystem/game.js +11 -11
  30. package/package.json +1 -1
  31. package/plugins/box2d.js +10 -8
  32. package/plugins/drawUtilities.js +5 -5
  33. package/plugins/newgrounds.js +6 -6
  34. package/plugins/pluginExport.js +1 -1
  35. package/plugins/uiSystem.js +103 -79
  36. package/plugins/zzfxm.js +10 -10
  37. package/reference.md +90 -54
  38. package/src/engine.js +22 -22
  39. package/src/engineAudio.js +284 -109
  40. package/src/engineBuild.js +9 -9
  41. package/src/engineDebug.js +26 -26
  42. package/src/engineDraw.js +148 -97
  43. package/src/engineExport.js +22 -16
  44. package/src/engineInput.js +57 -67
  45. package/src/engineMedals.js +25 -25
  46. package/src/engineObject.js +25 -22
  47. package/src/engineParticles.js +59 -59
  48. package/src/engineRelease.js +1 -1
  49. package/src/engineSettings.js +20 -13
  50. package/src/engineTileLayer.js +34 -34
  51. package/src/engineUtilities.js +62 -55
  52. package/src/engineWebGL.js +447 -65
  53. /package/examples/shorts/{playSound.js → sound.js} +0 -0
package/src/engineDraw.js CHANGED
@@ -1,21 +1,21 @@
1
- /**
1
+ /**
2
2
  * LittleJS Drawing System
3
3
  * - Hybrid system with both Canvas2D and WebGL available
4
4
  * - Super fast tile sheet rendering with WebGL
5
5
  * - Can apply rotation, mirror, color and additive color
6
6
  * - Font rendering system with built in engine font
7
7
  * - Many useful utility functions
8
- *
8
+ *
9
9
  * LittleJS uses a hybrid rendering solution with the best of both Canvas2D and WebGL.
10
10
  * There are 3 canvas/contexts available to draw to...
11
11
  * mainCanvas - 2D background canvas, non WebGL stuff like tile layers are drawn here.
12
12
  * glCanvas - Used by the accelerated WebGL batch rendering system.
13
13
  * overlayCanvas - Another 2D canvas that appears on top of the other 2 canvases.
14
- *
14
+ *
15
15
  * The WebGL rendering system is very fast with some caveats...
16
16
  * - Switching blend modes (additive) or textures causes another draw call which is expensive in excess
17
17
  * - Group additive rendering together using renderOrder to mitigate this issue
18
- *
18
+ *
19
19
  * The LittleJS rendering solution is intentionally simple, feel free to adjust it for your needs!
20
20
  * @namespace Draw
21
21
  */
@@ -62,7 +62,7 @@ let workCanvas;
62
62
  * @memberof Draw */
63
63
  let workContext;
64
64
 
65
- /** The size of the main canvas (and other secondary canvases)
65
+ /** The size of the main canvas (and other secondary canvases)
66
66
  * @type {Vector2}
67
67
  * @memberof Draw */
68
68
  let mainCanvasSize = vec2();
@@ -77,7 +77,7 @@ let drawCount;
77
77
 
78
78
  ///////////////////////////////////////////////////////////////////////////////
79
79
 
80
- /**
80
+ /**
81
81
  * Create a tile info object using a grid based system
82
82
  * - This can take vecs or floats for easier use and conversion
83
83
  * - If an index is passed in, the tile size and index will determine the position
@@ -91,15 +91,14 @@ let drawCount;
91
91
  * tile(5, 8) // a tile at index 5 using a tile size of 8
92
92
  * tile(1, 16, 3) // a tile at index 1 of size 16 on texture 3
93
93
  * tile(vec2(4,8), vec2(30,10)) // a tile at index (4,8) with a size of (30,10)
94
- * @memberof Draw
95
- */
94
+ * @memberof Draw */
96
95
  function tile(pos=new Vector2, size=tileSizeDefault, textureIndex=0, padding=0)
97
96
  {
98
97
  if (headlessMode)
99
98
  return new TileInfo;
100
99
 
101
100
  // if size is a number, make it a vector
102
- if (typeof size == 'number')
101
+ if (typeof size === 'number')
103
102
  {
104
103
  ASSERT(size > 0);
105
104
  size = new Vector2(size, size);
@@ -108,24 +107,24 @@ function tile(pos=new Vector2, size=tileSizeDefault, textureIndex=0, padding=0)
108
107
  // create tile info object
109
108
  const tileInfo = new TileInfo(new Vector2, size, textureIndex, padding);
110
109
 
111
- // use get the pos of the tile
110
+ // get the position of the tile
112
111
  const textureInfo = textureInfos[textureIndex];
113
112
  ASSERT(!!textureInfo, 'Texture not loaded');
114
113
  const sizePaddedX = size.x + padding*2;
115
114
  const sizePaddedY = size.y + padding*2;
116
- if (typeof pos == 'number')
115
+ if (typeof pos === 'number')
117
116
  {
118
117
  const cols = textureInfo.size.x / sizePaddedX |0;
119
- ASSERT(cols>0, 'Tile size is too big for texture');
118
+ ASSERT(cols > 0, 'Tile size is too big for texture');
120
119
  const posX = pos % cols, posY = (pos / cols) |0;
121
120
  tileInfo.pos.set(posX*sizePaddedX+padding, posY*sizePaddedY+padding);
122
121
  }
123
122
  else
124
123
  tileInfo.pos.set(pos.x*sizePaddedX+padding, pos.y*sizePaddedY+padding);
125
- return tileInfo;
124
+ return tileInfo;
126
125
  }
127
126
 
128
- /**
127
+ /**
129
128
  * Tile Info - Stores info about how to draw a tile
130
129
  */
131
130
  class TileInfo
@@ -163,14 +162,14 @@ class TileInfo
163
162
  */
164
163
  frame(frame)
165
164
  {
166
- ASSERT(typeof frame == 'number');
165
+ ASSERT(typeof frame === 'number');
167
166
  return this.offset(new Vector2(frame*(this.size.x+this.padding*2), 0));
168
167
  }
169
168
 
170
169
  /**
171
170
  * Set this tile to use a full image
172
171
  * @param {HTMLImageElement|OffscreenCanvas} image
173
- * @param {WebGLTexture} [glTexture] - webgl texture
172
+ * @param {WebGLTexture} [glTexture] - WebGL texture
174
173
  * @return {TileInfo}
175
174
  */
176
175
  setFullImage(image, glTexture)
@@ -188,7 +187,7 @@ class TextureInfo
188
187
  /**
189
188
  * Create a TextureInfo, called automatically by the engine
190
189
  * @param {HTMLImageElement|OffscreenCanvas} image
191
- * @param {WebGLTexture} [glTexture] - webgl texture
190
+ * @param {WebGLTexture} [glTexture] - WebGL texture
192
191
  */
193
192
  constructor(image, glTexture)
194
193
  {
@@ -198,7 +197,7 @@ class TextureInfo
198
197
  this.size = vec2(image.width, image.height);
199
198
  /** @property {Vector2} - inverse of the size, cached for rendering */
200
199
  this.sizeInverse = vec2(1/image.width, 1/image.height);
201
- /** @property {WebGLTexture} - webgl texture */
200
+ /** @property {WebGLTexture} - WebGL texture */
202
201
  this.glTexture = glTexture;
203
202
  }
204
203
 
@@ -214,28 +213,25 @@ class TextureInfo
214
213
  // Drawing functions
215
214
 
216
215
  /** Draw textured tile centered in world space, with color applied if using WebGL
217
- * @param {Vector2} pos - Center of the tile in world space
218
- * @param {Vector2} [size=(1,1)] - Size of the tile in world space
219
- * @param {TileInfo}[tileInfo] - Tile info to use, untextured if undefined
220
- * @param {Color} [color=(1,1,1,1)] - Color to modulate with
221
- * @param {number} [angle] - Angle to rotate by
222
- * @param {boolean} [mirror] - If true image is flipped along the Y axis
223
- * @param {Color} [additiveColor] - Additive color to be applied if any
224
- * @param {boolean} [useWebGL=glEnable] - Use accelerated WebGL rendering
225
- * @param {boolean} [screenSpace=false] - If true the pos and size are in screen space
216
+ * @param {Vector2} pos - Center of the tile in world space
217
+ * @param {Vector2} [size=(1,1)] - Size of the tile in world space
218
+ * @param {TileInfo} [tileInfo] - Tile info to use, untextured if undefined
219
+ * @param {Color} [color=(1,1,1,1)] - Color to modulate with
220
+ * @param {number} [angle] - Angle to rotate by
221
+ * @param {boolean} [mirror] - Is image flipped along the Y axis?
222
+ * @param {Color} [additiveColor] - Additive color to be applied if any
223
+ * @param {boolean} [useWebGL=glEnable] - Use accelerated WebGL rendering?
224
+ * @param {boolean} [screenSpace=false] - Are the pos and size are in screen space?
226
225
  * @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} [context] - Canvas 2D context to draw to
227
226
  * @memberof Draw */
228
- function drawTile(pos, size=new Vector2(1), tileInfo, color=new Color,
227
+ function drawTile(pos, size=new Vector2(1), tileInfo, color=WHITE,
229
228
  angle=0, mirror, additiveColor, useWebGL=glEnable, screenSpace, context)
230
229
  {
231
- ASSERT(!context || !useWebGL, 'context only supported in canvas 2D mode');
232
230
  ASSERT(isVector2(pos) && pos.isValid(), 'drawTile pos should be a vec2');
233
231
  ASSERT(isVector2(size) && size.isValid(), 'drawTile size should be a vec2');
234
232
  ASSERT(isColor(color) && (!additiveColor || isColor(additiveColor)), 'drawTile color is invalid');
235
233
  ASSERT(isNumber(angle), 'drawTile angle should be a number');
236
-
237
- if (color.a <= 0 && (!additiveColor || additiveColor.a <= 0) || !size.x || !size.y)
238
- return; // completely invisible, skip render
234
+ ASSERT(!context || !useWebGL, 'context only supported in canvas 2D mode');
239
235
 
240
236
  const textureInfo = tileInfo && tileInfo.textureInfo;
241
237
  if (useWebGL)
@@ -259,22 +255,22 @@ function drawTile(pos, size=new Vector2(1), tileInfo, color=new Color,
259
255
  {
260
256
  const tileImageFixBleedX = sizeInverse.x*tileFixBleedScale;
261
257
  const tileImageFixBleedY = sizeInverse.y*tileFixBleedScale;
262
- glDraw(pos.x, pos.y, mirror ? -size.x : size.x, size.y, angle,
263
- x + tileImageFixBleedX, y + tileImageFixBleedY,
264
- x - tileImageFixBleedX + w, y - tileImageFixBleedY + h,
265
- color.rgbaInt(), additiveColor && additiveColor.rgbaInt());
258
+ glDraw(pos.x, pos.y, mirror ? -size.x : size.x, size.y, angle,
259
+ x + tileImageFixBleedX, y + tileImageFixBleedY,
260
+ x - tileImageFixBleedX + w, y - tileImageFixBleedY + h,
261
+ color.rgbaInt(), additiveColor && additiveColor.rgbaInt());
266
262
  }
267
263
  else
268
264
  {
269
- glDraw(pos.x, pos.y, mirror ? -size.x : size.x, size.y, angle,
270
- x, y, x + w, y + h,
271
- color.rgbaInt(), additiveColor && additiveColor.rgbaInt());
265
+ glDraw(pos.x, pos.y, mirror ? -size.x : size.x, size.y, angle,
266
+ x, y, x + w, y + h,
267
+ color.rgbaInt(), additiveColor && additiveColor.rgbaInt());
272
268
  }
273
269
  }
274
270
  else
275
271
  {
276
272
  // if no tile info, force untextured
277
- glDraw(pos.x, pos.y, size.x, size.y, angle, 0, 0, 0, 0, 0, color.rgbaInt());
273
+ glDraw(pos.x, pos.y, size.x, size.y, angle, 0, 0, 0, 0, 0, color.rgbaInt());
278
274
  }
279
275
  }
280
276
  else
@@ -312,8 +308,8 @@ function drawTile(pos, size=new Vector2(1), tileInfo, color=new Color,
312
308
  * @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} [context]
313
309
  * @memberof Draw */
314
310
  function drawRect(pos, size, color, angle, useWebGL, screenSpace, context)
315
- {
316
- drawTile(pos, size, undefined, color, angle, false, undefined, useWebGL, screenSpace, context);
311
+ {
312
+ drawTile(pos, size, undefined, color, angle, false, undefined, useWebGL, screenSpace, context);
317
313
  }
318
314
 
319
315
  /** Draw colored line between two points
@@ -336,6 +332,30 @@ function drawLine(posA, posB, thickness=.1, color, pos=vec2(), angle=0, useWebGL
336
332
  drawRect(pos, size, color, angle, useWebGL, screenSpace, context);
337
333
  }
338
334
 
335
+ /** Draw colored regular polygon using passed in number of sides
336
+ * @param {Vector2} pos
337
+ * @param {Vector2} [size=(1,1)]
338
+ * @param {number} [sides]
339
+ * @param {Color} [color=(1,1,1,1)]
340
+ * @param {number} [angle]
341
+ * @param {number} [lineWidth]
342
+ * @param {Color} [lineColor=(0,0,0,1)]
343
+ * @param {boolean} [useWebGL=glEnable]
344
+ * @param {boolean} [screenSpace]
345
+ * @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} [context]
346
+ * @memberof Draw */
347
+ function drawRegularPoly(pos, size=vec2(1), sides=3, color=WHITE, lineWidth=0, lineColor=BLACK, angle=0, useWebGL=glEnable, screenSpace=false, context)
348
+ {
349
+ // build regular polygon points
350
+ const points = [];
351
+ for (let i=sides; i--;)
352
+ {
353
+ const a = (i/sides)*PI*2;
354
+ points.push(vec2(Math.sin(a)*size.x, Math.cos(a)*size.y));
355
+ }
356
+ drawPoly(points, color, lineWidth, lineColor, pos, angle, useWebGL, screenSpace, context);
357
+ }
358
+
339
359
  /** Draw colored polygon using passed in points
340
360
  * @param {Array<Vector2>} points - Array of Vector2 points
341
361
  * @param {Color} [color=(1,1,1,1)]
@@ -343,33 +363,49 @@ function drawLine(posA, posB, thickness=.1, color, pos=vec2(), angle=0, useWebGL
343
363
  * @param {Color} [lineColor=(0,0,0,1)]
344
364
  * @param {Vector2} [pos=(0,0)] - Offset to apply
345
365
  * @param {number} [angle] - Angle to rotate by
346
- * @param {boolean} [useWebGL] - Webgl not supported
366
+ * @param {boolean} [useWebGL=glEnable]
347
367
  * @param {boolean} [screenSpace]
348
- * @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} [context=drawContext]
368
+ * @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} [context]
349
369
  * @memberof Draw */
350
- function drawPoly(points, color=new Color, lineWidth=0, lineColor=BLACK, pos=vec2(), angle=0, useWebGL=false, screenSpace=false, context=drawContext)
370
+ function drawPoly(points, color=WHITE, lineWidth=0, lineColor=BLACK, pos=vec2(), angle=0, useWebGL=glEnable, screenSpace=false, context=undefined)
351
371
  {
352
372
  ASSERT(isVector2(pos) && pos.isValid(), 'drawPoly pos should be a vec2');
353
373
  ASSERT(Array.isArray(points), 'drawPoly points should be an array');
354
374
  ASSERT(isColor(color) && isColor(lineColor), 'drawPoly color is invalid');
355
375
  ASSERT(isNumber(lineWidth), 'drawPoly lineWidth should be a number');
356
376
  ASSERT(isNumber(angle), 'drawPoly angle should be a number');
357
- ASSERT(!useWebGL, 'drawPoly webgl not supported');
358
- drawCanvas2D(pos, vec2(1), angle, false, context=>
377
+ ASSERT(!context || !useWebGL, 'context only supported in canvas 2D mode');
378
+ if (useWebGL)
359
379
  {
360
- context.beginPath();
361
- for (const point of points)
362
- context.lineTo(point.x, point.y);
363
- context.closePath();
364
- context.fillStyle = color.toString();
365
- context.fill();
366
- if (lineWidth)
380
+ let scale = 1;
381
+ if (screenSpace)
367
382
  {
368
- context.strokeStyle = lineColor.toString();
369
- context.lineWidth = lineWidth;
370
- context.stroke();
383
+ // convert to world space
384
+ pos = screenToWorld(pos);
385
+ scale = 1/cameraScale;
371
386
  }
372
- }, screenSpace, context);
387
+ glDrawPointsTransform(points, color.rgbaInt(), pos.x, pos.y, scale, scale, angle);
388
+ if (lineWidth > 0)
389
+ glDrawOutlineTransform(points, lineColor.rgbaInt(), lineWidth, pos.x, pos.y, scale, scale, angle);
390
+ }
391
+ else
392
+ {
393
+ drawCanvas2D(pos, vec2(1), angle, false, context=>
394
+ {
395
+ context.fillStyle = color.toString();
396
+ context.beginPath();
397
+ for (const point of points)
398
+ context.lineTo(point.x, point.y);
399
+ context.closePath();
400
+ context.fill();
401
+ if (lineWidth)
402
+ {
403
+ context.strokeStyle = lineColor.toString();
404
+ context.lineWidth = lineWidth;
405
+ context.stroke();
406
+ }
407
+ }, screenSpace, context);
408
+ }
373
409
  }
374
410
 
375
411
  /** Draw colored ellipse using passed in point
@@ -379,32 +415,41 @@ function drawPoly(points, color=new Color, lineWidth=0, lineColor=BLACK, pos=vec
379
415
  * @param {number} [angle]
380
416
  * @param {number} [lineWidth]
381
417
  * @param {Color} [lineColor=(0,0,0,1)]
382
- * @param {boolean} [useWebGL] - Webgl not supported
418
+ * @param {boolean} [useWebGL=glEnable]
383
419
  * @param {boolean} [screenSpace]
384
- * @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} [context=drawContext]
420
+ * @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} [context]
385
421
  * @memberof Draw */
386
- function drawEllipse(pos, size=vec2(1), color=new Color, angle=0, lineWidth=0, lineColor=BLACK, useWebGL=false, screenSpace=false, context=drawContext)
422
+ function drawEllipse(pos, size=vec2(1), color=WHITE, angle=0, lineWidth=0, lineColor=BLACK, useWebGL=glEnable, screenSpace=false, context)
387
423
  {
388
424
  ASSERT(isVector2(pos) && pos.isValid(), 'drawEllipse pos should be a vec2');
389
425
  ASSERT(isVector2(size) && size.isValid(), 'drawEllipse size should be a vec2');
390
426
  ASSERT(isColor(color) && isColor(lineColor), 'drawEllipse color is invalid');
391
427
  ASSERT(isNumber(angle), 'drawEllipse angle should be a number');
392
428
  ASSERT(isNumber(lineWidth), 'drawEllipse lineWidth should be a number');
393
- ASSERT(lineWidth>=0 && lineWidth < size.x && lineWidth < size.y, 'drawEllipse invalid lineWidth');
394
- ASSERT(!useWebGL, 'drawEllipse webgl not supported');
395
- drawCanvas2D(pos, vec2(1), angle, false, context=>
429
+ ASSERT(lineWidth >= 0 && lineWidth < size.x && lineWidth < size.y, 'drawEllipse invalid lineWidth');
430
+ ASSERT(!context || !useWebGL, 'context only supported in canvas 2D mode');
431
+ if (useWebGL)
396
432
  {
397
- context.beginPath();
398
- context.ellipse(0, 0, size.y, size.x, 0, 0, 9);
399
- context.fillStyle = color.toString();
400
- context.fill();
401
- if (lineWidth)
433
+ // draw as a regular polygon
434
+ const sides = glCircleSides;
435
+ drawRegularPoly(pos, size, sides, color, lineWidth, lineColor, angle, useWebGL, screenSpace, context);
436
+ }
437
+ else
438
+ {
439
+ drawCanvas2D(pos, vec2(1), angle, false, context=>
402
440
  {
403
- context.strokeStyle = lineColor.toString();
404
- context.lineWidth = lineWidth;
405
- context.stroke();
406
- }
407
- }, screenSpace, context);
441
+ context.fillStyle = color.toString();
442
+ context.beginPath();
443
+ context.ellipse(0, 0, size.x, size.y, 0, 0, 9);
444
+ context.fill();
445
+ if (lineWidth)
446
+ {
447
+ context.strokeStyle = lineColor.toString();
448
+ context.lineWidth = lineWidth;
449
+ context.stroke();
450
+ }
451
+ }, screenSpace, context);
452
+ }
408
453
  }
409
454
 
410
455
  /** Draw colored circle using passed in point
@@ -413,11 +458,11 @@ function drawEllipse(pos, size=vec2(1), color=new Color, angle=0, lineWidth=0, l
413
458
  * @param {Color} [color=(1,1,1,1)]
414
459
  * @param {number} [lineWidth=0]
415
460
  * @param {Color} [lineColor=(0,0,0,1)]
416
- * @param {boolean} [useWebGL] - Webgl not supported
417
- * @param {boolean} [screenSpace=false]
418
- * @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} [context=drawContext]
461
+ * @param {boolean} [useWebGL=glEnable]
462
+ * @param {boolean} [screenSpace]
463
+ * @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} [context]
419
464
  * @memberof Draw */
420
- function drawCircle(pos, radius=1, color=new Color, lineWidth=0, lineColor=BLACK, useWebGL=false, screenSpace, context=drawContext)
465
+ function drawCircle(pos, radius=1, color=WHITE, lineWidth=0, lineColor=BLACK, useWebGL=glEnable, screenSpace=false, context)
421
466
  { drawEllipse(pos, vec2(radius), color, 0, lineWidth, lineColor, useWebGL, screenSpace, context); }
422
467
 
423
468
  /** Draw directly to a 2d canvas context in world space
@@ -426,7 +471,7 @@ function drawCircle(pos, radius=1, color=new Color, lineWidth=0, lineColor=BLACK
426
471
  * @param {number} angle
427
472
  * @param {boolean} [mirror]
428
473
  * @param {Function} [drawFunction]
429
- * @param {boolean} [screenSpace=false]
474
+ * @param {boolean} [screenSpace=false]
430
475
  * @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} [context=drawContext]
431
476
  * @memberof Draw */
432
477
  function drawCanvas2D(pos, size, angle=0, mirror=false, drawFunction, screenSpace=false, context=drawContext)
@@ -496,7 +541,7 @@ function drawTextOverlay(text, pos, size=1, color, lineWidth=0, lineColor, textA
496
541
  * @param {number} [maxWidth]
497
542
  * @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} [context=overlayContext]
498
543
  * @memberof Draw */
499
- function drawTextScreen(text, pos, size=1, color=new Color, lineWidth=0, lineColor=BLACK, textAlign='center', font=fontDefault, maxWidth=undefined, context=overlayContext)
544
+ function drawTextScreen(text, pos, size=1, color=WHITE, lineWidth=0, lineColor=BLACK, textAlign='center', font=fontDefault, maxWidth, context=overlayContext)
500
545
  {
501
546
  context.fillStyle = color.toString();
502
547
  context.strokeStyle = lineColor.toString();
@@ -528,7 +573,7 @@ function screenToWorld(screenPos)
528
573
  {
529
574
  let cameraPosRelativeX = (screenPos.x - mainCanvasSize.x/2 + .5) / cameraScale;
530
575
  let cameraPosRelativeY = (screenPos.y - mainCanvasSize.y/2 + .5) / -cameraScale;
531
- if (cameraAngle)
576
+ if (cameraAngle)
532
577
  {
533
578
  // apply camera rotation
534
579
  const cos = Math.cos(-cameraAngle), sin = Math.sin(-cameraAngle);
@@ -621,7 +666,7 @@ function drawImageColor(context, image, sx, sy, sWidth, sHeight, dx, dy, dWidth,
621
666
  {
622
667
  // white texture with no additive alpha, no need to tint
623
668
  context.globalAlpha = color.a;
624
- context.drawImage(image, sx+sx2, sy+sy2, sWidth2, sHeight2, dx, dy, dWidth, dHeight);
669
+ context.drawImage(image, sx+sx2, sy+sy2, sWidth2, sHeight2, dx, dy, dWidth, dHeight);
625
670
  context.globalAlpha = 1;
626
671
  }
627
672
  else
@@ -642,7 +687,7 @@ function drawImageColor(context, image, sx, sy, sWidth, sHeight, dx, dy, dWidth,
642
687
  for (let i = 0; i < data.length; ++i)
643
688
  data[i] = data[i] * colorMultiply[i&3] + colorAdd[i&3] |0;
644
689
  workContext.putImageData(imageData, 0, 0);
645
- context.drawImage(workCanvas, sx2, sy2, sWidth2, sHeight2, dx, dy, dWidth, dHeight);
690
+ context.drawImage(workCanvas, sx2, sy2, sWidth2, sHeight2, dx, dy, dWidth, dHeight);
646
691
  }
647
692
  else
648
693
  {
@@ -655,7 +700,7 @@ function drawImageColor(context, image, sx, sy, sWidth, sHeight, dx, dy, dWidth,
655
700
  }
656
701
  workContext.putImageData(imageData, 0, 0);
657
702
  context.globalAlpha = color.a;
658
- context.drawImage(workCanvas, sx2, sy2, sWidth2, sHeight2, dx, dy, dWidth, dHeight);
703
+ context.drawImage(workCanvas, sx2, sy2, sWidth2, sHeight2, dx, dy, dWidth, dHeight);
659
704
  context.globalAlpha = 1;
660
705
  }
661
706
  }
@@ -682,7 +727,7 @@ function toggleFullscreen()
682
727
  }
683
728
 
684
729
  /** Set the cursor style
685
- * @param {string} cursorStyle - CSS cursor style (auto, none, crosshair, etc)
730
+ * @param {string} [cursorStyle] - CSS cursor style (auto, none, crosshair, etc)
686
731
  * @memberof Draw */
687
732
  function setCursor(cursorStyle = 'auto')
688
733
  {
@@ -694,7 +739,7 @@ function setCursor(cursorStyle = 'auto')
694
739
 
695
740
  let engineFontImage;
696
741
 
697
- /**
742
+ /**
698
743
  * Font Image Object - Draw text on a 2D canvas by using characters in an image
699
744
  * - 96 characters (from space to tilde) are stored in an image
700
745
  * - Uses a default 8x8 font if none is supplied
@@ -702,7 +747,7 @@ let engineFontImage;
702
747
  * @example
703
748
  * // use built in font
704
749
  * const font = new FontImage;
705
- *
750
+ *
706
751
  * // draw text
707
752
  * font.drawTextScreen("LittleJS\nHello World!", vec2(200, 50));
708
753
  */
@@ -712,7 +757,6 @@ class FontImage
712
757
  * @param {HTMLImageElement} [image] - Image for the font, if undefined default font is used
713
758
  * @param {Vector2} [tileSize=(8,8)] - Size of the font source tiles
714
759
  * @param {Vector2} [paddingSize=(0,1)] - How much extra space to add between characters
715
- * @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} [context=overlayContext] - context to draw to
716
760
  */
717
761
  constructor(image, tileSize=vec2(8), paddingSize=vec2(0,1), context=overlayContext)
718
762
  {
@@ -726,7 +770,6 @@ class FontImage
726
770
  this.image = image || engineFontImage;
727
771
  this.tileSize = tileSize;
728
772
  this.paddingSize = paddingSize;
729
- this.context = context;
730
773
  }
731
774
 
732
775
  /** Draw text in world space using the image font
@@ -734,23 +777,32 @@ class FontImage
734
777
  * @param {Vector2} pos
735
778
  * @param {number} [scale=.25]
736
779
  * @param {boolean} [center]
780
+ * @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D}[context=drawContext]
737
781
  */
738
- drawText(text, pos, scale=1, center)
782
+ drawText(text, pos, scale=1, center, context=drawContext)
739
783
  {
740
- this.drawTextScreen(text, worldToScreen(pos).floor(), scale*cameraScale|0, center);
784
+ this.drawTextScreen(text, worldToScreen(pos).floor(), scale*cameraScale|0, center, context);
741
785
  }
742
786
 
743
- /** Draw text in screen space using the image font
787
+ /** Draw text on overlay canvas in world space using the image font
788
+ * @param {string} text
789
+ * @param {Vector2} pos
790
+ * @param {number} [scale]
791
+ * @param {boolean} [center]
792
+ */
793
+ drawTextOverlay(text, pos, scale=4, center)
794
+ { this.drawText(text, pos, scale, center, overlayContext); }
795
+
796
+ /** Draw text on overlay canvas in screen space using the image font
744
797
  * @param {string} text
745
798
  * @param {Vector2} pos
746
799
  * @param {number} [scale]
747
800
  * @param {boolean} [center]
801
+ * @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} [context=drawContext]
748
802
  */
749
- drawTextScreen(text, pos, scale=4, center)
803
+ drawTextScreen(text, pos, scale=4, center, context=overlayContext)
750
804
  {
751
- const context = this.context;
752
805
  context.save();
753
-
754
806
  const size = this.tileSize;
755
807
  const drawSize = size.add(this.paddingSize).scale(scale);
756
808
  const cols = this.image.width / this.tileSize.x |0;
@@ -769,11 +821,10 @@ class FontImage
769
821
  const x = tile % cols;
770
822
  const y = tile / cols |0;
771
823
  const drawPos = pos.add(vec2(j,i).multiply(drawSize));
772
- context.drawImage(this.image, x * size.x, y * size.y, size.x, size.y,
824
+ context.drawImage(this.image, x * size.x, y * size.y, size.x, size.y,
773
825
  drawPos.x - centerOffset, drawPos.y, size.x * scale, size.y * scale);
774
826
  }
775
827
  });
776
-
777
828
  context.restore();
778
829
  }
779
830
  }
@@ -225,27 +225,32 @@ export
225
225
  // WebGL
226
226
  glCanvas,
227
227
  glContext,
228
+ glClearCanvas,
229
+ glSetTexture,
228
230
  glCompileShader,
229
- glCopyToContext,
230
231
  glCreateProgram,
231
232
  glCreateTexture,
232
233
  glDeleteTexture,
233
234
  glSetTextureData,
234
- glDraw,
235
235
  glFlush,
236
- glSetTexture,
236
+ glCopyToContext,
237
237
  glSetAntialias,
238
- glClearCanvas,
238
+ glDraw,
239
+ glDrawPointsTransform,
240
+ glDrawOutlineTransform,
241
+ glDrawPoints,
239
242
  glAntialias,
240
- glShader,
241
- glActiveTexture,
242
- glArrayBuffer,
243
- glGeometryBuffer,
244
- glPositionData,
245
- glColorData,
246
- glInstanceCount,
247
- glAdditive,
243
+ glShader,
244
+ glPolyShader,
245
+ glPolyMode,
246
+ glAdditive,
248
247
  glBatchAdditive,
248
+ glActiveTexture,
249
+ glArrayBuffer,
250
+ glGeometryBuffer,
251
+ glPositionData,
252
+ glColorData,
253
+ glBatchCount,
249
254
 
250
255
  // Input
251
256
  keyIsDown,
@@ -278,17 +283,18 @@ export
278
283
  pointerLockIsActive,
279
284
 
280
285
  // Audio
286
+ audioContext,
287
+ audioMasterGain,
288
+ audioDefaultSampleRate,
281
289
  Sound,
282
290
  SoundWave,
283
- playAudioFile,
291
+ SoundInstance,
284
292
  speak,
285
293
  speakStop,
286
294
  getNoteFrequency,
287
295
  playSamples,
288
296
  zzfx,
289
297
  zzfxG,
290
- zzfxR,
291
- audioContext,
292
298
 
293
299
  // Base Object
294
300
  EngineObject,
@@ -313,4 +319,4 @@ export
313
319
  medalsPreventUnlock,
314
320
  medalsInit,
315
321
  Medal,
316
- };
322
+ }