littlejsengine 1.11.2 → 1.11.5

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 (73) hide show
  1. package/.vscode/launch.json +14 -0
  2. package/README.md +16 -18
  3. package/dist/littlejs.d.ts +41 -30
  4. package/dist/littlejs.esm.js +165 -143
  5. package/dist/littlejs.esm.min.js +1 -1
  6. package/dist/littlejs.js +161 -142
  7. package/dist/littlejs.min.js +1 -1
  8. package/dist/littlejs.release.js +157 -135
  9. package/examples/box2d/gameObjects.js +4 -4
  10. package/examples/box2d/scenes.js +2 -2
  11. package/examples/breakout/game.js +1 -1
  12. package/examples/breakout/gameObjects.js +28 -29
  13. package/examples/breakout/index.html +1 -1
  14. package/examples/breakoutTutorial/game.js +1 -1
  15. package/examples/index.html +1 -7
  16. package/examples/logo.png +0 -0
  17. package/examples/module/game.js +1 -1
  18. package/examples/platformer/game.js +2 -2
  19. package/examples/platformer/gameCharacter.js +5 -5
  20. package/examples/platformer/gameEffects.js +4 -4
  21. package/examples/platformer/gameObjects.js +2 -2
  22. package/examples/puzzle/game.js +3 -3
  23. package/examples/starter/game.js +11 -45
  24. package/examples/starter/tiles.png +0 -0
  25. package/jsconfig.json +1 -0
  26. package/package.json +1 -1
  27. package/plugins/box2d.js +10 -10
  28. package/plugins/newgrounds.js +1 -1
  29. package/plugins/postProcess.js +8 -8
  30. package/shortExamples/base.html +36 -0
  31. package/shortExamples/code/blending.js +12 -0
  32. package/shortExamples/code/helloWorld.js +7 -0
  33. package/shortExamples/code/particles.js +28 -0
  34. package/shortExamples/code/playSound.js +36 -0
  35. package/shortExamples/code/pong.js +40 -0
  36. package/shortExamples/code/shapes.js +24 -0
  37. package/shortExamples/code/spriteAtlas.js +27 -0
  38. package/shortExamples/code/systemFont.js +14 -0
  39. package/shortExamples/code/texture.js +12 -0
  40. package/shortExamples/code/tileLayer.js +50 -0
  41. package/shortExamples/index.html +242 -0
  42. package/shortExamples/tiles.png +0 -0
  43. package/src/engine.js +17 -3
  44. package/src/engineAudio.js +4 -4
  45. package/src/engineBuild.js +2 -1
  46. package/src/engineDebug.js +4 -7
  47. package/src/engineDraw.js +50 -25
  48. package/src/engineExport.js +4 -1
  49. package/src/engineInput.js +1 -1
  50. package/src/engineObject.js +8 -8
  51. package/src/engineParticles.js +7 -7
  52. package/src/engineSettings.js +5 -5
  53. package/src/engineTileLayer.js +6 -2
  54. package/src/engineUtilities.js +5 -5
  55. package/src/engineWebGL.js +52 -74
  56. package/examples/electron/build.js +0 -107
  57. package/examples/electron/electron.js +0 -43
  58. package/examples/electron/game.js +0 -131
  59. package/examples/electron/index.html +0 -13
  60. package/examples/electron/package.json +0 -22
  61. package/examples/electron/tiles.png +0 -0
  62. package/examples/js13k/build.bat +0 -2
  63. package/examples/js13k/build.js +0 -131
  64. package/examples/js13k/game.js +0 -118
  65. package/examples/js13k/index.html +0 -21
  66. package/examples/js13k/tiles.png +0 -0
  67. package/examples/typescript/build.bat +0 -5
  68. package/examples/typescript/build.js +0 -33
  69. package/examples/typescript/game.js +0 -102
  70. package/examples/typescript/game.ts +0 -134
  71. package/examples/typescript/index.html +0 -10
  72. package/examples/typescript/tiles.png +0 -0
  73. package/examples/typescript/tsconfig.json +0 -8
package/src/engineDraw.js CHANGED
@@ -48,7 +48,7 @@ let overlayContext;
48
48
  let mainCanvasSize = vec2();
49
49
 
50
50
  /** Array containing texture info for batch rendering system
51
- * @type {Array}
51
+ * @type {Array<TextureInfo>}
52
52
  * @memberof Draw */
53
53
  let textureInfos = [];
54
54
 
@@ -87,11 +87,13 @@ function tile(pos=vec2(), size=tileSizeDefault, textureIndex=0, padding=0)
87
87
 
88
88
  // use pos as a tile index
89
89
  const textureInfo = textureInfos[textureIndex];
90
- ASSERT(textureInfo, 'Texture not loaded');
90
+ ASSERT(!!textureInfo, 'Texture not loaded');
91
91
  const sizePadded = size.add(vec2(padding*2));
92
- const cols = textureInfo.size.x / sizePadded.x |0;
93
92
  if (typeof pos === 'number')
