littlejsengine 1.21.0 → 1.23.0

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.
@@ -36,6 +36,8 @@ export
36
36
  debugKeysAlways,
37
37
  debugTweakables,
38
38
  levelEditor,
39
+ LevelEditor,
40
+ setLevelEditor,
39
41
 
40
42
  // Debug
41
43
  ASSERT,
@@ -97,6 +99,7 @@ export
97
99
  touchInputEnable,
98
100
  touchGamepadEnable,
99
101
  touchGamepadPassthrough,
102
+ touchPinchWheel,
100
103
  touchGamepadCenterButtonSize,
101
104
  touchGamepadButtonCount,
102
105
  touchGamepadLeftStick,
@@ -158,6 +161,7 @@ export
158
161
  setInputWASDEmulateDirection,
159
162
  setTouchGamepadEnable,
160
163
  setTouchGamepadPassthrough,
164
+ setTouchPinchWheel,
161
165
  setTouchGamepadCenterButtonSize,
162
166
  setTouchGamepadButtonCount,
163
167
  setTouchGamepadLeftStick,
@@ -335,6 +339,8 @@ export
335
339
  glFlush,
336
340
  glCopyToContext,
337
341
  glSetAntialias,
342
+ glMaxTextureSize,
343
+ glClampTextureSize,
338
344
  glDraw,
339
345
  glDrawUntextured,
340
346
  glDrawPointsTransform,
@@ -359,6 +365,7 @@ export
359
365
  mouseDelta,
360
366
  mouseDeltaScreen,
361
367
  mouseWheel,
368
+ touchPinch,
362
369
  mouseInWindow,
363
370
  isUsingGamepad,
364
371
  lastInputDevice,
@@ -38,6 +38,13 @@ let mouseDeltaScreen = vec2();
38
38
  * @memberof Input */
39
39
  let mouseWheel = 0;
40
40
 
41
+ /** Touch pinch delta this frame, in the mouse wheel's units: two fingers moving apart are negative, as the wheel
42
+ * turned up is, and moving together positive, 1 for every 50 pixels; added to mouseWheel while touchPinchWheel
43
+ * is on, so a game that zooms with the wheel zooms with a pinch
44
+ * @type {number}
45
+ * @memberof Input */
46
+ let touchPinch = 0;
47
+
41
48
  /** True if mouse was inside the document window, set to false when mouse leaves
42
49
  * @type {boolean}
43
50
  * @memberof Input */
