littlejsengine 1.14.4 → 1.14.7
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/README.md +3 -3
- package/dist/littlejs.d.ts +40 -14
- package/dist/littlejs.esm.js +119 -59
- package/dist/littlejs.esm.min.js +1 -1
- package/dist/littlejs.js +115 -57
- package/dist/littlejs.min.js +1 -1
- package/dist/littlejs.release.js +108 -50
- package/examples/box2d/game.js +1 -3
- package/examples/box2d/gameObjects.js +2 -2
- package/examples/htmlMenu/game.js +1 -1
- package/examples/index.html +85 -49
- package/examples/puzzle/game.js +1 -2
- package/examples/shorts/animation.js +2 -2
- package/examples/shorts/box2d.js +1 -0
- package/examples/shorts/box2dCar.js +1 -0
- package/examples/shorts/flappyGame.js +2 -1
- package/examples/shorts/helloWorld.js +2 -2
- package/examples/shorts/hillGlideGame.js +6 -3
- package/examples/shorts/maze.js +1 -0
- package/examples/shorts/medals.js +3 -0
- package/examples/shorts/music.js +6 -8
- package/examples/shorts/platformer.js +1 -0
- package/examples/shorts/shapes.js +6 -6
- package/examples/shorts/sound.js +1 -0
- package/examples/shorts/spriteAtlas.js +1 -2
- package/examples/shorts/tileLayer.js +1 -0
- package/examples/shorts/tiltedView.js +1 -1
- package/examples/shorts/timers.js +34 -31
- package/examples/shorts/topDown.js +2 -1
- package/examples/shorts/uiSystem.js +3 -5
- package/examples/stress/index.html +1 -1
- package/examples/uiSystem/game.js +1 -1
- package/package.json +1 -1
- package/plugins/uiSystem.js +35 -17
- package/reference.md +1 -1
- package/src/engine.js +23 -6
- package/src/engineDebug.js +7 -7
- package/src/engineDraw.js +18 -11
- package/src/engineExport.js +4 -2
- package/src/engineSettings.js +10 -0
- package/src/engineUtilities.js +4 -0
- package/src/engineWebGL.js +18 -16
package/plugins/uiSystem.js
CHANGED
|
@@ -49,6 +49,8 @@ class UISystemPlugin
|
|
|
49
49
|
this.defaultLineWidth = 4;
|
|
50
50
|
/** @property {number} - Default rounded rect corner radius for UI elements */
|
|
51
51
|
this.defaultCornerRadius = 0;
|
|
52
|
+
/** @property {number} - Default scale to use for fitting text to object */
|
|
53
|
+
this.defaultTextScale = .8;
|
|
52
54
|
/** @property {string} - Default font for UI elements */
|
|
53
55
|
this.defaultFont = 'arial';
|
|
54
56
|
/** @property {Sound} - Default sound when interactive UI element is pressed */
|
|
@@ -65,6 +67,7 @@ class UISystemPlugin
|
|
|
65
67
|
engineAddPlugin(uiUpdate, uiRender);
|
|
66
68
|
|
|
67
69
|
// setup recursive update and render
|
|
70
|
+
// update in reverse order to detect mouse enter/leave
|
|
68
71
|
function uiUpdate()
|
|
69
72
|
{
|
|
70
73
|
function updateInvisibleObject(o)
|
|
@@ -89,7 +92,11 @@ class UISystemPlugin
|
|
|
89
92
|
else
|
|
90
93
|
updateInvisibleObject(o);
|
|
91
94
|
}
|
|
92
|
-
uiSystem.uiObjects.
|
|
95
|
+
for (let i = uiSystem.uiObjects.length; i--;)
|
|
96
|
+
{
|
|
97
|
+
const o = uiSystem.uiObjects[i];
|
|
98
|
+
o.parent || updateObject(o)
|
|
99
|
+
}
|
|
93
100
|
}
|
|
94
101
|
function uiRender()
|
|
95
102
|
{
|
|
@@ -168,10 +175,11 @@ class UISystemPlugin
|
|
|
168
175
|
* @param {number} [lineWidth=uiSystem.defaultLineWidth]
|
|
169
176
|
* @param {Color} [lineColor=uiSystem.defaultLineColor]
|
|
170
177
|
* @param {string} [align]
|
|
171
|
-
* @param {string} [font=uiSystem.defaultFont]
|
|
172
|
-
|
|
178
|
+
* @param {string} [font=uiSystem.defaultFont]
|
|
179
|
+
* @param {boolean} [applyMaxWidth=true] */
|
|
180
|
+
drawText(text, pos, size, color=uiSystem.defaultColor, lineWidth=uiSystem.defaultLineWidth, lineColor=uiSystem.defaultLineColor, align='center', font=uiSystem.defaultFont, applyMaxWidth=true)
|
|
173
181
|
{
|
|
174
|
-
drawTextScreen(text, pos, size.y, color, lineWidth, lineColor, align, font, size.x, uiSystem.uiContext);
|
|
182
|
+
drawTextScreen(text, pos, size.y, color, lineWidth, lineColor, align, font, applyMaxWidth ? size.x : undefined, uiSystem.uiContext);
|
|
175
183
|
}
|
|
176
184
|
}
|
|
177
185
|
|
|
@@ -213,8 +221,12 @@ class UIObject
|
|
|
213
221
|
this.cornerRadius = uiSystem.defaultCornerRadius;
|
|
214
222
|
/** @property {string} - Font for this objecct */
|
|
215
223
|
this.font = uiSystem.defaultFont;
|
|
224
|
+
/** @property {number} - Override for text width */
|
|
225
|
+
this.textWidth = undefined;
|
|
216
226
|
/** @property {number} - Override for text height */
|
|
217
227
|
this.textHeight = undefined;
|
|
228
|
+
/** @property {number} - Scale text to fit in the object */
|
|
229
|
+
this.textScale = uiSystem.defaultTextScale;
|
|
218
230
|
/** @property {boolean} - Should this object be drawn */
|
|
219
231
|
this.visible = true;
|
|
220
232
|
/** @property {Array<UIObject>} - A list of this object's children */
|
|
@@ -324,6 +336,16 @@ class UIObject
|
|
|
324
336
|
this.mouseIsOver = this.mouseIsHeld = false;
|
|
325
337
|
}
|
|
326
338
|
|
|
339
|
+
/** Get the size for text with overrides and scale
|
|
340
|
+
* @return {Vector2}
|
|
341
|
+
*/
|
|
342
|
+
getTextSize()
|
|
343
|
+
{
|
|
344
|
+
return vec2(
|
|
345
|
+
this.textWidth || this.textScale * this.size.x,
|
|
346
|
+
this.textHeight || this.textScale * this.size.y);
|
|
347
|
+
}
|
|
348
|
+
|
|
327
349
|
/** Called when the mouse enters the object */
|
|
328
350
|
onEnter() {}
|
|
329
351
|
|
|
@@ -371,7 +393,7 @@ class UIText extends UIObject
|
|
|
371
393
|
}
|
|
372
394
|
render()
|
|
373
395
|
{
|
|
374
|
-
const textSize =
|
|
396
|
+
const textSize = this.getTextSize();
|
|
375
397
|
uiSystem.drawText(this.text, this.pos, textSize, this.textColor, this.lineWidth, this.lineColor, this.align, this.font);
|
|
376
398
|
}
|
|
377
399
|
}
|
|
@@ -439,9 +461,8 @@ class UIButton extends UIObject
|
|
|
439
461
|
const color = this.disabled ? this.disabledColor : this.mouseIsOver ? this.hoverColor : this.color;
|
|
440
462
|
uiSystem.drawRect(this.pos, this.size, color, this.lineWidth, lineColor, this.cornerRadius);
|
|
441
463
|
|
|
442
|
-
// draw the text
|
|
443
|
-
const
|
|
444
|
-
const textSize = vec2(this.size.x, this.textHeight || this.size.y*textScale);
|
|
464
|
+
// draw the text scaled to fit
|
|
465
|
+
const textSize = this.getTextSize();
|
|
445
466
|
uiSystem.drawText(this.text, this.pos, textSize,
|
|
446
467
|
this.textColor, 0, undefined, this.align, this.font);
|
|
447
468
|
}
|
|
@@ -490,13 +511,11 @@ class UICheckbox extends UIObject
|
|
|
490
511
|
uiSystem.drawLine(this.pos.add(s.multiply(vec2(-1,1))), this.pos.add(s.multiply(vec2(1,-1))), this.lineWidth, this.lineColor);
|
|
491
512
|
}
|
|
492
513
|
|
|
493
|
-
// draw the text to the
|
|
494
|
-
const
|
|
495
|
-
const
|
|
496
|
-
const textSize = vec2(this.size.x, this.textHeight || this.size.y*textScale);
|
|
497
|
-
const pos = this.pos.add(vec2(this.size.x*gapScale,0));
|
|
514
|
+
// draw the text next to the checkbox
|
|
515
|
+
const textSize = this.getTextSize();
|
|
516
|
+
const pos = this.pos.add(vec2(this.size.x,0));
|
|
498
517
|
uiSystem.drawText(this.text, pos, textSize,
|
|
499
|
-
this.textColor, 0, undefined, 'left', this.font);
|
|
518
|
+
this.textColor, 0, undefined, 'left', this.font, false);
|
|
500
519
|
}
|
|
501
520
|
}
|
|
502
521
|
|
|
@@ -563,9 +582,8 @@ class UIScrollbar extends UIObject
|
|
|
563
582
|
this.interactive && this.mouseIsHeld ? this.color : this.handleColor;
|
|
564
583
|
uiSystem.drawRect(handlePos, handleSize, handleColor, this.lineWidth, this.lineColor, this.cornerRadius);
|
|
565
584
|
|
|
566
|
-
// draw the text on the scrollbar
|
|
567
|
-
const
|
|
568
|
-
const textSize = vec2(this.size.x, this.textHeight || this.size.y*textScale);
|
|
585
|
+
// draw the text scaled to fit on the scrollbar
|
|
586
|
+
const textSize = this.getTextSize();
|
|
569
587
|
uiSystem.drawText(this.text, this.pos, textSize,
|
|
570
588
|
this.textColor, 0, undefined, this.align, this.font);
|
|
571
589
|
}
|
package/reference.md
CHANGED
|
@@ -426,7 +426,7 @@ particleEmitRateScale = 1 // Scales particles emit rate
|
|
|
426
426
|
```javascript
|
|
427
427
|
ASSERT(assert, output) // Asserts if the expression is false
|
|
428
428
|
debugRect(pos, size, color='#fff', time=0, angle=0, fill) // Draw debug rectangle
|
|
429
|
-
debugCircle(pos,
|
|
429
|
+
debugCircle(pos, size, color='#fff', time=0, fill) // Draw debug circle
|
|
430
430
|
debugPoint(pos, color, time, angle) // Draw debug point
|
|
431
431
|
debugLine(posA, posB, color, width=.1, time) // Draw debug line
|
|
432
432
|
debugText(text, pos, size=1, color='#fff', time=0, angle=0) // Draw debug text
|
package/src/engine.js
CHANGED
|
@@ -30,7 +30,7 @@ const engineName = 'LittleJS';
|
|
|
30
30
|
* @type {string}
|
|
31
31
|
* @default
|
|
32
32
|
* @memberof Engine */
|
|
33
|
-
const engineVersion = '1.14.
|
|
33
|
+
const engineVersion = '1.14.7';
|
|
34
34
|
|
|
35
35
|
/** Frames per second to update
|
|
36
36
|
* @type {number}
|
|
@@ -169,15 +169,15 @@ async function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, game
|
|
|
169
169
|
frameTimeBufferMS += paused ? 0 : frameTimeDeltaMS;
|
|
170
170
|
if (!debugSpeedUp)
|
|
171
171
|
frameTimeBufferMS = min(frameTimeBufferMS, 50); // clamp min framerate
|
|
172
|
-
if (debugVideoCaptureIsActive())
|
|
173
|
-
frameTimeBufferMS = 0; // no time smoothing when capturing video
|
|
174
|
-
updateCanvas();
|
|
175
172
|
|
|
176
173
|
if (paused)
|
|
177
174
|
{
|
|
175
|
+
updateCanvas();
|
|
176
|
+
|
|
178
177
|
// update object transforms even when paused
|
|
179
178
|
for (const o of engineObjects)
|
|
180
179
|
o.parent || o.updateTransforms();
|
|
180
|
+
|
|
181
181
|
inputUpdate();
|
|
182
182
|
pluginUpdateList.forEach(f=>f());
|
|
183
183
|
debugUpdate();
|
|
@@ -202,6 +202,7 @@ async function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, game
|
|
|
202
202
|
time = frame++ / frameRate;
|
|
203
203
|
|
|
204
204
|
// update game and objects
|
|
205
|
+
updateCanvas();
|
|
205
206
|
inputUpdate();
|
|
206
207
|
gameUpdate();
|
|
207
208
|
pluginUpdateList.forEach(f=>f());
|
|
@@ -211,14 +212,23 @@ async function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, game
|
|
|
211
212
|
debugUpdate();
|
|
212
213
|
gameUpdatePost();
|
|
213
214
|
inputUpdatePost();
|
|
215
|
+
|
|
216
|
+
if (debugVideoCaptureIsActive())
|
|
217
|
+
renderFrame();
|
|
214
218
|
}
|
|
215
219
|
|
|
216
220
|
// add the time smoothing back in
|
|
217
221
|
frameTimeBufferMS += deltaSmooth;
|
|
218
222
|
}
|
|
219
223
|
|
|
220
|
-
if (!
|
|
224
|
+
if (!debugVideoCaptureIsActive())
|
|
225
|
+
renderFrame();
|
|
226
|
+
requestAnimationFrame(engineUpdate);
|
|
227
|
+
|
|
228
|
+
function renderFrame()
|
|
221
229
|
{
|
|
230
|
+
if (headlessMode) return;
|
|
231
|
+
|
|
222
232
|
// render sort then render while removing destroyed objects
|
|
223
233
|
enginePreRender();
|
|
224
234
|
gameRender();
|
|
@@ -248,7 +258,6 @@ async function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, game
|
|
|
248
258
|
}
|
|
249
259
|
drawCount = 0;
|
|
250
260
|
}
|
|
251
|
-
requestAnimationFrame(engineUpdate);
|
|
252
261
|
}
|
|
253
262
|
|
|
254
263
|
function updateCanvas()
|
|
@@ -274,6 +283,14 @@ async function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, game
|
|
|
274
283
|
mainCanvas.height = min(innerHeight, canvasMaxSize.y);
|
|
275
284
|
}
|
|
276
285
|
|
|
286
|
+
// apply the clear color to main canvas
|
|
287
|
+
if (canvasClearColor.a > 0)
|
|
288
|
+
{
|
|
289
|
+
mainContext.fillStyle = canvasClearColor.toString();
|
|
290
|
+
mainContext.fillRect(0, 0, mainCanvasSize.x, mainCanvasSize.y);
|
|
291
|
+
mainContext.fillStyle = BLACK.toString();
|
|
292
|
+
}
|
|
293
|
+
|
|
277
294
|
// clear overlay canvas and set size
|
|
278
295
|
overlayCanvas.width = mainCanvas.width;
|
|
279
296
|
overlayCanvas.height = mainCanvas.height;
|
package/src/engineDebug.js
CHANGED
|
@@ -94,15 +94,15 @@ function debugPoly(pos, points, color='#fff', time=0, angle=0, fill=false)
|
|
|
94
94
|
|
|
95
95
|
/** Draw a debug circle in world space
|
|
96
96
|
* @param {Vector2} pos
|
|
97
|
-
* @param {number} [
|
|
97
|
+
* @param {number} [size] - diameter
|
|
98
98
|
* @param {string} [color]
|
|
99
99
|
* @param {number} [time]
|
|
100
100
|
* @param {boolean} [fill]
|
|
101
101
|
* @memberof Debug */
|
|
102
|
-
function debugCircle(pos,
|
|
102
|
+
function debugCircle(pos, size=0, color='#fff', time=0, fill=false)
|
|
103
103
|
{
|
|
104
104
|
ASSERT(typeof color === 'string', 'pass in css color strings');
|
|
105
|
-
debugPrimitives.push({pos, size
|
|
105
|
+
debugPrimitives.push({pos, size, color, time:new Timer(time), angle:0, fill});
|
|
106
106
|
}
|
|
107
107
|
|
|
108
108
|
/** Draw a debug point in world space
|
|
@@ -302,7 +302,7 @@ function debugRender()
|
|
|
302
302
|
{
|
|
303
303
|
const drawPos = centerPos.add(vec2(j*stickScale*2, i*stickScale*3));
|
|
304
304
|
const stickPos = drawPos.add(sticks[j].scale(stickScale));
|
|
305
|
-
debugCircle(drawPos, stickScale, '#fff7',0,true);
|
|
305
|
+
debugCircle(drawPos, stickScale*2, '#fff7',0,true);
|
|
306
306
|
debugLine(drawPos, stickPos, '#f00');
|
|
307
307
|
debugPoint(stickPos, '#f00');
|
|
308
308
|
}
|
|
@@ -310,7 +310,7 @@ function debugRender()
|
|
|
310
310
|
{
|
|
311
311
|
const drawPos = centerPos.add(vec2(j*buttonScale*2, i*stickScale*3-stickScale-buttonScale));
|
|
312
312
|
const pressed = gamepad.buttons[j].pressed;
|
|
313
|
-
debugCircle(drawPos, buttonScale, pressed ? '#f00' : '#fff7', 0, true);
|
|
313
|
+
debugCircle(drawPos, buttonScale*2, pressed ? '#f00' : '#fff7', 0, true);
|
|
314
314
|
debugText(''+j, drawPos, .2);
|
|
315
315
|
}
|
|
316
316
|
}
|
|
@@ -410,7 +410,7 @@ function debugRender()
|
|
|
410
410
|
{
|
|
411
411
|
// circle
|
|
412
412
|
overlayContext.beginPath();
|
|
413
|
-
overlayContext.arc(0, 0, p.size*cameraScale, 0, 9);
|
|
413
|
+
overlayContext.arc(0, 0, p.size*cameraScale/2, 0, 9);
|
|
414
414
|
p.fill && overlayContext.fill();
|
|
415
415
|
overlayContext.stroke();
|
|
416
416
|
}
|
|
@@ -524,7 +524,7 @@ function debugVideoCaptureStart()
|
|
|
524
524
|
const chunks = [];
|
|
525
525
|
debugVideoCaptureTrack = stream.getVideoTracks()[0];
|
|
526
526
|
if (debugVideoCaptureTrack.applyConstraints)
|
|
527
|
-
debugVideoCaptureTrack.applyConstraints({frameRate:
|
|
527
|
+
debugVideoCaptureTrack.applyConstraints({frameRate:60}); // force 60 fps
|
|
528
528
|
debugVideoCapture = new MediaRecorder(stream, {mimeType:'video/webm;codecs=vp8'});
|
|
529
529
|
debugVideoCapture.ondataavailable = (e)=> chunks.push(e.data);
|
|
530
530
|
debugVideoCapture.onstop = ()=>
|
package/src/engineDraw.js
CHANGED
|
@@ -136,8 +136,9 @@ class TileInfo
|
|
|
136
136
|
* @param {Vector2} [size=tileSizeDefault] - Size of tile in pixels
|
|
137
137
|
* @param {number} [textureIndex] - Texture index to use
|
|
138
138
|
* @param {number} [padding] - How many pixels padding around tiles
|
|
139
|
+
* @param {number} [bleedScale] - How many pixels smaller to draw tiles
|
|
139
140
|
*/
|
|
140
|
-
constructor(pos=vec2(), size=tileSizeDefault, textureIndex=0, padding=0)
|
|
141
|
+
constructor(pos=vec2(), size=tileSizeDefault, textureIndex=0, padding=0, bleedScale=tileFixBleedScale)
|
|
141
142
|
{
|
|
142
143
|
/** @property {Vector2} - Top left corner of tile in pixels */
|
|
143
144
|
this.pos = pos.copy();
|
|
@@ -149,6 +150,8 @@ class TileInfo
|
|
|
149
150
|
this.padding = padding;
|
|
150
151
|
/** @property {TextureInfo} - The texture info for this tile */
|
|
151
152
|
this.textureInfo = textureInfos[this.textureIndex];
|
|
153
|
+
/** @property {float} - Shrinks tile by this many pixels to prevent neighbors bleeding */
|
|
154
|
+
this.bleedScale = bleedScale;
|
|
152
155
|
}
|
|
153
156
|
|
|
154
157
|
/** Returns a copy of this tile offset by a vector
|
|
@@ -156,7 +159,7 @@ class TileInfo
|
|
|
156
159
|
* @return {TileInfo}
|
|
157
160
|
*/
|
|
158
161
|
offset(offset)
|
|
159
|
-
{ return new TileInfo(this.pos.add(offset), this.size, this.textureIndex); }
|
|
162
|
+
{ return new TileInfo(this.pos.add(offset), this.size, this.textureIndex, this.padding, this.bleedScale); }
|
|
160
163
|
|
|
161
164
|
/** Returns a copy of this tile offset by a number of animation frames
|
|
162
165
|
* @param {number} frame - Offset to apply in animation frames
|
|
@@ -179,6 +182,8 @@ class TileInfo
|
|
|
179
182
|
this.pos = new Vector2;
|
|
180
183
|
this.size = new Vector2(image.width, image.height);
|
|
181
184
|
this.textureInfo = new TextureInfo(image, glTexture);
|
|
185
|
+
// do not use padding or bleed
|
|
186
|
+
this.bleedScale = this.padding = 0;
|
|
182
187
|
return this;
|
|
183
188
|
}
|
|
184
189
|
}
|
|
@@ -236,6 +241,7 @@ function drawTile(pos, size=new Vector2(1), tileInfo, color=WHITE,
|
|
|
236
241
|
ASSERT(!context || !useWebGL, 'context only supported in canvas 2D mode');
|
|
237
242
|
|
|
238
243
|
const textureInfo = tileInfo && tileInfo.textureInfo;
|
|
244
|
+
const bleedScale = tileInfo ? tileInfo.bleedScale : 0;
|
|
239
245
|
if (useWebGL)
|
|
240
246
|
{
|
|
241
247
|
if (screenSpace)
|
|
@@ -253,10 +259,10 @@ function drawTile(pos, size=new Vector2(1), tileInfo, color=WHITE,
|
|
|
253
259
|
const w = tileInfo.size.x * sizeInverse.x;
|
|
254
260
|
const h = tileInfo.size.y * sizeInverse.y;
|
|
255
261
|
glSetTexture(textureInfo.glTexture);
|
|
256
|
-
if (
|
|
262
|
+
if (bleedScale)
|
|
257
263
|
{
|
|
258
|
-
const tileImageFixBleedX = sizeInverse.x*
|
|
259
|
-
const tileImageFixBleedY = sizeInverse.y*
|
|
264
|
+
const tileImageFixBleedX = sizeInverse.x*bleedScale;
|
|
265
|
+
const tileImageFixBleedY = sizeInverse.y*bleedScale;
|
|
260
266
|
glDraw(pos.x, pos.y, mirror ? -size.x : size.x, size.y, angle,
|
|
261
267
|
x + tileImageFixBleedX, y + tileImageFixBleedY,
|
|
262
268
|
x - tileImageFixBleedX + w, y - tileImageFixBleedY + h,
|
|
@@ -287,7 +293,7 @@ function drawTile(pos, size=new Vector2(1), tileInfo, color=WHITE,
|
|
|
287
293
|
// calculate uvs and render
|
|
288
294
|
const x = tileInfo.pos.x, y = tileInfo.pos.y;
|
|
289
295
|
const w = tileInfo.size.x, h = tileInfo.size.y;
|
|
290
|
-
drawImageColor(context, textureInfo.image, x, y, w, h, -.5, -.5, 1, 1, color, additiveColor);
|
|
296
|
+
drawImageColor(context, textureInfo.image, x, y, w, h, -.5, -.5, 1, 1, color, additiveColor, bleedScale);
|
|
291
297
|
}
|
|
292
298
|
else
|
|
293
299
|
{
|
|
@@ -775,15 +781,16 @@ function combineCanvases()
|
|
|
775
781
|
* @param {number} dHeight
|
|
776
782
|
* @param {Color} color
|
|
777
783
|
* @param {Color} [additiveColor]
|
|
784
|
+
* @param {number} [bleedScale] - How much to shrink the source, used to fix bleeding
|
|
778
785
|
* @memberof Draw */
|
|
779
|
-
function drawImageColor(context, image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight, color, additiveColor)
|
|
786
|
+
function drawImageColor(context, image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight, color, additiveColor, bleedScale=0)
|
|
780
787
|
{
|
|
781
788
|
function isWhite(c) { return c.r >= 1 && c.g >= 1 && c.b >= 1; }
|
|
782
789
|
function isBlack(c) { return c.r <= 0 && c.g <= 0 && c.b <= 0 && c.a <= 0; }
|
|
783
|
-
const sx2 =
|
|
784
|
-
const sy2 =
|
|
785
|
-
const sWidth2 = sWidth - 2*
|
|
786
|
-
const sHeight2 = sHeight - 2*
|
|
790
|
+
const sx2 = bleedScale;
|
|
791
|
+
const sy2 = bleedScale;
|
|
792
|
+
const sWidth2 = sWidth - 2*bleedScale;
|
|
793
|
+
const sHeight2 = sHeight - 2*bleedScale;
|
|
787
794
|
if (!canvasColorTiles || (additiveColor ? isWhite(color.add(additiveColor)) && additiveColor.a <= 0 : isWhite(color)))
|
|
788
795
|
{
|
|
789
796
|
// white texture with no additive alpha, no need to tint
|
package/src/engineExport.js
CHANGED
|
@@ -53,6 +53,7 @@ export
|
|
|
53
53
|
cameraAngle,
|
|
54
54
|
cameraScale,
|
|
55
55
|
canvasColorTiles,
|
|
56
|
+
canvasClearColor,
|
|
56
57
|
canvasMaxSize,
|
|
57
58
|
canvasFixedSize,
|
|
58
59
|
canvasPixelated,
|
|
@@ -94,6 +95,7 @@ export
|
|
|
94
95
|
setCameraAngle,
|
|
95
96
|
setCameraScale,
|
|
96
97
|
setCanvasColorTiles,
|
|
98
|
+
setCanvasClearColor,
|
|
97
99
|
setCanvasMaxSize,
|
|
98
100
|
setCanvasFixedSize,
|
|
99
101
|
setCanvasPixelated,
|
|
@@ -192,8 +194,6 @@ export
|
|
|
192
194
|
MAGENTA,
|
|
193
195
|
|
|
194
196
|
// Draw
|
|
195
|
-
textureInfos,
|
|
196
|
-
drawCount,
|
|
197
197
|
tile,
|
|
198
198
|
TileInfo,
|
|
199
199
|
TextureInfo,
|
|
@@ -204,6 +204,8 @@ export
|
|
|
204
204
|
overlayCanvas,
|
|
205
205
|
overlayContext,
|
|
206
206
|
mainCanvasSize,
|
|
207
|
+
textureInfos,
|
|
208
|
+
drawCount,
|
|
207
209
|
screenToWorld,
|
|
208
210
|
worldToScreen,
|
|
209
211
|
drawTile,
|
package/src/engineSettings.js
CHANGED
|
@@ -37,6 +37,11 @@ let cameraScale = 32;
|
|
|
37
37
|
* @memberof Settings */
|
|
38
38
|
let canvasColorTiles = true;
|
|
39
39
|
|
|
40
|
+
/** Color to clear the canvas to before render
|
|
41
|
+
* @type {Color}
|
|
42
|
+
* @memberof Draw */
|
|
43
|
+
let canvasClearColor = CLEAR_BLACK;
|
|
44
|
+
|
|
40
45
|
/** The max size of the canvas, centered if window is larger
|
|
41
46
|
* @type {Vector2}
|
|
42
47
|
* @default Vector2(1920,1080)
|
|
@@ -315,6 +320,11 @@ function setCameraScale(scale) { cameraScale = scale; }
|
|
|
315
320
|
* @memberof Settings */
|
|
316
321
|
function setCanvasColorTiles(colorTiles) { canvasColorTiles = colorTiles; }
|
|
317
322
|
|
|
323
|
+
/** Set color to clear the canvas to before render
|
|
324
|
+
* @param {Color} color
|
|
325
|
+
* @memberof Settings */
|
|
326
|
+
function setCanvasClearColor(color) { canvasClearColor = color; }
|
|
327
|
+
|
|
318
328
|
/** Set max size of the canvas
|
|
319
329
|
* @param {Vector2} size
|
|
320
330
|
* @memberof Settings */
|
package/src/engineUtilities.js
CHANGED
|
@@ -985,6 +985,10 @@ class Timer
|
|
|
985
985
|
* @return {number} */
|
|
986
986
|
getPercent() { return this.isSet()? 1-percent(this.time - time, 0, this.setTime) : 0; }
|
|
987
987
|
|
|
988
|
+
/** Get the time this timer was set to, returns 0 if not set
|
|
989
|
+
* @return {number} */
|
|
990
|
+
getSetTime() { return this.isSet() ? this.setTime : 0; }
|
|
991
|
+
|
|
988
992
|
/** Returns this timer expressed as a string
|
|
989
993
|
* @return {string} */
|
|
990
994
|
toString() { if (debug) { return this.isSet() ? Math.abs(this.get()) + ' seconds ' + (this.get()<0 ? 'before' : 'after' ) : 'unset'; }}
|
package/src/engineWebGL.js
CHANGED
|
@@ -260,7 +260,8 @@ function glSetTexture(texture, wrap=false)
|
|
|
260
260
|
return;
|
|
261
261
|
|
|
262
262
|
glFlush();
|
|
263
|
-
|
|
263
|
+
glActiveTexture = texture;
|
|
264
|
+
glContext.bindTexture(glContext.TEXTURE_2D, glActiveTexture);
|
|
264
265
|
|
|
265
266
|
// set wrap mode
|
|
266
267
|
const wrapMode = wrap ? glContext.REPEAT : glContext.CLAMP_TO_EDGE;
|
|
@@ -310,6 +311,7 @@ function glCreateProgram(vsSource, fsSource)
|
|
|
310
311
|
}
|
|
311
312
|
|
|
312
313
|
/** Create WebGL texture from an image and init the texture settings
|
|
314
|
+
* Restores the active texture when done
|
|
313
315
|
* @param {HTMLImageElement|HTMLCanvasElement|OffscreenCanvas} [image]
|
|
314
316
|
* @return {WebGLTexture}
|
|
315
317
|
* @memberof WebGL */
|
|
@@ -319,30 +321,29 @@ function glCreateTexture(image)
|
|
|
319
321
|
|
|
320
322
|
// build the texture
|
|
321
323
|
const texture = glContext.createTexture();
|
|
322
|
-
|
|
324
|
+
let mipMap = false;
|
|
323
325
|
if (image && image.width)
|
|
324
326
|
{
|
|
325
327
|
glSetTextureData(texture, image);
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
// use mipmap filtering
|
|
329
|
-
glContext.generateMipmap(glContext.TEXTURE_2D);
|
|
330
|
-
glContext.texParameteri(glContext.TEXTURE_2D, glContext.TEXTURE_MIN_FILTER, glContext.LINEAR_MIPMAP_LINEAR);
|
|
331
|
-
glContext.texParameteri(glContext.TEXTURE_2D, glContext.TEXTURE_MAG_FILTER, glContext.LINEAR);
|
|
332
|
-
return texture;
|
|
333
|
-
}
|
|
328
|
+
glContext.bindTexture(glContext.TEXTURE_2D, texture);
|
|
329
|
+
mipMap = !tilesPixelated && isPowerOfTwo(image.width) && isPowerOfTwo(image.height);
|
|
334
330
|
}
|
|
335
331
|
else
|
|
336
332
|
{
|
|
337
333
|
// create a white texture
|
|
338
334
|
const whitePixel = new Uint8Array([255, 255, 255, 255]);
|
|
335
|
+
glContext.bindTexture(glContext.TEXTURE_2D, texture);
|
|
339
336
|
glContext.texImage2D(glContext.TEXTURE_2D, 0, glContext.RGBA, 1, 1, 0, glContext.RGBA, glContext.UNSIGNED_BYTE, whitePixel);
|
|
340
337
|
}
|
|
341
338
|
|
|
342
339
|
// set texture filtering
|
|
343
|
-
const
|
|
344
|
-
|
|
345
|
-
glContext.texParameteri(glContext.TEXTURE_2D, glContext.TEXTURE_MAG_FILTER,
|
|
340
|
+
const magFilter = tilesPixelated ? glContext.NEAREST : glContext.LINEAR;
|
|
341
|
+
const minFilter = mipMap ? glContext.LINEAR_MIPMAP_LINEAR : magFilter;
|
|
342
|
+
glContext.texParameteri(glContext.TEXTURE_2D, glContext.TEXTURE_MAG_FILTER, magFilter);
|
|
343
|
+
glContext.texParameteri(glContext.TEXTURE_2D, glContext.TEXTURE_MIN_FILTER, minFilter);
|
|
344
|
+
if (mipMap)
|
|
345
|
+
glContext.generateMipmap(glContext.TEXTURE_2D);
|
|
346
|
+
glContext.bindTexture(glContext.TEXTURE_2D, glActiveTexture); // rebind active texture
|
|
346
347
|
return texture;
|
|
347
348
|
}
|
|
348
349
|
|
|
@@ -355,7 +356,7 @@ function glDeleteTexture(texture)
|
|
|
355
356
|
glContext.deleteTexture(texture);
|
|
356
357
|
}
|
|
357
358
|
|
|
358
|
-
/** Set WebGL texture data from an image
|
|
359
|
+
/** Set WebGL texture data from an image, restores the active texture when done
|
|
359
360
|
* @param {WebGLTexture} texture
|
|
360
361
|
* @param {HTMLImageElement|HTMLCanvasElement|OffscreenCanvas} image
|
|
361
362
|
* @memberof WebGL */
|
|
@@ -367,6 +368,7 @@ function glSetTextureData(texture, image)
|
|
|
367
368
|
ASSERT(!!image && image.width > 0, 'Invalid image data.');
|
|
368
369
|
glContext.bindTexture(glContext.TEXTURE_2D, texture);
|
|
369
370
|
glContext.texImage2D(glContext.TEXTURE_2D, 0, glContext.RGBA, glContext.RGBA, glContext.UNSIGNED_BYTE, image);
|
|
371
|
+
glContext.bindTexture(glContext.TEXTURE_2D, glActiveTexture); // rebind active texture
|
|
370
372
|
}
|
|
371
373
|
|
|
372
374
|
/** Draw all sprites and clear out the buffer, called automatically by the system whenever necessary
|
|
@@ -512,7 +514,7 @@ function glDrawPoints(points, rgba)
|
|
|
512
514
|
|
|
513
515
|
// setup triangle strip with degenerate verts at start and end
|
|
514
516
|
let offset = glBatchCount * gl_INDICES_PER_POLY_VERTEX;
|
|
515
|
-
for(let i = vertCount; i--;)
|
|
517
|
+
for (let i = vertCount; i--;)
|
|
516
518
|
{
|
|
517
519
|
const j = clamp(i-1, 0, vertCount-3);
|
|
518
520
|
const point = points[j];
|
|
@@ -540,7 +542,7 @@ function glDrawColoredPoints(points, pointColors)
|
|
|
540
542
|
|
|
541
543
|
// setup triangle strip with degenerate verts at start and end
|
|
542
544
|
let offset = glBatchCount * gl_INDICES_PER_POLY_VERTEX;
|
|
543
|
-
for(let i = vertCount; i--;)
|
|
545
|
+
for (let i = vertCount; i--;)
|
|
544
546
|
{
|
|
545
547
|
const j = clamp(i-1, 0, vertCount-3);
|
|
546
548
|
const point = points[j];
|