94
- pos = vec2(pos%cols, pos/cols|0);
93
+ {
94
+ const cols = textureInfo.size.x / sizePadded.x |0;
95
+ pos = cols>0 ? vec2(pos%cols, pos/cols|0) : vec2();
96
+ }
95
97
  pos = vec2(pos.x*sizePadded.x+padding, pos.y*sizePadded.y+padding);
96
98
 
97
99
  // return a tile info object
@@ -397,24 +399,6 @@ function drawCanvas2D(pos, size, angle, mirror, drawFunction, screenSpace, conte
397
399
  context.restore();
398
400
  }
399
401
 
400
- /** Enable normal or additive blend mode
401
- * @param {Boolean} [additive]
402
- * @param {Boolean} [useWebGL=glEnable]
403
- * @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} [context=mainContext]
404
- * @memberof Draw */
405
- function setBlendMode(additive, useWebGL=glEnable, context)
406
- {
407
- ASSERT(!context || !useWebGL, 'context only supported in canvas 2D mode');
408
- if (useWebGL)
409
- glAdditive = additive;
410
- else
411
- {
412
- if (!context)
413
- context = mainContext;
414
- context.globalCompositeOperation = additive ? 'lighter' : 'source-over';
415
- }
416
- }
417
-
418
402
  /** Draw text on main canvas in world space
419
403
  * Automatically splits new lines into rows
420
404
  * @param {String} text
@@ -482,6 +466,38 @@ function drawTextScreen(text, pos, size=1, color=new Color, lineWidth=0, lineCol
482
466
  });
483
467
  }
484
468
 
469
+ /** Enable normal or additive blend mode
470
+ * @param {Boolean} [additive]
471
+ * @param {Boolean} [useWebGL=glEnable]
472
+ * @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} [context=mainContext]
473
+ * @memberof Draw */
474
+ function setBlendMode(additive, useWebGL=glEnable, context)
475
+ {
476
+ ASSERT(!context || !useWebGL, 'context only supported in canvas 2D mode');
477
+ if (useWebGL)
478
+ glAdditive = additive;
479
+ else
480
+ {
481
+ if (!context)
482
+ context = mainContext;
483
+ context.globalCompositeOperation = additive ? 'lighter' : 'source-over';
484
+ }
485
+ }
486
+
487
+ /** Combines all LittleJS canvases onto the main canvas and clears them
488
+ * This is necessary for things like saving a screenshot
489
+ * @memberof Draw */
490
+ function combineCanvases()
491
+ {
492
+ // combine canvases
493
+ glCopyToContext(mainContext, true);
494
+ mainContext.drawImage(overlayCanvas, 0, 0);
495
+
496
+ // clear canvases
497
+ glClearCanvas();
498
+ overlayCanvas.width |= 0;
499
+ }
500
+
485
501
  ///////////////////////////////////////////////////////////////////////////////
486
502
 
487
503
  let engineFontImage;
@@ -493,7 +509,7 @@ let engineFontImage;
493
509
  * - You can also use fonts from the main tile sheet
494
510
  * @example
495
511
  * // use built in font
496
- * const font = new ImageFont;
512
+ * const font = new FontImage;
497
513
  *
498
514
  * // draw text
499
515
  * font.drawTextScreen("LittleJS\nHello World!", vec2(200, 50));
@@ -568,14 +584,14 @@ class FontImage
568
584
  }
569
585
 
570
586
  ///////////////////////////////////////////////////////////////////////////////
571
- // Fullscreen mode
587
+ // Display functions
572
588
 
573
589
  /** Returns true if fullscreen mode is active
574
590
  * @return {Boolean}
575
591
  * @memberof Draw */
576
592
  function isFullscreen() { return !!document.fullscreenElement; }
577
593
 
578
- /** Toggle fullsceen mode
594
+ /** Toggle fullscreen mode
579
595
  * @memberof Draw */
580
596
  function toggleFullscreen()
581
597
  {
@@ -587,4 +603,13 @@ function toggleFullscreen()
587
603
  }
588
604
  else if (rootElement.requestFullscreen)
589
605
  rootElement.requestFullscreen();
606
+ }
607
+
608
+ /** Set the cursor style
609
+ * @param {String} cursorStyle - CSS cursor style (auto, none, crosshair, etc)
610
+ * @memberof Draw */
611
+ function setCursor(cursorStyle = 'auto')
612
+ {
613
+ const rootElement = mainCanvas.parentElement;
614
+ rootElement.style.cursor = cursorStyle;
590
615
  }