@@ -126,6 +133,7 @@ function inputClearKey(key, device=0, clearDown=true, clearPressed=true, clearRe
126
133
  const inputWASDToArrow = {KeyW:'ArrowUp', KeyS:'ArrowDown', KeyA:'ArrowLeft', KeyD:'ArrowRight'};
127
134
  const inputArrowToWASD = {ArrowUp:'KeyW', ArrowDown:'KeyS', ArrowLeft:'KeyA', ArrowRight:'KeyD'};
128
135
  const inputKeysHeld = new Set; // the keys physically down, since an arrow's slot is shared with its alias
136
+ let inputPinch; // the two fingers pinching and how far apart they were, undefined with no pinch
129
137
  let inputWasTouching = 0, inputTouchIdentifier; // the touch driving the mouse, cleared with the input so only a new touch presses
130
138
  let inputLastTouchTime = -1e9; // when a touch event last came, the mouse events a browser makes from a tap follow it
131
139
 
@@ -168,6 +176,7 @@ function inputClear()
168
176
  if (!i || inputData[i]) inputData[i] = [];
169
177
  inputKeysHeld.clear();
170
178
  inputWasTouching = 0;
179
+ inputPinch = undefined;
171
180
  // release the touch gamepad, a finger still on it has to lift before it can take a control again
172
181
  touchGamepadPointerRole.clear();
173
182
  touchGamepadButtons.length = 0;
@@ -695,19 +704,52 @@ function inputInit()
695
704
  const pressTouch = !inputWasTouching && e.type == 'touchstart' &&
696
705
  [...e.changedTouches].find(t=> !isGamepadTouch(t));
697
706
  const touch = pressTouch || gameTouches[0];
707
+ let pos = vec2(touch.clientX, touch.clientY);
708
+
709
+ // two fingers pinch: how far they moved together or apart is the touch screen's wheel, a
710
+ // click for every 50 pixels, and the mouse is between them, the place to zoom about; with
711
+ // touchPinchWheel off the pinch is only measured, and the first finger is the mouse as ever
712
+ const pinching = touching > 1 && touchPinchWheel;
713
+ if (touching > 1)
714
+ {
715
+ const [a, b] = gameTouches, key = a.identifier + ' ' + b.identifier;
716
+ const distance = hypot(a.clientX - b.clientX, a.clientY - b.clientY);
717
+ if (inputPinch && inputPinch.key === key)
718
+ {
719
+ const delta = (inputPinch.distance - distance) / 50;
720
+ touchPinch += delta;
721
+ if (touchPinchWheel)
722
+ mouseWheel += delta;
723
+ }
724
+ inputPinch = {key, distance}; // other fingers start it over, with no jump
725
+ if (pinching)
726
+ pos = vec2((a.clientX + b.clientX) / 2, (a.clientY + b.clientY) / 2);
727
+ }
728
+ else
729
+ inputPinch = undefined;
698
730
 
699
731
  // set event pos and pass it along
700
- const pos = vec2(touch.clientX, touch.clientY);
701
732
  const mousePosScreenLast = mousePosScreen;
702
733
  mousePosScreen = mouseEventToScreen(pos);
703
- if (inputWasTouching && touch.identifier === inputTouchIdentifier)
734
+ if (pinching)
735
+ {
736
+ // a pinch is not a press or a drag, the finger that pressed lets go
737
+ if (inputData[0][button] & 1)
738
+ inputData[0][button] = inputData[0][button] & 2 | 4;
739
+ }
740
+ else if (inputWasTouching && touch.identifier === inputTouchIdentifier)
704
741
  mouseDeltaScreen = mouseDeltaScreen.add(mousePosScreen.subtract(mousePosScreenLast));
705
742
  else if (pressTouch)
706
743
  inputData[0][button] = 3;
707
- inputTouchIdentifier = touch.identifier;
744
+ // the finger left after a pinch moves the mouse from where it is, with no jump and no press
745
+ inputTouchIdentifier = pinching ? undefined : touch.identifier;
746
+ }
747
+ else
748
+ {
749
+ inputPinch = undefined;
750
+ if (inputWasTouching && (inputData[0][button] & 1))
751
+ inputData[0][button] = inputData[0][button] & 2 | 4; // released only if it was pressed
708
752
  }
709
- else if (inputWasTouching && (inputData[0][button] & 1))
710
- inputData[0][button] = inputData[0][button] & 2 | 4; // released only if it was pressed
711
753
 
712
754
  // set was touching
713
755
  inputWasTouching = touching;
@@ -966,7 +1008,7 @@ function inputUpdatePost()
966
1008
  for (const deviceInputData of inputData)
967
1009
  for (const i in deviceInputData)
968
1010
  deviceInputData[i] &= 1;
969
- mouseWheel = 0;
1011
+ mouseWheel = touchPinch = 0;
970
1012
  mouseDelta = vec2();
971
1013
  mouseDeltaScreen = vec2();
972
1014
  }
@@ -165,6 +165,13 @@ class ParticleEmitter extends EngineObject
165
165
  this.localSpace = localSpace;
166
166
  /** @property {number} - If non zero the particle is drawn as a trail, stretched in the direction of velocity */
167
167
  this.trailScale = 0;
