littlejsengine 1.16.2 → 1.17.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.
- package/dist/littlejs.d.ts +291 -246
- package/dist/littlejs.esm.js +1520 -1271
- package/dist/littlejs.esm.min.js +1 -1
- package/dist/littlejs.js +1178 -920
- package/dist/littlejs.min.js +1 -1
- package/dist/littlejs.release.js +1170 -912
- package/examples/box2d/gameObjects.js +4 -4
- package/examples/breakout/game.js +5 -6
- package/examples/electron/index.html +2 -2
- package/examples/electron/tiles.png +0 -0
- package/examples/htmlMenu/tiles.png +0 -0
- package/examples/index.html +9 -8
- package/examples/logo.png +0 -0
- package/examples/module/build.bat +7 -0
- package/examples/module/build.js +121 -0
- package/examples/module/tiles.png +0 -0
- package/examples/platformer/game.js +1 -1
- package/examples/platformer/gameEffects.js +25 -29
- package/examples/platformer/gameLevel.js +27 -28
- package/examples/puzzle/game.js +2 -2
- package/examples/shorts/base.html +4 -1
- package/examples/shorts/box2dPool.js +2 -2
- package/examples/shorts/box2dTileLayer.js +48 -0
- package/examples/shorts/clock.js +3 -3
- package/examples/shorts/fontImage.js +4 -3
- package/examples/shorts/music.js +2 -2
- package/examples/shorts/musicPlayer.js +2 -2
- package/examples/shorts/parallax.js +1 -1
- package/examples/shorts/sequencer.js +1 -1
- package/examples/shorts/shapes.js +1 -1
- package/examples/shorts/texture.js +10 -6
- package/examples/shorts/tiles.png +0 -0
- package/examples/shorts/tiltedView.js +2 -0
- package/examples/starter/index.html +2 -2
- package/examples/starter/tiles.png +0 -0
- package/examples/typescript/tiles.png +0 -0
- package/examples/uiSystem/game.js +1 -1
- package/examples/uiSystem/tiles.png +0 -0
- package/package.json +5 -5
- package/plugins/box2d.js +167 -63
- package/plugins/postProcess.js +47 -28
- package/plugins/uiSystem.js +18 -18
- package/plugins/zzfxm.js +2 -2
- package/reference.md +4 -3
- package/src/engine.js +182 -181
- package/src/engineAudio.js +47 -63
- package/src/engineDebug.js +8 -8
- package/src/engineDraw.js +184 -124
- package/src/engineExport.js +325 -334
- package/src/engineFont.png +0 -0
- package/src/engineInput.js +18 -24
- package/src/engineMath.js +24 -113
- package/src/engineObject.js +27 -26
- package/src/engineParticles.js +2 -2
- package/src/engineTileLayer.js +229 -192
- package/src/engineUtilities.js +100 -4
- package/src/engineWebGL.js +124 -73
package/src/engineDraw.js
CHANGED
|
@@ -77,10 +77,11 @@ let drawCount;
|
|
|
77
77
|
* Create a tile info object using a grid based system
|
|
78
78
|
* - This can take vecs or floats for easier use and conversion
|
|
79
79
|
* - If an index is passed in, the tile size and index will determine the position
|
|
80
|
-
* @param {Vector2|number} [
|
|
80
|
+
* @param {Vector2|number} [index=0] - Index of the tile in 1d or 2d form
|
|
81
81
|
* @param {Vector2|number} [size] - Size of tile in pixels
|
|
82
|
-
* @param {number} [
|
|
82
|
+
* @param {TextureInfo|number} [texture] - Texture index or info to use
|
|
83
83
|
* @param {number} [padding] - How many pixels padding around tiles
|
|
84
|
+
* @param {number} [bleed] - How many pixels smaller to draw tiles
|
|
84
85
|
* @return {TileInfo}
|
|
85
86
|
* @example
|
|
86
87
|
* tile(2) // a tile at index 2 using the default tile size of 16
|
|
@@ -88,36 +89,43 @@ let drawCount;
|
|
|
88
89
|
* tile(1, 16, 3) // a tile at index 1 of size 16 on texture 3
|
|
89
90
|
* tile(vec2(4,8), vec2(30,10)) // a tile at index (4,8) with a size of (30,10)
|
|
90
91
|
* @memberof Draw */
|
|
91
|
-
function tile(
|
|
92
|
+
function tile(index=new Vector2, size=tileDefaultSize, texture=0, padding=tileDefaultPadding, bleed=tileDefaultBleed)
|
|
92
93
|
{
|
|
93
|
-
|
|
94
|
-
|
|
94
|
+
ASSERT(isVector2(index) || typeof index === 'number', 'index must be a vec2 or number');
|
|
95
|
+
ASSERT(isVector2(size) || typeof size === 'number', 'size must be a vec2 or number');
|
|
96
|
+
ASSERT(isNumber(texture) || texture instanceof TextureInfo, 'texture must be a number or TextureInfo');
|
|
97
|
+
ASSERT(isNumber(padding), 'padding must be a number');
|
|
98
|
+
|
|
99
|
+
if (headlessMode) return new TileInfo;
|
|
95
100
|
|
|
96
|
-
// if size is a number, make it a vector
|
|
97
101
|
if (typeof size === 'number')
|
|
98
102
|
{
|
|
103
|
+
// if size is a number, make it a vector
|
|
99
104
|
ASSERT(size > 0);
|
|
100
105
|
size = new Vector2(size, size);
|
|
101
106
|
}
|
|
102
107
|
|
|
103
108
|
// create tile info object
|
|
104
|
-
const
|
|
109
|
+
const textureInfo = typeof texture === 'number' ?
|
|
110
|
+
textureInfos[texture] : texture;
|
|
105
111
|
|
|
106
112
|
// get the position of the tile
|
|
107
|
-
const textureInfo = textureInfos[textureIndex];
|
|
108
|
-
ASSERT(!!textureInfo, 'Texture not loaded');
|
|
109
113
|
const sizePaddedX = size.x + padding*2;
|
|
110
114
|
const sizePaddedY = size.y + padding*2;
|
|
111
|
-
|
|
115
|
+
let x, y;
|
|
116
|
+
if (typeof index === 'number')
|
|
112
117
|
{
|
|
113
118
|
const cols = textureInfo.size.x / sizePaddedX |0;
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
tileInfo.pos.set(posX*sizePaddedX+padding, posY*sizePaddedY+padding);
|
|
119
|
+
x = index % cols;
|
|
120
|
+
y = index / cols |0;
|
|
117
121
|
}
|
|
118
122
|
else
|
|
119
|
-
|
|
120
|
-
|
|
123
|
+
{
|
|
124
|
+
x = index.x;
|
|
125
|
+
y = index.y;
|
|
126
|
+
}
|
|
127
|
+
const pos = new Vector2(x*sizePaddedX + padding, y*sizePaddedY + padding);
|
|
128
|
+
return new TileInfo(pos, size, textureInfo, padding, bleed);
|
|
121
129
|
}
|
|
122
130
|
|
|
123
131
|
/**
|
|
@@ -127,24 +135,22 @@ function tile(pos=new Vector2, size=tileDefaultSize, textureIndex=0, padding=til
|
|
|
127
135
|
class TileInfo
|
|
128
136
|
{
|
|
129
137
|
/** Create a tile info object
|
|
130
|
-
* @param {Vector2} [pos=(
|
|
138
|
+
* @param {Vector2} [pos=vec2()] - Top left corner of tile in pixels
|
|
131
139
|
* @param {Vector2} [size] - Size of tile in pixels
|
|
132
|
-
* @param {
|
|
133
|
-
* @param {number}
|
|
134
|
-
* @param {number}
|
|
140
|
+
* @param {TextureInfo} [textureInfo] - Texture info to use
|
|
141
|
+
* @param {number} [padding] - How many pixels padding around tiles
|
|
142
|
+
* @param {number} [bleed] - How many pixels smaller to draw tiles
|
|
135
143
|
*/
|
|
136
|
-
constructor(pos=vec2(), size=tileDefaultSize,
|
|
144
|
+
constructor(pos=vec2(), size=tileDefaultSize, textureInfo=textureInfos[0], padding=tileDefaultPadding, bleed=tileDefaultBleed)
|
|
137
145
|
{
|
|
138
146
|
/** @property {Vector2} - Top left corner of tile in pixels */
|
|
139
147
|
this.pos = pos.copy();
|
|
140
148
|
/** @property {Vector2} - Size of tile in pixels */
|
|
141
149
|
this.size = size.copy();
|
|
142
|
-
/** @property {number} - Texture index to use */
|
|
143
|
-
this.textureIndex = textureIndex;
|
|
144
150
|
/** @property {number} - How many pixels padding around tiles */
|
|
145
151
|
this.padding = padding;
|
|
146
152
|
/** @property {TextureInfo} - The texture info for this tile */
|
|
147
|
-
this.textureInfo =
|
|
153
|
+
this.textureInfo = textureInfo;
|
|
148
154
|
/** @property {number} - Shrinks tile by this many pixels to prevent neighbors bleeding */
|
|
149
155
|
this.bleed = bleed;
|
|
150
156
|
}
|
|
@@ -154,7 +160,7 @@ class TileInfo
|
|
|
154
160
|
* @return {TileInfo}
|
|
155
161
|
*/
|
|
156
162
|
offset(offset)
|
|
157
|
-
{ return new TileInfo(this.pos.add(offset), this.size, this.
|
|
163
|
+
{ return new TileInfo(this.pos.add(offset), this.size, this.textureInfo, this.padding, this.bleed); }
|
|
158
164
|
|
|
159
165
|
/** Returns a copy of this tile offset by a number of animation frames
|
|
160
166
|
* @param {number} frame - Offset to apply in animation frames
|
|
@@ -163,23 +169,33 @@ class TileInfo
|
|
|
163
169
|
frame(frame)
|
|
164
170
|
{
|
|
165
171
|
ASSERT(typeof frame === 'number');
|
|
166
|
-
|
|
172
|
+
const w = this.size.x + this.padding*2;
|
|
173
|
+
const x = frame*w;
|
|
174
|
+
ASSERT(x < this.textureInfo.size.x, 'frame extends beyond texture width!');
|
|
175
|
+
return this.offset(new Vector2(x));
|
|
167
176
|
}
|
|
168
177
|
|
|
169
178
|
/**
|
|
170
179
|
* Set this tile to use a full image in a texture info
|
|
171
|
-
* @param {TextureInfo} textureInfo
|
|
180
|
+
* @param {TextureInfo} [textureInfo]
|
|
172
181
|
* @return {TileInfo}
|
|
173
182
|
*/
|
|
174
|
-
setFullImage(textureInfo)
|
|
183
|
+
setFullImage(textureInfo=this.textureInfo)
|
|
175
184
|
{
|
|
185
|
+
this.textureInfo = textureInfo;
|
|
176
186
|
this.pos = new Vector2;
|
|
177
187
|
this.size = textureInfo.size.copy();
|
|
178
|
-
this.textureInfo = textureInfo;
|
|
179
|
-
// do not use padding or bleed
|
|
180
188
|
this.bleed = this.padding = 0;
|
|
181
189
|
return this;
|
|
182
190
|
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Returns a tile info for an index using this tile as refrence
|
|
194
|
+
* @param {Vector2|number} [index=0]
|
|
195
|
+
* @return {TileInfo}
|
|
196
|
+
*/
|
|
197
|
+
tile(index)
|
|
198
|
+
{ return tile(index, this.size, this.textureInfo, this.padding, this.bleed); }
|
|
183
199
|
}
|
|
184
200
|
|
|
185
201
|
/**
|
|
@@ -220,19 +236,19 @@ class TextureInfo
|
|
|
220
236
|
///////////////////////////////////////////////////////////////////////////////
|
|
221
237
|
// Drawing functions
|
|
222
238
|
|
|
223
|
-
/** Draw textured tile centered in world space
|
|
224
|
-
* @param {Vector2} pos
|
|
225
|
-
* @param {Vector2} [size=(1
|
|
226
|
-
* @param {TileInfo} [tileInfo]
|
|
227
|
-
* @param {Color} [color=
|
|
228
|
-
* @param {number} [angle]
|
|
229
|
-
* @param {boolean} [mirror]
|
|
230
|
-
* @param {Color} [additiveColor]
|
|
239
|
+
/** Draw textured tile centered in world space
|
|
240
|
+
* @param {Vector2} pos - Center of the tile in world space
|
|
241
|
+
* @param {Vector2} [size=vec2(1)] - Size of the tile in world space
|
|
242
|
+
* @param {TileInfo} [tileInfo] - Tile info to use, untextured if undefined
|
|
243
|
+
* @param {Color} [color=WHITE] - Color to modulate with
|
|
244
|
+
* @param {number} [angle] - Angle to rotate by
|
|
245
|
+
* @param {boolean} [mirror] - Is image flipped along the Y axis?
|
|
246
|
+
* @param {Color} [additiveColor] - Additive color to be applied if any
|
|
231
247
|
* @param {boolean} [useWebGL=glEnable] - Use accelerated WebGL rendering?
|
|
232
248
|
* @param {boolean} [screenSpace=false] - Are the pos and size are in screen space?
|
|
233
249
|
* @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} [context] - Canvas 2D context to draw to
|
|
234
250
|
* @memberof Draw */
|
|
235
|
-
function drawTile(pos, size=
|
|
251
|
+
function drawTile(pos, size=vec2(1), tileInfo, color=WHITE,
|
|
236
252
|
angle=0, mirror, additiveColor, useWebGL=glEnable, screenSpace, context)
|
|
237
253
|
{
|
|
238
254
|
ASSERT(isVector2(pos), 'pos must be a vec2');
|
|
@@ -242,7 +258,7 @@ function drawTile(pos, size=new Vector2(1), tileInfo, color=WHITE,
|
|
|
242
258
|
ASSERT(!additiveColor || isColor(additiveColor), 'additiveColor must be a color');
|
|
243
259
|
ASSERT(!context || !useWebGL, 'context only supported in canvas 2D mode');
|
|
244
260
|
|
|
245
|
-
const textureInfo = tileInfo
|
|
261
|
+
const textureInfo = tileInfo?.textureInfo;
|
|
246
262
|
const bleed = tileInfo?.bleed ?? 0;
|
|
247
263
|
if (useWebGL && glEnable)
|
|
248
264
|
{
|
|
@@ -307,8 +323,8 @@ function drawTile(pos, size=new Vector2(1), tileInfo, color=WHITE,
|
|
|
307
323
|
|
|
308
324
|
/** Draw colored rect centered on pos
|
|
309
325
|
* @param {Vector2} pos
|
|
310
|
-
* @param {Vector2} [size=(1
|
|
311
|
-
* @param {Color} [color=
|
|
326
|
+
* @param {Vector2} [size=vec2(1)]
|
|
327
|
+
* @param {Color} [color=WHITE]
|
|
312
328
|
* @param {number} [angle]
|
|
313
329
|
* @param {boolean} [useWebGL=glEnable]
|
|
314
330
|
* @param {boolean} [screenSpace]
|
|
@@ -321,9 +337,9 @@ function drawRect(pos, size, color, angle, useWebGL, screenSpace, context)
|
|
|
321
337
|
|
|
322
338
|
/** Draw a rect centered on pos with a gradient from top to bottom
|
|
323
339
|
* @param {Vector2} pos
|
|
324
|
-
* @param {Vector2} [size=(1
|
|
325
|
-
* @param {Color} [colorTop=
|
|
326
|
-
* @param {Color} [colorBottom=
|
|
340
|
+
* @param {Vector2} [size=vec2(1)]
|
|
341
|
+
* @param {Color} [colorTop=WHITE]
|
|
342
|
+
* @param {Color} [colorBottom=BLACK]
|
|
327
343
|
* @param {number} [angle]
|
|
328
344
|
* @param {boolean} [useWebGL=glEnable]
|
|
329
345
|
* @param {boolean} [screenSpace]
|
|
@@ -385,9 +401,9 @@ function drawRectGradient(pos, size, colorTop=WHITE, colorBottom=BLACK, angle=0,
|
|
|
385
401
|
/** Draw connected lines between a series of points
|
|
386
402
|
* @param {Array<Vector2>} points
|
|
387
403
|
* @param {number} [width]
|
|
388
|
-
* @param {Color} [color=
|
|
404
|
+
* @param {Color} [color=WHITE]
|
|
389
405
|
* @param {boolean} [wrap] - Should the last point connect to the first?
|
|
390
|
-
* @param {Vector2} [pos=(
|
|
406
|
+
* @param {Vector2} [pos=vec2()] - Offset to apply
|
|
391
407
|
* @param {number} [angle] - Angle to rotate by
|
|
392
408
|
* @param {boolean} [useWebGL=glEnable]
|
|
393
409
|
* @param {boolean} [screenSpace]
|
|
@@ -422,13 +438,9 @@ function drawLineList(points, width=.1, color, wrap=false, pos=vec2(), angle=0,
|
|
|
422
438
|
for (let i=0; i<points.length; ++i)
|
|
423
439
|
{
|
|
424
440
|
const point = points[i];
|
|
425
|
-
|
|
426
|
-
context.lineTo(point.x, point.y);
|
|
427
|
-
else
|
|
428
|
-
context.moveTo(point.x, point.y);
|
|
441
|
+
context.lineTo(point.x, point.y);
|
|
429
442
|
}
|
|
430
|
-
|
|
431
|
-
context.closePath();
|
|
443
|
+
wrap && context.closePath();
|
|
432
444
|
context.stroke();
|
|
433
445
|
}, screenSpace, context);
|
|
434
446
|
}
|
|
@@ -438,8 +450,8 @@ function drawLineList(points, width=.1, color, wrap=false, pos=vec2(), angle=0,
|
|
|
438
450
|
* @param {Vector2} posA
|
|
439
451
|
* @param {Vector2} posB
|
|
440
452
|
* @param {number} [width]
|
|
441
|
-
* @param {Color} [color=
|
|
442
|
-
* @param {Vector2} [pos=(
|
|
453
|
+
* @param {Color} [color=WHITE]
|
|
454
|
+
* @param {Vector2} [pos=vec2()] - Offset to apply
|
|
443
455
|
* @param {number} [angle] - Angle to rotate by
|
|
444
456
|
* @param {boolean} [useWebGL=glEnable]
|
|
445
457
|
* @param {boolean} [screenSpace]
|
|
@@ -458,12 +470,12 @@ function drawLine(posA, posB, width=.1, color, pos=vec2(), angle=0, useWebGL, sc
|
|
|
458
470
|
|
|
459
471
|
/** Draw colored regular polygon using passed in number of sides
|
|
460
472
|
* @param {Vector2} pos
|
|
461
|
-
* @param {Vector2} [size=(1
|
|
473
|
+
* @param {Vector2} [size=vec2(1)]
|
|
462
474
|
* @param {number} [sides]
|
|
463
|
-
* @param {Color} [color=
|
|
475
|
+
* @param {Color} [color=WHITE]
|
|
464
476
|
* @param {number} [angle]
|
|
465
477
|
* @param {number} [lineWidth]
|
|
466
|
-
* @param {Color} [lineColor=
|
|
478
|
+
* @param {Color} [lineColor=BLACK]
|
|
467
479
|
* @param {boolean} [useWebGL=glEnable]
|
|
468
480
|
* @param {boolean} [screenSpace]
|
|
469
481
|
* @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} [context]
|
|
@@ -486,10 +498,10 @@ function drawRegularPoly(pos, size=vec2(1), sides=3, color=WHITE, lineWidth=0, l
|
|
|
486
498
|
|
|
487
499
|
/** Draw colored polygon using passed in points
|
|
488
500
|
* @param {Array<Vector2>} points - Array of Vector2 points
|
|
489
|
-
* @param {Color} [color=
|
|
501
|
+
* @param {Color} [color=WHITE]
|
|
490
502
|
* @param {number} [lineWidth]
|
|
491
|
-
* @param {Color} [lineColor=
|
|
492
|
-
* @param {Vector2} [pos=(
|
|
503
|
+
* @param {Color} [lineColor=BLACK]
|
|
504
|
+
* @param {Vector2} [pos=vec2()] - Offset to apply
|
|
493
505
|
* @param {number} [angle] - Angle to rotate by
|
|
494
506
|
* @param {boolean} [useWebGL=glEnable]
|
|
495
507
|
* @param {boolean} [screenSpace]
|
|
@@ -536,11 +548,11 @@ function drawPoly(points, color=WHITE, lineWidth=0, lineColor=BLACK, pos=vec2(),
|
|
|
536
548
|
|
|
537
549
|
/** Draw colored ellipse using passed in point
|
|
538
550
|
* @param {Vector2} pos
|
|
539
|
-
* @param {Vector2} [size=(1
|
|
540
|
-
* @param {Color} [color=
|
|
551
|
+
* @param {Vector2} [size=vec2(1)] - Width and height diameter
|
|
552
|
+
* @param {Color} [color=WHITE]
|
|
541
553
|
* @param {number} [angle]
|
|
542
554
|
* @param {number} [lineWidth]
|
|
543
|
-
* @param {Color} [lineColor=
|
|
555
|
+
* @param {Color} [lineColor=BLACK]
|
|
544
556
|
* @param {boolean} [useWebGL=glEnable]
|
|
545
557
|
* @param {boolean} [screenSpace]
|
|
546
558
|
* @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} [context]
|
|
@@ -552,9 +564,12 @@ function drawEllipse(pos, size=vec2(1), color=WHITE, angle=0, lineWidth=0, lineC
|
|
|
552
564
|
ASSERT(isColor(color) && isColor(lineColor), 'color is invalid');
|
|
553
565
|
ASSERT(isNumber(angle), 'angle must be a number');
|
|
554
566
|
ASSERT(isNumber(lineWidth), 'lineWidth must be a number');
|
|
555
|
-
ASSERT(lineWidth >= 0
|
|
567
|
+
ASSERT(lineWidth >= 0, 'lineWidth must be a positive value or 0');
|
|
556
568
|
ASSERT(!context || !useWebGL, 'context only supported in canvas 2D mode');
|
|
557
569
|
|
|
570
|
+
// clamp line width to prevent artifacts
|
|
571
|
+
lineWidth = clamp(lineWidth, 0, Math.min(size.x, size.y));
|
|
572
|
+
|
|
558
573
|
if (useWebGL && glEnable)
|
|
559
574
|
{
|
|
560
575
|
// draw as a regular polygon
|
|
@@ -582,9 +597,9 @@ function drawEllipse(pos, size=vec2(1), color=WHITE, angle=0, lineWidth=0, lineC
|
|
|
582
597
|
/** Draw colored circle using passed in point
|
|
583
598
|
* @param {Vector2} pos
|
|
584
599
|
* @param {number} [size=1] - Diameter
|
|
585
|
-
* @param {Color} [color=
|
|
600
|
+
* @param {Color} [color=WHITE]
|
|
586
601
|
* @param {number} [lineWidth=0]
|
|
587
|
-
* @param {Color} [lineColor=
|
|
602
|
+
* @param {Color} [lineColor=BLACK]
|
|
588
603
|
* @param {boolean} [useWebGL=glEnable]
|
|
589
604
|
* @param {boolean} [screenSpace]
|
|
590
605
|
* @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} [context]
|
|
@@ -639,9 +654,9 @@ function drawCanvas2D(pos, size, angle=0, mirror=false, drawFunction, screenSpac
|
|
|
639
654
|
* @param {string|number} text
|
|
640
655
|
* @param {Vector2} pos
|
|
641
656
|
* @param {number} [size]
|
|
642
|
-
* @param {Color} [color=
|
|
657
|
+
* @param {Color} [color=WHITE]
|
|
643
658
|
* @param {number} [lineWidth]
|
|
644
|
-
* @param {Color} [lineColor=
|
|
659
|
+
* @param {Color} [lineColor=BLACK]
|
|
645
660
|
* @param {CanvasTextAlign} [textAlign='center']
|
|
646
661
|
* @param {string} [font=fontDefault]
|
|
647
662
|
* @param {string} [fontStyle]
|
|
@@ -665,10 +680,10 @@ function drawText(text, pos, size=1, color, lineWidth=0, lineColor, textAlign, f
|
|
|
665
680
|
* Automatically splits new lines into rows
|
|
666
681
|
* @param {string|number} text
|
|
667
682
|
* @param {Vector2} pos
|
|
668
|
-
* @param {number}
|
|
669
|
-
* @param {Color} [color=
|
|
683
|
+
* @param {number} size
|
|
684
|
+
* @param {Color} [color=WHITE]
|
|
670
685
|
* @param {number} [lineWidth]
|
|
671
|
-
* @param {Color} [lineColor=
|
|
686
|
+
* @param {Color} [lineColor=BLACK]
|
|
672
687
|
* @param {CanvasTextAlign} [textAlign]
|
|
673
688
|
* @param {string} [font=fontDefault]
|
|
674
689
|
* @param {string} [fontStyle]
|
|
@@ -676,7 +691,7 @@ function drawText(text, pos, size=1, color, lineWidth=0, lineColor, textAlign, f
|
|
|
676
691
|
* @param {number} [angle]
|
|
677
692
|
* @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} [context=drawContext]
|
|
678
693
|
* @memberof Draw */
|
|
679
|
-
function drawTextScreen(text, pos, size
|
|
694
|
+
function drawTextScreen(text, pos, size, color=WHITE, lineWidth=0, lineColor=BLACK, textAlign='center', font=fontDefault, fontStyle='', maxWidth, angle=0, context=drawContext)
|
|
680
695
|
{
|
|
681
696
|
ASSERT(isString(text), 'text must be a string');
|
|
682
697
|
ASSERT(isVector2(pos), 'pos must be a vec2');
|
|
@@ -800,7 +815,7 @@ function worldToScreenDelta(worldDelta)
|
|
|
800
815
|
|
|
801
816
|
/** Convert screen space transform to world space
|
|
802
817
|
* @param {Vector2} screenPos
|
|
803
|
-
* @param {Vector2} screenSize
|
|
818
|
+
* @param {Vector2} screenSize
|
|
804
819
|
* @param {number} [screenAngle]
|
|
805
820
|
* @return {[Vector2, Vector2, number]} - [pos, size, angle]
|
|
806
821
|
* @memberof Draw */
|
|
@@ -861,10 +876,9 @@ function isOnScreen(pos, size=0)
|
|
|
861
876
|
* @param {boolean} [additive]
|
|
862
877
|
* @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} [context]
|
|
863
878
|
* @memberof Draw */
|
|
864
|
-
function setBlendMode(additive=false, context)
|
|
879
|
+
function setBlendMode(additive=false, context=drawContext)
|
|
865
880
|
{
|
|
866
881
|
glAdditive = additive;
|
|
867
|
-
context ||= drawContext;
|
|
868
882
|
context.globalCompositeOperation = additive ? 'lighter' : 'source-over';
|
|
869
883
|
}
|
|
870
884
|
|
|
@@ -879,7 +893,6 @@ function combineCanvases()
|
|
|
879
893
|
workContext.fillRect(0,0,w,h); // remove background alpha
|
|
880
894
|
glCopyToContext(workContext);
|
|
881
895
|
workContext.drawImage(mainCanvas, 0, 0);
|
|
882
|
-
mainCanvas.width |= 0;
|
|
883
896
|
mainContext.drawImage(workCanvas, 0, 0);
|
|
884
897
|
}
|
|
885
898
|
|
|
@@ -984,17 +997,22 @@ function setCursor(cursorStyle = 'auto')
|
|
|
984
997
|
|
|
985
998
|
///////////////////////////////////////////////////////////////////////////////
|
|
986
999
|
|
|
1000
|
+
/** Engine font image, 8x8 font provided by the engine
|
|
1001
|
+
* @type {FontImage}
|
|
1002
|
+
* @memberof Draw */
|
|
987
1003
|
let engineFontImage;
|
|
988
1004
|
|
|
989
1005
|
/**
|
|
990
|
-
* Font Image Object - Draw text
|
|
1006
|
+
* Font Image Object - Draw text by using tiles in an image
|
|
991
1007
|
* - 96 characters (from space to tilde) are stored in an image
|
|
992
|
-
* -
|
|
993
|
-
* -
|
|
1008
|
+
* - A 8x8 default engine font is supplied for general use
|
|
1009
|
+
* - This system is WebGL enabled for fast text rendering
|
|
1010
|
+
* - Fonts can also be colored and scaled along each axis
|
|
1011
|
+
*
|
|
994
1012
|
* @memberof Draw
|
|
995
1013
|
* @example
|
|
996
1014
|
* // use built in font
|
|
997
|
-
* const font =
|
|
1015
|
+
* const font = engineFontImage;
|
|
998
1016
|
*
|
|
999
1017
|
* // draw text
|
|
1000
1018
|
* font.drawTextScreen('LittleJS\nHello World!', vec2(200, 50));
|
|
@@ -1002,68 +1020,110 @@ let engineFontImage;
|
|
|
1002
1020
|
class FontImage
|
|
1003
1021
|
{
|
|
1004
1022
|
/** Create an image font
|
|
1005
|
-
* @param {
|
|
1006
|
-
* @param {Vector2} [tileSize=(8,8)] - Size of the font source tiles
|
|
1007
|
-
* @param {Vector2} [paddingSize=(0,1)] - How much space between characters
|
|
1023
|
+
* @param {TileInfo} tileInfo - Tile info of first characeter in font
|
|
1008
1024
|
*/
|
|
1009
|
-
constructor(
|
|
1025
|
+
constructor(tileInfo)
|
|
1010
1026
|
{
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
{
|
|
1014
|
-
|
|
1015
|
-
engineFontImage.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQAAAAAYAQAAAAA9+x6JAAAAAnRSTlMAAHaTzTgAAAGiSURBVHjaZZABhxxBEIUf6ECLBdFY+Q0PMNgf0yCgsSAGZcT9sgIPtBWwIA5wgAPEoHUyJeeSlW+gjK+fegWwtROWpVQEyWh2npdpBmTUFVhb29RINgLIukoXr5LIAvYQ5ve+1FqWEMqNKTX3FAJHyQDRZvmKWubAACcv5z5Gtg2oyCWE+Yk/8JZQX1jTTCpKAFGIgza+dJCNBF2UskRlsgwitHbSV0QLgt9sTPtsRlvJjEr8C/FARWA2bJ/TtJ7lko34dNDn6usJUMzuErP89UUBJbWeozrwLLncXczd508deAjLWipLO4Q5XGPcJvPu92cNDaN0P5G1FL0nSOzddZOrJ6rNhbXGmeDvO3TF7DeJWl4bvaYQTNHCTeuqKZmbjHaSOFes+IX/+IhHrnAkXOAsfn24EM68XieIECoccD4KZLk/odiwzeo2rovYdhvb2HYFgyznJyDpYJdYOmfXgVdJTaUi4xA2uWYNYec9BLeqdl9EsoTw582mSFDX2DxVLbNt9U3YYoeatBad1c2Tj8t2akrjaIGJNywKB/7h75/gN3vCMSaadIUTAAAAAElFTkSuQmCC';
|
|
1016
|
-
}
|
|
1017
|
-
|
|
1018
|
-
this.image = image || engineFontImage;
|
|
1019
|
-
this.tileSize = tileSize;
|
|
1020
|
-
this.paddingSize = paddingSize;
|
|
1027
|
+
ASSERT(!!tileInfo, 'tileInfo is required for FontImage');
|
|
1028
|
+
|
|
1029
|
+
/** @property {TileInfo} - Tile info for the font */
|
|
1030
|
+
this.tileInfo = tileInfo.frame(0);
|
|
1021
1031
|
}
|
|
1022
1032
|
|
|
1023
1033
|
/** Draw text in world space using the image font
|
|
1024
|
-
* @param {string|number}
|
|
1034
|
+
* @param {string|number} text
|
|
1025
1035
|
* @param {Vector2} pos
|
|
1026
|
-
* @param {number}
|
|
1027
|
-
* @param {boolean} [center]
|
|
1028
|
-
* @param {
|
|
1036
|
+
* @param {Vector2|number} [size]
|
|
1037
|
+
* @param {boolean} [center=true]
|
|
1038
|
+
* @param {Color} [color=WHITE]
|
|
1039
|
+
* @param {boolean} [useWebGL=glEnable]
|
|
1040
|
+
* @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} [context]
|
|
1029
1041
|
*/
|
|
1030
|
-
drawText(text, pos,
|
|
1042
|
+
drawText(text, pos, size=1, center, color, useWebGL, context)
|
|
1031
1043
|
{
|
|
1032
|
-
|
|
1044
|
+
ASSERT(isVector2(size) || typeof size === 'number', 'size must be a vec2 or number');
|
|
1045
|
+
|
|
1046
|
+
if (typeof size === 'number')
|
|
1047
|
+
{
|
|
1048
|
+
// if size is a number, make it a vector
|
|
1049
|
+
ASSERT(size > 0);
|
|
1050
|
+
size *= cameraScale;
|
|
1051
|
+
size = new Vector2(size, size);
|
|
1052
|
+
}
|
|
1053
|
+
else
|
|
1054
|
+
size = size.scale(cameraScale);
|
|
1055
|
+
this.drawTextScreen(text, worldToScreen(pos), size, center, color, useWebGL, context);
|
|
1033
1056
|
}
|
|
1034
1057
|
|
|
1035
1058
|
/** Draw text in screen space using the image font
|
|
1036
|
-
* @param {string|number}
|
|
1059
|
+
* @param {string|number} text
|
|
1037
1060
|
* @param {Vector2} pos
|
|
1038
|
-
* @param {number}
|
|
1061
|
+
* @param {Vector2|number} size
|
|
1039
1062
|
* @param {boolean} [center]
|
|
1040
|
-
* @param {
|
|
1063
|
+
* @param {Color} [color=WHITE]
|
|
1064
|
+
* @param {boolean} [useWebGL=glEnable]
|
|
1065
|
+
* @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} [context]
|
|
1041
1066
|
*/
|
|
1042
|
-
drawTextScreen(text, pos,
|
|
1067
|
+
drawTextScreen(text, pos, size, center=true, color=WHITE, useWebGL=glEnable, context)
|
|
1043
1068
|
{
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1069
|
+
ASSERT(isString(text), 'text must be a string');
|
|
1070
|
+
ASSERT(isVector2(pos), 'pos must be a vec2');
|
|
1071
|
+
ASSERT(isVector2(size) || typeof size === 'number', 'size must be a vec2 or number');
|
|
1072
|
+
ASSERT(isColor(color), 'color must be a color');
|
|
1073
|
+
|
|
1074
|
+
// if size is a number, make it a vector
|
|
1075
|
+
size = typeof size === 'number' ? new Vector2(size, size) : size;
|
|
1076
|
+
|
|
1077
|
+
// precache objects for drawing
|
|
1078
|
+
const drawPos = new Vector2;
|
|
1079
|
+
const tileInfo = this.tileInfo;
|
|
1080
|
+
const padding = tileInfo.padding;
|
|
1081
|
+
const sizePaddedX = tileInfo.size.x + padding*2;
|
|
1082
|
+
const sizePaddedY = tileInfo.size.y + padding*2;
|
|
1083
|
+
const cols = tileInfo.textureInfo.size.x / sizePaddedX |0;
|
|
1084
|
+
|
|
1085
|
+
// draw each line of text
|
|
1086
|
+
(text+'').split('\n').forEach((line, j)=>
|
|
1049
1087
|
{
|
|
1050
|
-
const centerOffset = center ? line.length * size.x
|
|
1051
|
-
for (let
|
|
1088
|
+
const centerOffset = center ? (line.length-1) * size.x / 2 : 0;
|
|
1089
|
+
for (let i=line.length; i--;)
|
|
1052
1090
|
{
|
|
1053
|
-
//
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
charCode
|
|
1057
|
-
|
|
1058
|
-
// get the
|
|
1059
|
-
const
|
|
1060
|
-
const
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1091
|
+
// get the character index
|
|
1092
|
+
const charCode = line.charCodeAt(i);
|
|
1093
|
+
const index = charCode < 32 || charCode > 127 ?
|
|
1094
|
+
95 : charCode - 32; // handle out of range characters
|
|
1095
|
+
|
|
1096
|
+
// get the position of the tile
|
|
1097
|
+
const x = index % cols;
|
|
1098
|
+
const y = index / cols |0;
|
|
1099
|
+
tileInfo.pos.x = x*sizePaddedX + padding;
|
|
1100
|
+
tileInfo.pos.y = y*sizePaddedY + padding;
|
|
1101
|
+
|
|
1102
|
+
// draw the tile
|
|
1103
|
+
drawPos.x = pos.x + i * size.x - centerOffset |0;
|
|
1104
|
+
drawPos.y = pos.y + j * size.y |0;
|
|
1105
|
+
drawTile(drawPos, size, tileInfo, color, 0, false, undefined, useWebGL, true, context);
|
|
1065
1106
|
}
|
|
1066
1107
|
});
|
|
1067
|
-
context.restore();
|
|
1068
1108
|
}
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
// load engine font, called automatically on startup
|
|
1112
|
+
function fontImageInit()
|
|
1113
|
+
{
|
|
1114
|
+
return new Promise(resolve =>
|
|
1115
|
+
{
|
|
1116
|
+
// create the engine font
|
|
1117
|
+
const image = new Image;
|
|
1118
|
+
image.onerror = image.onload = ()=>
|
|
1119
|
+
{
|
|
1120
|
+
const tilePos=vec2(), tileSize=vec2(8), padding=1, bleed=0;
|
|
1121
|
+
const textureInfo = new TextureInfo(image);
|
|
1122
|
+
const tileInfo = new TileInfo(tilePos, tileSize, textureInfo, padding, bleed);
|
|
1123
|
+
engineFontImage = new FontImage(tileInfo);
|
|
1124
|
+
resolve();
|
|
1125
|
+
}
|
|
1126
|
+
image.crossOrigin = 'anonymous';
|
|
1127
|
+
image.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAUAAAAAeAQMAAABnrVXaAAAABlBMVEUAAAD///+l2Z/dAAAAAXRSTlMAQObYZgAAAjpJREFUOMu9kzFu2zAUhn+CAROgqrk+B2l0BWYxMjlXeYaAtFtbdA1sGgHqRQfI0CNkSG5AwYB0BQ8d5Bsomwah6CPVeGg6tEPzAxLwyI+P78cP4u9lNO9OoMKnLMOobG5020/yaj/MrRcCGh1gBbyiLTPJEYaIiom5KM9Jq7KgynMGtb6L4GL4MF2H4LQKCXTvDVw2I4MsgZT7QLExdiutH+D08VOP3INXRrWX1/mmpbkNgAPYRVANb4xpcegYvhiNbIXauQICEjBuYLfMakaakWQeXxiZ0VDtuJCKs3ztMV59QtsHJNcRxDzfdL21ty3PrfIcXTN+E+GFAv6T5nbT9jd50/WFxb5ksdAv49qS6ouymG66ji08UMT6moykYLAo+V0j23GN4m829ZySAD5K7QsBfQTvOG8eE+gTeGYRAmnNAubN3hf5Zv9tJWDHp/VTuaSm7SN4fyINQqaNO3RMVxvpSPXnOChnRNvFcGY0gnwiPswYwTKVPE0zVtX3mTEIOoFzaqLrGuJaV+Uqumb71fVk/VoOH3cdLNQP/FHi8hV0CQNoqBZsUPlLPMsdCJro9QAaQQ0woDy9BJm0eTxCFnO9srcYlhNVlfR2EyTrph1uUtbUtAJifwRgrKuYdXVHeb0YI3QpawohQHkloI3J5FuVwI5ORxC9k2Tuz9Ir1IjgeIPGMHYkAZe2RuYkmWFmt3gGbTPOmBUWVTmRmHtGrfpzG/yuQNOKa6gBB/WA9khitPgl6/GP+gl2Af6tCbvaygAAAABJRU5ErkJggg==';
|
|
1128
|
+
});
|
|
1069
1129
|
}
|