@@ -197,14 +197,16 @@ export {
197
197
  drawEllipse,
198
198
  drawCircle,
199
199
  drawCanvas2D,
200
- setBlendMode,
201
200
  drawText,
202
201
  drawTextOverlay,
203
202
  drawTextScreen,
203
+ setBlendMode,
204
+ combineCanvases,
204
205
  engineFontImage,
205
206
  FontImage,
206
207
  isFullscreen,
207
208
  toggleFullscreen,
209
+ setCursor,
208
210
  getCameraSize,
209
211
 
210
212
  // WebGL
@@ -218,6 +220,7 @@ export {
218
220
  glFlush,
219
221
  glSetTexture,
220
222
  glSetAntialias,
223
+ glClearCanvas,
221
224
  glAntialias,
222
225
  glShader,
223
226
  glActiveTexture,
@@ -341,7 +341,7 @@ function vibrateStop() { vibrate(0); }
341
341
 
342
342
  /** True if a touch device has been detected
343
343
  * @memberof Input */
344
- const isTouchDevice = window.ontouchstart !== undefined;
344
+ const isTouchDevice = !headlessMode && window.ontouchstart !== undefined;
345
345
 
346
346
  // touch gamepad internal variables
347
347
  let touchGamepadTimer = new Timer, touchGamepadButtons, touchGamepadStick;
@@ -155,7 +155,7 @@ class EngineObject
155
155
  const oldPos = this.pos.copy();
156
156
  this.velocity.x *= this.damping;
157
157
  this.velocity.y *= this.damping;
158
- if (this.mass) // dont apply gravity to static objects
158
+ if (this.mass) // don't apply gravity to static objects
159
159
  this.velocity.y += gravity * this.gravityScale;
160
160
  this.pos.x += this.velocity.x;
161
161
  this.pos.y += this.velocity.y;
@@ -164,7 +164,7 @@ class EngineObject
164
164
  // physics sanity checks
165
165
  ASSERT(this.angleDamping >= 0 && this.angleDamping <= 1);
166
166
  ASSERT(this.damping >= 0 && this.damping <= 1);
167
- if (!enablePhysicsSolver || !this.mass) // dont do collision for static objects
167
+ if (!enablePhysicsSolver || !this.mass) // don't do collision for static objects
168
168
  return;
169
169
 
170
170
  const wasMovingDown = this.velocity.y < 0;
@@ -183,7 +183,7 @@ class EngineObject
183
183
  const epsilon = .001; // necessary to push slightly outside of the collision
184
184
  for (const o of engineObjectsCollide)
185
185
  {
186
- // non solid objects don't collide with eachother
186
+ // non solid objects don't collide with each other
187
187
  if (!this.isSolid && !o.isSolid || o.destroyed || o.parent || o == this)
188
188
  continue;
189
189
 
@@ -243,7 +243,7 @@ class EngineObject
243
243
  const elastic1 = o.velocity.y * (o.mass - this.mass) / (this.mass + o.mass)
244
244
  + this.velocity.y * 2 * this.mass / (this.mass + o.mass);
245
245
 
246
- // lerp betwen elastic or inelastic based on elasticity
246
+ // lerp between elastic or inelastic based on elasticity
247
247
  this.velocity.y = lerp(elasticity, inelastic, elastic0);
248
248
  o.velocity.y = lerp(elasticity, inelastic, elastic1);
249
249
  }
@@ -263,7 +263,7 @@ class EngineObject
263
263
  const elastic1 = o.velocity.x * (o.mass - this.mass) / (this.mass + o.mass)
264
264
  + this.velocity.x * 2 * this.mass / (this.mass + o.mass);
265
265
 
266
- // lerp betwen elastic or inelastic based on elasticity
266
+ // lerp between elastic or inelastic based on elasticity
267
267
  this.velocity.x = lerp(elasticity, inelastic, elastic0);
268
268
  o.velocity.x = lerp(elasticity, inelastic, elastic1);
269
269
  }
@@ -329,7 +329,7 @@ class EngineObject
329
329
  if (this.destroyed)
330
330
  return;
331
331
 
332
- // disconnect from parent and destroy chidren
332
+ // disconnect from parent and destroy children
333
333
  this.destroyed = 1;
334
334
  this.parent && this.parent.removeChild(this);
335
335
  for (const child of this.children)
@@ -354,7 +354,7 @@ class EngineObject
354
354
 
355
355
  /** Called to check if a tile collision should be resolved
356
356
  * @param {Number} tileData - the value of the tile at the position
357
- * @param {Vector2} pos - tile where the collision occured
357
+ * @param {Vector2} pos - tile where the collision occurred
358
358
  * @return {Boolean} - true if the collision should be resolved */
359
359
  collideWithTile(tileData, pos) { return tileData > 0; }
360
360
 
@@ -417,7 +417,7 @@ class EngineObject
417
417
  this.collideRaycast = collideRaycast;
418
418
  }
419
419
 
420
- /** Returns string containg info about this object for debugging
420
+ /** Returns string containing info about this object for debugging
421
421
  * @return {String} */
422
422
  toString()