168
+ /** @property {number} - Grows the whole effect as each particle is born: the spawn area, the particles' sizes,
169
+ * speed and fall, so it looks the same only bigger; 1 is as made, and a particle keeps the scale it was born
170
+ * with, so a change never moves the ones already out */
171
+ this.scale = 1;
172
+ /** @property {number} - The effect's own fall, added to each particle's velocity y every frame, on top of the
173
+ * world's gravity times gravityScale; an effect that sets its own looks the same in any game */
174
+ this.gravity = 0;
168
175
  /** @property {ParticleCallback|undefined} - Callback when particle is created
169
176
  * @type {ParticleCallback|undefined} */
170
177
  this.particleCreateCallback = undefined;
@@ -251,9 +258,9 @@ class ParticleEmitter extends EngineObject
251
258
  {
252
259
  // show emitter bounds
253
260
  if (this.emitCircle)
254
- debugCircle(this.pos, this.emitSize.x, '#0f0', 0, false, false);
261
+ debugCircle(this.pos, this.emitSize.x * this.scale, '#0f0', 0, false, false);
255
262
  else
256
- debugRect(this.pos, this.emitSize, '#0f0', 0, this.angle, false, false);
263
+ debugRect(this.pos, this.emitSize.scale(this.scale), '#0f0', 0, this.angle, false, false);
257
264
  }
258
265
  }
259
266
 
@@ -262,10 +269,11 @@ class ParticleEmitter extends EngineObject
262
269
  emitParticle()