423
423
  {
@@ -12,7 +12,7 @@
12
12
  * let pos = vec2(2,3);
13
13
  * let particleEmitter = new ParticleEmitter
14
14
  * (
15
- * pos, 0, 1, 0, 500, PI, // pos, angle, emitSize, emitTime, emitRate, emiteCone
15
+ * pos, 0, 1, 0, 500, PI, // pos, angle, emitSize, emitTime, emitRate, emitCone
16
16
  * tile(0, 16), // tileInfo
17
17
  * rgb(1,1,1), rgb(0,0,0), // colorStartA, colorStartB
18
18
  * rgb(1,1,1,0), rgb(0,0,0,0), // colorEndA, colorEndB
@@ -47,7 +47,7 @@ class ParticleEmitter extends EngineObject
47
47
  * @param {Number} [fadeRate] - How quick to fade particles at start/end in percent of life
48
48
  * @param {Number} [randomness] - Apply extra randomness percent
49
49
  * @param {Boolean} [collideTiles] - Do particles collide against tiles
50
- * @param {Boolean} [additive] - Should particles use addtive blend
50
+ * @param {Boolean} [additive] - Should particles use additive blend
51
51
  * @param {Boolean} [randomColorLinear] - Should color be randomized linearly or across each component
52
52
  * @param {Number} [renderOrder] - Render order for particles (additive is above other stuff by default)
53
53
  * @param {Boolean} [localSpace] - Should it be in local space of emitter (world space is default)
@@ -132,11 +132,11 @@ class ParticleEmitter extends EngineObject
132
132
  this.randomness = randomness;
133
133
  /** @property {Boolean} - Do particles collide against tiles */
134
134
  this.collideTiles = collideTiles;
135
- /** @property {Boolean} - Should particles use addtive blend */
135
+ /** @property {Boolean} - Should particles use additive blend */
136
136
  this.additive = additive;
137
137
  /** @property {Boolean} - Should it be in local space of emitter */
138
138
  this.localSpace = localSpace;
139
- /** @property {Number} - If non zero the partile is drawn as a trail, stretched in the drection of velocity */
139
+ /** @property {Number} - If non zero the particle is drawn as a trail, stretched in the direction of velocity */
140
140
  this.trailScale = 0;
141
141
  /** @property {Function} - Callback when particle is destroyed */
142
142
  this.particleDestroyCallback = undefined;
@@ -185,7 +185,7 @@ class ParticleEmitter extends EngineObject
185
185
  angle += this.angle;
186
186
  }
187
187
 
188
- // randomness scales each paremeter by a percentage
188
+ // randomness scales each parameter by a percentage
189
189
  const randomness = this.randomness;
190
190
  const randomizeScale = (v)=> v + v*rand(randomness, -randomness);
191
191
 
@@ -214,7 +214,7 @@ class ParticleEmitter extends EngineObject
214
214
  particle.renderOrder = this.renderOrder;
215
215
  particle.mirror = !!randInt(2);
216
216
 
217
- // call particle create callaback
217
+ // call particle create callback
218
218
  this.particleCreateCallback && this.particleCreateCallback(particle);
219
219
 
220
220
  // return the newly created particle
@@ -283,7 +283,7 @@ class Particle extends EngineObject
283
283
  render()
284
284
  {
285
285
  // modulate size and color
286
- const p = min((time - this.spawnTime) / this.lifeTime, 1);
286
+ const p = this.lifeTime > 0 ? min((time - this.spawnTime) / this.lifeTime, 1) : 1;
287
287
  const radius = this.sizeStart + p * this.sizeEndDelta;
288
288
  const size = vec2(radius);
289
289
  const fadeRate = this.fadeRate/2;
@@ -106,7 +106,7 @@ let tileFixBleedScale = 0;
106
106
  * @memberof Settings */
107
107
  let enablePhysicsSolver = true;
108
108
 
109
- /** Default object mass for collision calcuations (how heavy objects are)
109
+ /** Default object mass for collision calculations (how heavy objects are)
110
110
  * @type {Number}
111
111
  * @default
112
112
  * @memberof Settings */
@@ -317,7 +317,7 @@ function setFontDefault(font) { fontDefault = font; }
317
317
  * @memberof Settings */
318
318
  function setShowSplashScreen(show) { showSplashScreen = show; }
319
319
 
320
- /** Set to disalbe rendering, audio, and input for servers
320
+ /** Set to disable rendering, audio, and input for servers
321
321
  * @param {Boolean} headless
322
322
  * @memberof Settings */
323
323
  function setHeadlessMode(headless) { headlessMode = headless; }
@@ -347,7 +347,7 @@ function setTileFixBleedScale(scale) { tileFixBleedScale = scale; }
347
347
  * @memberof Settings */
348
348
  function setEnablePhysicsSolver(enable) { enablePhysicsSolver = enable; }
349
349
 
350
- /** Set default object mass for collison calcuations
350
+ /** Set default object mass for collision calculations
351
351
  * @param {Number} mass
352
352
  * @memberof Settings */
353
353
  function setObjectDefaultMass(mass) { objectDefaultMass = mass; }
@@ -417,7 +417,7 @@ function setTouchGamepadEnable(enable) { touchGamepadEnable = enable; }
417
417
  * @memberof Settings */
418
418
  function setTouchGamepadAnalog(analog) { touchGamepadAnalog = analog; }
419
419
 
420
- /** Set size of virutal gamepad for touch devices in pixels
420
+ /** Set size of virtual gamepad for touch devices in pixels
421
421
  * @param {Number} size
422
422
  * @memberof Settings */
423
423
  function setTouchGamepadSize(size) { touchGamepadSize = size; }
@@ -444,7 +444,7 @@ function setSoundVolume(volume)
444
444
  {
445
445
  soundVolume = volume;
446
446
  if (soundEnable && !headlessMode && audioGainNode)
447
- audioGainNode.gain.value = volume; // update gain immediatly
447
+ audioGainNode.gain.value = volume; // update gain immediately
448
448
  }
449
449
 
450
450
  /** Set default range where sound no longer plays
@@ -239,6 +239,10 @@ class TileLayer extends EngineObject
239
239
 
240
240
  // draw the entire cached level onto the canvas
241
241
  const pos = worldToScreen(this.pos.add(vec2(0,this.size.y*this.scale.y)));
242
+
243
+ // fix canvas jitter in some browsers if position is not an integer
244
+ pos.x |= 0; pos.y |= 0;
245
+
242
246
  (this.isOverlay ? overlayContext : mainContext).drawImage
243
247
  (
244
248
  this.canvas, pos.x, pos.y,
@@ -301,7 +305,7 @@ class TileLayer extends EngineObject
301
305
 
302
306
  /** Draw the tile at a given position in the tile grid
303
307
  * This can be used to clear out tiles when they are destroyed
304
- * Tiles can also be redrawn if isinde a redrawStart/End block
308
+ * Tiles can also be redrawn if inside a redrawStart/End block
305
309
  * @param {Vector2} layerPos
306
310
  * @param {Boolean} [clear] - should the old tile be cleared out
307
311
  */
@@ -326,7 +330,7 @@ class TileLayer extends EngineObject
326
330
  }
327
331
  }
328
332
 
329
- /** Draw directly to the 2D canvas in world space (bipass webgl)
333
+ /** Draw directly to the 2D canvas in world space (bypass webgl)
330
334
  * @param {Vector2} pos
331
335
  * @param {Vector2} size
332
336
  * @param {Number} angle
@@ -16,7 +16,7 @@
16
16
  * @memberof Utilities */
17
17
  const PI = Math.PI;
18
18
 
19
- /** Returns absoulte value of value passed in
19
+ /** Returns absolute value of value passed in
20
20
  * @param {Number} value
21
21
  * @return {Number}
22
22
  * @memberof Utilities */
@@ -49,7 +49,7 @@ function sign(value) { return Math.sign(value); }
49
49
  * @memberof Utilities */
50
50
  function mod(dividend, divisor=1) { return ((dividend % divisor) + divisor) % divisor; }
51
51
 
52
- /** Clamps the value beween max and min
52
+ /** Clamps the value between max and min
53
53
  * @param {Number} value
54
54
  * @param {Number} [min]
55
55
  * @param {Number} [max]
@@ -485,7 +485,7 @@ class Vector2
485
485
  return new Vector2(this.x*c - this.y*s, this.x*s + this.y*c);
486
486
  }
487
487
 
488
- /** Set the integer direction of this vector, corrosponding to multiples of 90 degree rotation (0-3)
488
+ /** Set the integer direction of this vector, corresponding to multiples of 90 degree rotation (0-3)
489
489
  * @param {Number} [direction]
490
490
  * @param {Number} [length] */
491
491
  setDirection(direction, length=1)
@@ -496,7 +496,7 @@ class Vector2
496
496
  direction%2 ? 0 : direction ? -length : length);
497
497
  }
498
498
 
499
- /** Returns the integer direction of this vector, corrosponding to multiples of 90 degree rotation (0-3)
499
+ /** Returns the integer direction of this vector, corresponding to multiples of 90 degree rotation (0-3)
500
500
  * @return {Number} */
501
501
  direction()
502
502
  { return abs(this.x) > abs(this.y) ? this.x < 0 ? 3 : 1 : this.y < 0 ? 2 : 0; }
@@ -881,7 +881,7 @@ const MAGENTA = rgb(1,0,1);
881
881
  * a.set(3); // sets the timer to 3 seconds
882
882
  *
883
883
  * let b = new Timer(1); // creates a timer with 1 second left
884
- * b.unset(); // unsets the timer
884
+ * b.unset(); // unset the timer
885
885
  */
886
886
  class Timer