263
270
  {
264
271
  // spawn a particle
272
+ const scale = this.scale; // grows the spawn area, the sizes and the speed of each particle born
265
273
  let pos = this.emitCircle ? // check if circle emitter
266
- randInCircle(this.emitSize.x/2) // circle emitter
267
- : vec2(rand(-.5,.5), rand(-.5,.5)) // box emitter
268
- .multiply(this.emitSize);
274
+ randInCircle(this.emitSize.x/2 * scale) // circle emitter
275
+ : vec2(rand(-.5,.5) * this.emitSize.x * scale, // box emitter, one vector made
276
+ rand(-.5,.5) * this.emitSize.y * scale);
269
277
  let angle = rand(this.particleConeAngle, -this.particleConeAngle);
270
278
  if (!this.localSpace)
271
279
  {
@@ -282,9 +290,9 @@ class ParticleEmitter extends EngineObject
282
290
 
283
291
  // randomize particle settings
284
292
  const particleTime = randomizeScale(this.particleTime);
285
- const sizeStart = randomizeScale(this.sizeStart);
286
- const sizeEnd = randomizeScale(this.sizeEnd);
287
- const speed = randomizeScale(this.speed);
293
+ const sizeStart = randomizeScale(this.sizeStart) * scale;
294
+ const sizeEnd = randomizeScale(this.sizeEnd) * scale;
295
+ const speed = randomizeScale(this.speed) * scale;
288
296
  const angleSpeed = randomizeScale(this.angleSpeed) * randSign();
289
297
  const coneAngle = rand(this.emitConeAngle, -this.emitConeAngle);
290
298
  const colorStart = randColor(this.colorStartA, this.colorStartB, this.randomColorLinear);
@@ -318,9 +326,13 @@ class ParticleEmitter extends EngineObject
318
326
  render()
319
327
  {
320
328
  // render all particles, the blend switched once for them all, not around each one
329
+ // and the tile's draw worked out once for them all, fresh each frame so a tile changed in place draws changed
321
330
  this.additive && setAdditiveBlendMode();
331
+ particleTile = null; // none yet, undefined is the untextured tile
332
+ particleTileBatch = true;
322
333
  for (const particle of this.particles)
323
334
  particle.render();
335
+ particleTileBatch = false;
324
336
  this.additive && setAdditiveBlendMode(false);
325
337
  }
326
338
 
@@ -347,6 +359,39 @@ class ParticleEmitter extends EngineObject
347
359
  // scratch vectors reused by Particle.render and the tile collision to avoid per-frame allocations
348
360
  const particleDrawPos = new Vector2, particleDrawSize = new Vector2, particleCollidePos = new Vector2;
349
361
 
362
+ // the WebGL draw of the tile particles draw with, what drawTile works out for each sprite: kept while an emitter
363
+ // renders its particles, so each one only writes its own values into the batch
364
+ let particleTile, particleTileBatch = false, particleTileTextured = false, particleTileEmpty = false;
365
+ let particleTileU0 = 0, particleTileV0 = 0, particleTileU1 = 0, particleTileV1 = 0;
366
+ function particleTileSet(tileInfo)
367
+ {
368
+ particleTile = tileInfo;
369
+ const textureInfo = tileInfo?.textureInfo;
370
+ particleTileTextured = !!textureInfo;
371
+ particleTileEmpty = !!textureInfo && !(tileInfo.size.x && tileInfo.size.y); // like a sprite still loading
372
+ if (!textureInfo || particleTileEmpty) return;
373
+
374
+ ASSERT(!!textureInfo.glTexture, 'texture has no WebGL texture, draw it with useWebGL false');
375
+ glSetTexture(textureInfo.glTexture); // bound, and its mipmaps brought up to date, once for the emitter
376
+ const sizeInverse = textureInfo.sizeInverse, bleed = tileInfo.bleed;
377
+ const x = tileInfo.pos.x * sizeInverse.x;
378
+ const y = tileInfo.pos.y * sizeInverse.y;
379
+ const w = tileInfo.size.x * sizeInverse.x;
380
+ const h = tileInfo.size.y * sizeInverse.y;
381
+ if (bleed)
382
+ {
383
+ const bleedX = sizeInverse.x*bleed;
384
+ const bleedY = sizeInverse.y*bleed;
385
+ particleTileU0 = x + bleedX; particleTileV0 = y + bleedY;
386
+ particleTileU1 = x - bleedX + w; particleTileV1 = y - bleedY + h;
387
+ }
388
+ else
389
+ {
390
+ particleTileU0 = x; particleTileV0 = y;
391
+ particleTileU1 = x + w; particleTileV1 = y + h;
392
+ }
393
+ }
394
+
350
395
  // tests if a particle collides with tiles at x, y, through its emitter's collide callback if it has one
351
396
  function particleCollideTest(particle, collideCallback, x, y)
352
397
  {
@@ -382,6 +427,8 @@ class Particle
382
427
  {
383
428
  /** @property {ParticleEmitter} - The emitter this particle came from */
384
429
  this.emitter = emitter;
430
+ /** @property {number} - The emitter's scale when it was made, which grows its fall */
431
+ this.scale = emitter.scale ?? 1; // a hand made emitter-like object may have none
385
432
  /** @property {Vector2} - Position, world space or local to the emitter when localSpace is set */
386
433
  this.pos = pos;
387
434
  /** @property {number} - Angle in radians */
@@ -444,7 +491,10 @@ class Particle
444
491
  // apply physics; only the tile collision needs where the particle was
445
492
  const solve = enablePhysicsSolver && collideLevel;
446
493
  const oldX = this.pos.x, oldY = this.pos.y;
447
- let gravityX = gravity.x * gravityScale, gravityY = gravity.y * gravityScale;
494
+ // the world's gravity times gravityScale plus the emitter's own, grown by the particle's scale
495
+ const fall = this.scale;
496
+ let gravityX = gravity.x * gravityScale * fall;
497
+ let gravityY = (gravity.y * gravityScale + (emitter.gravity || 0)) * fall;
448
498
  if (emitter.localSpace && emitter.angle)
449
499
  {
450
500
  // world gravity turned into the emitter's space, the render turns it back
@@ -498,7 +548,9 @@ class Particle
498
548
  }
499
549
  if (isBlockedY || !isBlockedX)
500
550
  {
501
- const wasFalling = this.velocity.y < 0 && gravity.y < 0 || this.velocity.y > 0 && gravity.y > 0;
551
+ // down is the world's gravity, or the emitter's own fall in a world with none
552
+ const down = gravity.y || emitter.gravity || 0;
553
+ const wasFalling = this.velocity.y < 0 && down < 0 || this.velocity.y > 0 && down > 0;
502
554
  if (wasFalling)
503
555
  this.groundObject = hitLayer;
504
556
 
@@ -577,7 +629,24 @@ class Particle
577
629
  angle = atan2(velocity.x, velocity.y);
578
630
  }
579
631
  }
580
- drawTile(pos, size, this.tileInfo, this.color, angle, this.mirror, undefined, glEnable, false);
632
+ if (glEnable && !headlessMode)
633
+ {
634
+ // straight into the batch, the tile's draw worked out once for the emitter's particles
635
+ const tileInfo = this.tileInfo;
636
+ if (!particleTileBatch || tileInfo !== particleTile)
637
+ particleTileSet(tileInfo);
638
+ if (!particleTileTextured)
639
+ glDrawUntextured(pos.x, pos.y, size.x, size.y, angle, this.color.rgbaInt());
640
+ else if (!particleTileEmpty)
641
+ {
642
+ const texture = tileInfo.textureInfo.glTexture;
643
+ glActiveTexture === texture || glSetTexture(texture); // bound again only if a draw between changed it
644
+ glDraw(pos.x, pos.y, this.mirror ? -size.x : size.x, size.y, angle,
645
+ particleTileU0, particleTileV0, particleTileU1, particleTileV1, this.color.rgbaInt());
646
+ }
647
+ }
648
+ else
649
+ drawTile(pos, size, this.tileInfo, this.color, angle, this.mirror, undefined, false, false);
581
650
  additive && setAdditiveBlendMode(false);
582
651
  debugParticles && debugRect(pos, size, '#f005', 0, angle, false, false);
583
652
  }
@@ -52,8 +52,19 @@ function tweak(){}
52
52
  function tweakButton(){}
53
53
  function tweakDivider(){}
54
54
  function tweakEngineDefaults(){}
55
- const levelEditor = {isOpen: false, open(){}, close(){}, onTile: undefined, onRestart: undefined, onPlayFrom: undefined,
56
- paletteTiles: undefined, use3D: undefined};
55
+ class LevelEditor
56
+ {
57
+ constructor() { this.paletteTiles = this.use3D = this.tool = undefined; }
58
+ get isOpen() { return false; }
59
+ get is3D() { return false; }
60
+ get edit2D() { return undefined; }
61
+ get edit3D() { return undefined; }
62
+ open(){} close(){} addKey(){} addButton(){} addTool(){}
63
+ onTile(){} onRestart(){} onPlayFrom(){} onOpen(){} onClose(){} onUpdate(){} onDraw(){} onPanel(){}
64
+ onSave(){ return false; }
65
+ }
66
+ let levelEditor = new LevelEditor;
67
+ function setLevelEditor(editor){ levelEditor = editor; }
57
68
  function editorMapRestore(map){ return map; }
58
69
  function editorMapLoaded(){}
59
70
  function editorJSONFetched(){}
@@ -313,6 +313,15 @@ let touchGamepadEnable = false;
313
313
  * @memberof Settings */
314
314
  let touchGamepadPassthrough = false;
315
315
 
316
+ /** True if a pinch of two fingers turns the mouse wheel: touchPinch is added to mouseWheel, so what zooms with
317
+ * the wheel zooms with a pinch, the mouse is between the two fingers, and a second finger lets go of the button
318
+ * the first pressed, since a pinch is not a drag; turn it off for a game with its own use for two fingers, the
319
+ * first finger stays the mouse and touchPinch can still be read
320
+ * @type {boolean}
321
+ * @default
322
+ * @memberof Settings */
323
+ let touchPinchWheel = true;
324
+
316
325
  /** Size of center button if touch gamepad should have start button in the center
317
326
  * - Prevents activating when pressed near virtual stick or face buttons
318
327
  * - When the game is paused, any touch will press the button
@@ -708,6 +717,11 @@ function setTouchInputEnable(enable) { touchInputEnable = enable; }
708
717
  * @memberof Settings */
709
718
  function setTouchGamepadEnable(enable) { touchGamepadEnable = enable; }
710
719
 
720
+ /** Set if a pinch of two fingers turns the mouse wheel
721
+ * @param {boolean} enable
722
+ * @memberof Settings */
723
+ function setTouchPinchWheel(enable) { touchPinchWheel = enable; }
724
+
711
725
  /** Set if touches outside the gamepad controls should still drive mouse/touch input
712
726
  * @param {boolean} passthrough
713
727
  * @memberof Settings */
@@ -26,6 +26,19 @@ let glCanvas;
26
26
  * @memberof WebGL */
27
27
  let glContext;
28
28
 
29
+ /** The largest texture this device makes, in pixels across, 0 until WebGL starts; at least 2048 with WebGL2
30
+ * @type {number}
31
+ * @memberof WebGL */
32
+ let glMaxTextureSize = 0;
33
+
34
+ /** A texture size this device can make: the size asked for, or the largest it supports when that is smaller
35
+ * - The engine sizes the textures it makes itself through this, the shadow maps and the like, so a size a device
36
+ * does not have falls back instead of failing
37
+ * @param {number} size - Pixels across
38
+ * @return {number}
39
+ * @memberof WebGL */
40
+ function glClampTextureSize(size) { return glMaxTextureSize ? min(size, glMaxTextureSize) : size; }
41
+
29
42
  /** Should WebGL be setup with anti-aliasing? must be set before calling engineInit
30
43
  * @type {boolean}
31
44
  * @memberof WebGL */
@@ -115,7 +128,7 @@ function glInit(rootElement)
115
128
  // startup webgl, and make the textures of any texture infos made before it
116
129
  initWebGL();
117
130
  for (const info of glTextureInfos)
118
- info.glTexture ||= glCreateTexture(info.image, info.wrap);
131
+ info.glTexture ||= glCreateTexture(info.image, info.wrap, info.pixelated);
119
132
 
120
133
  // setup context lost and restore handlers
121
134
  glCanvas.addEventListener('webglcontextlost', (e)=>
@@ -155,7 +168,7 @@ function glInit(rootElement)
155
168
  glPremultipliedTextures = new WeakSet; // the tile layers draw into their new textures again below
156
169
  initWebGL();
157
170
  for (const info of glTextureInfos)
158
- info.glTexture = glCreateTexture(info.image, info.wrap);
171
+ info.glTexture = glCreateTexture(info.image, info.wrap, info.pixelated);
159
172
  pluginList.forEach(plugin=>plugin.glContextRestored?.());
160
173
 
161
174
  // a tile layer drawn on the GPU only had its tiles in the lost texture, it draws them again
@@ -165,6 +178,8 @@ function glInit(rootElement)
165
178
 
166
179
  function initWebGL()
167
180
  {
181
+ glMaxTextureSize = glContext.getParameter(glContext.MAX_TEXTURE_SIZE) | 0;
182
+
168
183
  // setup instanced rendering shader program
169
184
  glShader = glCreateProgram(gl_VERTEX_SOURCE,
170
185
  '#version 300 es\n' + // specify GLSL ES version
@@ -488,9 +503,10 @@ function glShaderProgram(shader)
488
503
  * Restores the active texture when done
489
504
  * @param {HTMLImageElement|HTMLCanvasElement|OffscreenCanvas|ImageBitmap} [image]
490
505
  * @param {boolean|Array<number>} [wrap] - true for REPEAT, false for CLAMP_TO_EDGE, or the WebGL modes across and down
506
+ * @param {boolean} [pixelated] - Hard edged or smooth, undefined follows tilesPixelated
491
507
  * @return {WebGLTexture}
492
508
  * @memberof WebGL */
493
- function glCreateTexture(image, wrap=false)
509
+ function glCreateTexture(image, wrap=false, pixelated=tilesPixelated)
494
510
  {
495
511
  if (!glContext) return;
496
512
 
@@ -499,10 +515,10 @@ function glCreateTexture(image, wrap=false)
499
515
  let mipMap = false;
500
516
  if (image?.width)
501
517
  {
502
- glSetTextureData(texture, image);
518
+ glSetTextureData(texture, image, pixelated);
503
519
  glContext.bindTexture(glContext.TEXTURE_2D, texture);
504
520
  // WebGL2 makes mipmaps at any size, a texture that becomes a render target keeps them only at powers of two
505
- mipMap = !tilesPixelated;
521
+ mipMap = !pixelated;
506
522
  if (mipMap && !(isPowerOfTwo(image.width) && isPowerOfTwo(image.height)))
507
523
  glMipmapsUntilTarget.add(texture);
508
524
  }
@@ -515,7 +531,7 @@ function glCreateTexture(image, wrap=false)
515
531
  }
516
532
 
517
533
  // set texture filtering
518
- const magFilter = tilesPixelated ? glContext.NEAREST : glContext.LINEAR;
534
+ const magFilter = pixelated ? glContext.NEAREST : glContext.LINEAR;
519
535
  const minFilter = mipMap ? glContext.LINEAR_MIPMAP_LINEAR : magFilter;
520
536
  glContext.texParameteri(glContext.TEXTURE_2D, glContext.TEXTURE_MAG_FILTER, magFilter);
521
537
  glContext.texParameteri(glContext.TEXTURE_2D, glContext.TEXTURE_MIN_FILTER, minFilter);
@@ -546,8 +562,9 @@ function glDeleteTexture(texture)
546
562
  /** Set WebGL texture data from an image, restores the active texture when done
547
563
  * @param {WebGLTexture} texture
548
564
  * @param {HTMLImageElement|HTMLCanvasElement|OffscreenCanvas|ImageBitmap} image
565
+ * @param {boolean} [pixelated] - Hard edged or smooth, undefined follows tilesPixelated
549
566
  * @memberof WebGL */
550
- function glSetTextureData(texture, image)
567
+ function glSetTextureData(texture, image, pixelated=tilesPixelated)
551
568
  {
552
569
  if (!glContext) return;
553
570
 
@@ -565,7 +582,7 @@ function glSetTextureData(texture, image)
565
582
  }
566
583
  // smooth filtering mixes a texel with its see through neighbors, right only for premultiplied color, or the
567
584
  // edges go dark; pixel art is sampled a texel at a time, and uploads straight color as it always has
568
- const premultiply = !tilesPixelated;
585
+ const premultiply = !pixelated;
569
586
  glContext.pixelStorei(glContext.UNPACK_PREMULTIPLY_ALPHA_WEBGL, premultiply);
570
587
  glContext.texImage2D(glContext.TEXTURE_2D, 0, glContext.RGBA, glContext.RGBA, glContext.UNSIGNED_BYTE, image);
571
588
  glContext.pixelStorei(glContext.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
@@ -596,9 +613,9 @@ function glRegisterTextureInfo(textureInfo)
596
613
 
597
614
  // create or set the texture data
598
615
  if (textureInfo.glTexture)
599
- glSetTextureData(textureInfo.glTexture, textureInfo.image);
616
+ glSetTextureData(textureInfo.glTexture, textureInfo.image, textureInfo.pixelated);
600
617
  else
601
- textureInfo.glTexture = glCreateTexture(textureInfo.image, textureInfo.wrap);
618
+ textureInfo.glTexture = glCreateTexture(textureInfo.image, textureInfo.wrap, textureInfo.pixelated);
602
619
  }
603
620
 
604
621
  /** Internal: tells WebGL to destroy the glTexture and stop tracking it, TextureInfo calls it