887
887
  {
@@ -22,7 +22,7 @@ let glCanvas;
22
22
  * @memberof WebGL */
23
23
  let glContext;
24
24
 
25
- /** Shoule webgl be setup with antialiasing, must be set before calling engineInit
25
+ /** Should webgl be setup with anti-aliasing? must be set before calling engineInit
26
26
  * @type {Boolean}
27
27
  * @memberof WebGL */
28
28
  let glAntialias = true;
@@ -30,9 +30,15 @@ let glAntialias = true;
30
30
  // WebGL internal variables not exposed to documentation
31
31
  let glShader, glActiveTexture, glArrayBuffer, glGeometryBuffer, glPositionData, glColorData, glInstanceCount, glAdditive, glBatchAdditive;
32
32
 
33
+ // WebGL internal constants
34
+ const gl_MAX_INSTANCES = 1e4;
35
+ const gl_INDICES_PER_INSTANCE = 11;
36
+ const gl_INSTANCE_BYTE_STRIDE = gl_INDICES_PER_INSTANCE * 4;
37
+ const gl_INSTANCE_BUFFER_SIZE = gl_MAX_INSTANCES * gl_INSTANCE_BYTE_STRIDE;
38
+
33
39
  ///////////////////////////////////////////////////////////////////////////////
34
40
 
35
- // Initalize WebGL, called automatically by the engine
41
+ // Initialize WebGL, called automatically by the engine
36
42
  function glInit()
37
43
  {
38
44
  if (!glEnable || headlessMode) return;
@@ -82,8 +88,8 @@ function glInit()
82
88
 
83
89
  // create the geometry buffer, triangle strip square
84
90
  const geometry = new Float32Array([glInstanceCount=0,0,1,0,0,1,1,1]);
85
- glContext.bindBuffer(gl_ARRAY_BUFFER, glGeometryBuffer);
86
- glContext.bufferData(gl_ARRAY_BUFFER, geometry, gl_STATIC_DRAW);
91
+ glContext.bindBuffer(glContext.ARRAY_BUFFER, glGeometryBuffer);
92
+ glContext.bufferData(glContext.ARRAY_BUFFER, geometry, glContext.STATIC_DRAW);
87
93
  }
88
94
 
89
95
  // Setup render each frame, called automatically by engine
@@ -91,15 +97,12 @@ function glPreRender()
91
97
  {
92
98
  if (!glEnable || headlessMode) return;
93
99
 
94
- // clear and set to same size as main canvas
95
- glContext.viewport(0, 0, glCanvas.width=mainCanvas.width, glCanvas.height=mainCanvas.height);
96
- glContext.clear(gl_COLOR_BUFFER_BIT);
97
-
98
- // set up the shader
100
+ // set up the shader and canvas
101
+ glClearCanvas();
99
102
  glContext.useProgram(glShader);
100
- glContext.activeTexture(gl_TEXTURE0);
103
+ glContext.activeTexture(glContext.TEXTURE0);
101
104
  if (textureInfos[0])
102
- glContext.bindTexture(gl_TEXTURE_2D, glActiveTexture = textureInfos[0].glTexture);
105
+ glContext.bindTexture(glContext.TEXTURE_2D, glActiveTexture = textureInfos[0].glTexture);
103
106
 
104
107
  // set vertex attributes
105
108
  let offset = glAdditive = glBatchAdditive = 0;
@@ -114,15 +117,15 @@ function glPreRender()
114
117
  glContext.vertexAttribDivisor(location, divisor);
115
118
  offset += size*typeSize;
116
119
  }
117
- glContext.bindBuffer(gl_ARRAY_BUFFER, glGeometryBuffer);
118
- initVertexAttribArray('g', gl_FLOAT, 0, 2); // geometry
119
- glContext.bindBuffer(gl_ARRAY_BUFFER, glArrayBuffer);
120
- glContext.bufferData(gl_ARRAY_BUFFER, gl_INSTANCE_BUFFER_SIZE, gl_DYNAMIC_DRAW);
121
- initVertexAttribArray('p', gl_FLOAT, 4, 4); // position & size
122
- initVertexAttribArray('u', gl_FLOAT, 4, 4); // texture coords
123
- initVertexAttribArray('c', gl_UNSIGNED_BYTE, 1, 4); // color
124
- initVertexAttribArray('a', gl_UNSIGNED_BYTE, 1, 4); // additiveColor
125
- initVertexAttribArray('r', gl_FLOAT, 4, 1); // rotation
120
+ glContext.bindBuffer(glContext.ARRAY_BUFFER, glGeometryBuffer);
121
+ initVertexAttribArray('g', glContext.FLOAT, 0, 2); // geometry
122
+ glContext.bindBuffer(glContext.ARRAY_BUFFER, glArrayBuffer);
123
+ glContext.bufferData(glContext.ARRAY_BUFFER, gl_INSTANCE_BUFFER_SIZE, glContext.DYNAMIC_DRAW);
124
+ initVertexAttribArray('p', glContext.FLOAT, 4, 4); // position & size
125
+ initVertexAttribArray('u', glContext.FLOAT, 4, 4); // texture coords
126
+ initVertexAttribArray('c', glContext.UNSIGNED_BYTE, 1, 4); // color
127
+ initVertexAttribArray('a', glContext.UNSIGNED_BYTE, 1, 4); // additiveColor
128
+ initVertexAttribArray('r', glContext.FLOAT, 4, 1); // rotation
126
129
 
127
130
  // build the transform matrix
128
131
  const s = vec2(2*cameraScale).divide(mainCanvasSize);
@@ -137,6 +140,15 @@ function glPreRender()
137
140
  );
138
141
  }
139
142
 
143
+ /** Clear the canvas and setup the viewport
144
+ * @memberof WebGL */
145
+ function glClearCanvas()
146
+ {
147
+ // clear and set to same size as main canvas
148
+ glContext.viewport(0, 0, glCanvas.width=mainCanvas.width, glCanvas.height=mainCanvas.height);
149
+ glContext.clear(glContext.COLOR_BUFFER_BIT);
150
+ }
151
+
140
152
  /** Set the WebGl texture, called automatically if using multiple textures
141
153
  * - This may also flush the gl buffer resulting in more draw calls and worse performance
142
154
  * @param {WebGLTexture} texture
@@ -148,7 +160,7 @@ function glSetTexture(texture)
148
160
  return;
149
161
 
150
162
  glFlush();
151
- glContext.bindTexture(gl_TEXTURE_2D, glActiveTexture = texture);
163
+ glContext.bindTexture(glContext.TEXTURE_2D, glActiveTexture = texture);
152
164
  }
153
165
 
154
166
  /** Compile WebGL shader of the given type, will throw errors if in debug mode
@@ -164,7 +176,7 @@ function glCompileShader(source, type)
164
176
  glContext.compileShader(shader);
165
177
 
166
178
  // check for errors
167
- if (debug && !glContext.getShaderParameter(shader, gl_COMPILE_STATUS))
179
+ if (debug && !glContext.getShaderParameter(shader, glContext.COMPILE_STATUS))
168
180
  throw glContext.getShaderInfoLog(shader);
169
181
  return shader;
170
182
  }
@@ -178,12 +190,12 @@ function glCreateProgram(vsSource, fsSource)
178
190
  {
179
191
  // build the program
180
192
  const program = glContext.createProgram();
181
- glContext.attachShader(program, glCompileShader(vsSource, gl_VERTEX_SHADER));
182
- glContext.attachShader(program, glCompileShader(fsSource, gl_FRAGMENT_SHADER));
193
+ glContext.attachShader(program, glCompileShader(vsSource, glContext.VERTEX_SHADER));
194
+ glContext.attachShader(program, glCompileShader(fsSource, glContext.FRAGMENT_SHADER));
183
195
  glContext.linkProgram(program);
184
196
 
185
197
  // check for errors
186
- if (debug && !glContext.getProgramParameter(program, gl_LINK_STATUS))
198
+ if (debug && !glContext.getProgramParameter(program, glContext.LINK_STATUS))
187
199
  throw glContext.getProgramInfoLog(program);
188
200
  return program;
189
201
  }
@@ -196,20 +208,20 @@ function glCreateTexture(image)
196
208
  {
197
209
  // build the texture
198
210
  const texture = glContext.createTexture();
199
- glContext.bindTexture(gl_TEXTURE_2D, texture);
211
+ glContext.bindTexture(glContext.TEXTURE_2D, texture);
200
212
  if (image && image.width)
201
- glContext.texImage2D(gl_TEXTURE_2D, 0, gl_RGBA, gl_RGBA, gl_UNSIGNED_BYTE, image);
213
+ glContext.texImage2D(glContext.TEXTURE_2D, 0, glContext.RGBA, glContext.RGBA, glContext.UNSIGNED_BYTE, image);
202
214
  else
203
215
  {
204
216
  // create a white texture
205
217
  const whitePixel = new Uint8Array([255, 255, 255, 255]);
206
- glContext.texImage2D(gl_TEXTURE_2D, 0, gl_RGBA, 1, 1, 0, gl_RGBA, gl_UNSIGNED_BYTE, whitePixel);
218
+ glContext.texImage2D(glContext.TEXTURE_2D, 0, glContext.RGBA, 1, 1, 0, glContext.RGBA, glContext.UNSIGNED_BYTE, whitePixel);
207
219
  }
208
220
 
209
221
  // use point filtering for pixelated rendering
210
- const filter = tilesPixelated ? gl_NEAREST : gl_LINEAR;
211
- glContext.texParameteri(gl_TEXTURE_2D, gl_TEXTURE_MIN_FILTER, filter);
212
- glContext.texParameteri(gl_TEXTURE_2D, gl_TEXTURE_MAG_FILTER, filter);
222
+ const filter = tilesPixelated ? glContext.NEAREST : glContext.LINEAR;
223
+ glContext.texParameteri(glContext.TEXTURE_2D, glContext.TEXTURE_MIN_FILTER, filter);
224
+ glContext.texParameteri(glContext.TEXTURE_2D, glContext.TEXTURE_MAG_FILTER, filter);
213
225
  return texture;
214
226
  }
215
227
 
@@ -219,20 +231,20 @@ function glFlush()
219
231
  {
220
232
  if (!glInstanceCount) return;
221
233
 
222
- const destBlend = glBatchAdditive ? gl_ONE : gl_ONE_MINUS_SRC_ALPHA;
223
- glContext.blendFuncSeparate(gl_SRC_ALPHA, destBlend, gl_ONE, destBlend);
224
- glContext.enable(gl_BLEND);
234
+ const destBlend = glBatchAdditive ? glContext.ONE : glContext.ONE_MINUS_SRC_ALPHA;
235
+ glContext.blendFuncSeparate(glContext.SRC_ALPHA, destBlend, glContext.ONE, destBlend);
236
+ glContext.enable(glContext.BLEND);
225
237
 
226
238
  // draw all the sprites in the batch and reset the buffer
227
- glContext.bufferSubData(gl_ARRAY_BUFFER, 0, glPositionData);
228
- glContext.drawArraysInstanced(gl_TRIANGLE_STRIP, 0, 4, glInstanceCount);
239
+ glContext.bufferSubData(glContext.ARRAY_BUFFER, 0, glPositionData);
240
+ glContext.drawArraysInstanced(glContext.TRIANGLE_STRIP, 0, 4, glInstanceCount);
229
241
  if (showWatermark)
230
242
  drawCount += glInstanceCount;
231
243
  glInstanceCount = 0;
232
244
  glBatchAdditive = glAdditive;
233
245
  }
234
246
 
235
- /** Draw any sprites still in the buffer, copy to main canvas and clear
247
+ /** Draw any sprites still in the buffer and copy to main canvas
236
248
  * @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} context
237
249
  * @param {Boolean} [forceDraw]
238
250
  * @memberof WebGL */
@@ -247,7 +259,7 @@ function glCopyToContext(context, forceDraw=false)
247
259
  context.drawImage(glCanvas, 0, 0);
248
260
  }
249
261
 
250
- /** Set antialiasing for webgl canvas
262
+ /** Set anti-aliasing for webgl canvas
251
263
  * @param {Boolean} [antialias]
252
264
  * @memberof WebGL */
253
265
  function glSetAntialias(antialias=true)
@@ -277,7 +289,7 @@ function glDraw(x, y, sizeX, sizeY, angle, uv0X, uv0Y, uv1X, uv1Y, rgba, rgbaAdd
277
289
  if (glInstanceCount >= gl_MAX_INSTANCES || glBatchAdditive != glAdditive)
278
290
  glFlush();
279
291
 
280
- let offset = glInstanceCount * gl_INDICIES_PER_INSTANCE;
292
+ let offset = glInstanceCount++ * gl_INDICES_PER_INSTANCE;
281
293
  glPositionData[offset++] = x;
282
294
  glPositionData[offset++] = y;
283
295
  glPositionData[offset++] = sizeX;
@@ -289,38 +301,4 @@ function glDraw(x, y, sizeX, sizeY, angle, uv0X, uv0Y, uv1X, uv1Y, rgba, rgbaAdd
289
301
  glColorData[offset++] = rgba;
290
302
  glColorData[offset++] = rgbaAdditive;
291
303
  glPositionData[offset++] = angle;
292
- glInstanceCount++;
293
- }
294
-
295
- ///////////////////////////////////////////////////////////////////////////////
296
- // store gl constants as integers so their name doesn't use space in minifed
297
- const
298
- gl_ONE = 1,
299
- gl_TRIANGLE_STRIP = 5,
300
- gl_SRC_ALPHA = 770,
301
- gl_ONE_MINUS_SRC_ALPHA = 771,
302
- gl_BLEND = 3042,
303
- gl_TEXTURE_2D = 3553,
304
- gl_UNSIGNED_BYTE = 5121,
305
- gl_FLOAT = 5126,
306
- gl_RGBA = 6408,
307
- gl_NEAREST = 9728,
308
- gl_LINEAR = 9729,
309
- gl_TEXTURE_MAG_FILTER = 10240,
310
- gl_TEXTURE_MIN_FILTER = 10241,
311
- gl_COLOR_BUFFER_BIT = 16384,
312
- gl_TEXTURE0 = 33984,
313
- gl_ARRAY_BUFFER = 34962,
314
- gl_STATIC_DRAW = 35044,
315
- gl_DYNAMIC_DRAW = 35048,
316
- gl_FRAGMENT_SHADER = 35632,
317
- gl_VERTEX_SHADER = 35633,
318
- gl_COMPILE_STATUS = 35713,
319
- gl_LINK_STATUS = 35714,
320
- gl_UNPACK_FLIP_Y_WEBGL = 37440,
321
-
322
- // constants for batch rendering
323
- gl_INDICIES_PER_INSTANCE = 11,
324
- gl_MAX_INSTANCES = 1e4,
325
- gl_INSTANCE_BYTE_STRIDE = gl_INDICIES_PER_INSTANCE * 4, // 11 * 4
326
- gl_INSTANCE_BUFFER_SIZE = gl_MAX_INSTANCES * gl_INSTANCE_BYTE_STRIDE;
304
+ }