littlejsengine 1.14.2 → 1.14.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/README.md +3 -3
- package/dist/littlejs.d.ts +59 -19
- package/dist/littlejs.esm.js +239 -90
- package/dist/littlejs.esm.min.js +1 -1
- package/dist/littlejs.js +233 -90
- package/dist/littlejs.min.js +1 -1
- package/dist/littlejs.release.js +224 -81
- package/examples/box2d/game.js +4 -4
- package/examples/breakoutTutorial/README.md +1 -1
- package/examples/breakoutTutorial/game.js +1 -1
- package/examples/electron/build.js +1 -1
- package/examples/empty/game.js +1 -1
- package/examples/htmlMenu/index.html +7 -7
- package/examples/index.html +3 -3
- package/examples/platformer/gameEffects.js +1 -7
- package/examples/shorts/music.js +3 -3
- package/examples/shorts/shapes.js +12 -10
- package/examples/stress/index.html +14 -12
- package/examples/typescript/build.js +1 -1
- package/package.json +1 -1
- package/plugins/box2d.js +3 -3
- package/reference.md +9 -7
- package/src/engine.js +7 -3
- package/src/engineBuild.js +2 -2
- package/src/engineDebug.js +9 -9
- package/src/engineDraw.js +140 -18
- package/src/engineExport.js +6 -0
- package/src/engineObject.js +3 -3
- package/src/engineTileLayer.js +0 -1
- package/src/engineUtilities.js +4 -4
- package/src/engineWebGL.js +66 -48
- package/copyToGithub.bat +0 -28
package/dist/littlejs.js
CHANGED
|
@@ -33,7 +33,7 @@ const engineName = 'LittleJS';
|
|
|
33
33
|
* @type {string}
|
|
34
34
|
* @default
|
|
35
35
|
* @memberof Engine */
|
|
36
|
-
const engineVersion = '1.14.
|
|
36
|
+
const engineVersion = '1.14.5';
|
|
37
37
|
|
|
38
38
|
/** Frames per second to update
|
|
39
39
|
* @type {number}
|
|
@@ -249,8 +249,7 @@ async function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, game
|
|
|
249
249
|
overlayContext.fillStyle = '#fff';
|
|
250
250
|
overlayContext.fillText(text, mainCanvas.width-2, 2);
|
|
251
251
|
}
|
|
252
|
-
|
|
253
|
-
drawCount = 0;
|
|
252
|
+
drawCount = 0;
|
|
254
253
|
}
|
|
255
254
|
requestAnimationFrame(engineUpdate);
|
|
256
255
|
}
|
|
@@ -284,6 +283,11 @@ async function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, game
|
|
|
284
283
|
|
|
285
284
|
// save canvas size
|
|
286
285
|
mainCanvasSize = vec2(mainCanvas.width, mainCanvas.height);
|
|
286
|
+
|
|
287
|
+
// set default line join and cap
|
|
288
|
+
const lineJoin = 'round', lineCap = 'round';
|
|
289
|
+
mainContext.lineJoin = overlayContext.lineJoin = lineJoin;
|
|
290
|
+
mainContext.lineCap = overlayContext.lineCap = lineCap;
|
|
287
291
|
}
|
|
288
292
|
|
|
289
293
|
// wait for gameInit to load
|
|
@@ -745,15 +749,15 @@ function debugPoly(pos, points, color='#fff', time=0, angle=0, fill=false)
|
|
|
745
749
|
|
|
746
750
|
/** Draw a debug circle in world space
|
|
747
751
|
* @param {Vector2} pos
|
|
748
|
-
* @param {number} [
|
|
752
|
+
* @param {number} [size] - diameter
|
|
749
753
|
* @param {string} [color]
|
|
750
754
|
* @param {number} [time]
|
|
751
755
|
* @param {boolean} [fill]
|
|
752
756
|
* @memberof Debug */
|
|
753
|
-
function debugCircle(pos,
|
|
757
|
+
function debugCircle(pos, size=0, color='#fff', time=0, fill=false)
|
|
754
758
|
{
|
|
755
759
|
ASSERT(typeof color === 'string', 'pass in css color strings');
|
|
756
|
-
debugPrimitives.push({pos, size
|
|
760
|
+
debugPrimitives.push({pos, size, color, time:new Timer(time), angle:0, fill});
|
|
757
761
|
}
|
|
758
762
|
|
|
759
763
|
/** Draw a debug point in world space
|
|
@@ -772,13 +776,13 @@ function debugPoint(pos, color, time, angle)
|
|
|
772
776
|
* @param {Vector2} posA
|
|
773
777
|
* @param {Vector2} posB
|
|
774
778
|
* @param {string} [color]
|
|
775
|
-
* @param {number} [
|
|
779
|
+
* @param {number} [width]
|
|
776
780
|
* @param {number} [time]
|
|
777
781
|
* @memberof Debug */
|
|
778
|
-
function debugLine(posA, posB, color,
|
|
782
|
+
function debugLine(posA, posB, color, width=.1, time)
|
|
779
783
|
{
|
|
780
784
|
const halfDelta = vec2((posB.x - posA.x)/2, (posB.y - posA.y)/2);
|
|
781
|
-
const size = vec2(
|
|
785
|
+
const size = vec2(width, halfDelta.length()*2);
|
|
782
786
|
debugRect(posA.add(halfDelta), size, color, time, halfDelta.angle(), true);
|
|
783
787
|
}
|
|
784
788
|
|
|
@@ -953,7 +957,7 @@ function debugRender()
|
|
|
953
957
|
{
|
|
954
958
|
const drawPos = centerPos.add(vec2(j*stickScale*2, i*stickScale*3));
|
|
955
959
|
const stickPos = drawPos.add(sticks[j].scale(stickScale));
|
|
956
|
-
debugCircle(drawPos, stickScale, '#fff7',0,true);
|
|
960
|
+
debugCircle(drawPos, stickScale*2, '#fff7',0,true);
|
|
957
961
|
debugLine(drawPos, stickPos, '#f00');
|
|
958
962
|
debugPoint(stickPos, '#f00');
|
|
959
963
|
}
|
|
@@ -961,7 +965,7 @@ function debugRender()
|
|
|
961
965
|
{
|
|
962
966
|
const drawPos = centerPos.add(vec2(j*buttonScale*2, i*stickScale*3-stickScale-buttonScale));
|
|
963
967
|
const pressed = gamepad.buttons[j].pressed;
|
|
964
|
-
debugCircle(drawPos, buttonScale, pressed ? '#f00' : '#fff7', 0, true);
|
|
968
|
+
debugCircle(drawPos, buttonScale*2, pressed ? '#f00' : '#fff7', 0, true);
|
|
965
969
|
debugText(''+j, drawPos, .2);
|
|
966
970
|
}
|
|
967
971
|
}
|
|
@@ -1061,7 +1065,7 @@ function debugRender()
|
|
|
1061
1065
|
{
|
|
1062
1066
|
// circle
|
|
1063
1067
|
overlayContext.beginPath();
|
|
1064
|
-
overlayContext.arc(0, 0, p.size*cameraScale, 0, 9);
|
|
1068
|
+
overlayContext.arc(0, 0, p.size*cameraScale/2, 0, 9);
|
|
1065
1069
|
p.fill && overlayContext.fill();
|
|
1066
1070
|
overlayContext.stroke();
|
|
1067
1071
|
}
|
|
@@ -1619,10 +1623,10 @@ function vec2(x=0, y) { return new Vector2(x, y === undefined ? x : y); }
|
|
|
1619
1623
|
* @param {any} v
|
|
1620
1624
|
* @return {boolean}
|
|
1621
1625
|
* @memberof Utilities */
|
|
1622
|
-
function isVector2(v) { return v instanceof Vector2; }
|
|
1626
|
+
function isVector2(v) { return v instanceof Vector2 && v.isValid(); }
|
|
1623
1627
|
|
|
1624
1628
|
// vector2 asserts
|
|
1625
|
-
function ASSERT_VECTOR2_VALID(v) { ASSERT(isVector2(v)
|
|
1629
|
+
function ASSERT_VECTOR2_VALID(v) { ASSERT(isVector2(v), 'Vector2 is invalid.', v); }
|
|
1626
1630
|
function ASSERT_NUMBER_VALID(n) { ASSERT(isNumber(n), 'Number is invalid.', n); }
|
|
1627
1631
|
function ASSERT_VECTOR2_NORMAL(v)
|
|
1628
1632
|
{
|
|
@@ -1880,10 +1884,10 @@ function hsl(h, s, l, a) { return new Color().setHSLA(h, s, l, a); }
|
|
|
1880
1884
|
* @param {any} c
|
|
1881
1885
|
* @return {boolean}
|
|
1882
1886
|
* @memberof Utilities */
|
|
1883
|
-
function isColor(c) { return c instanceof Color; }
|
|
1887
|
+
function isColor(c) { return c instanceof Color && c.isValid(); }
|
|
1884
1888
|
|
|
1885
1889
|
// color asserts
|
|
1886
|
-
function ASSERT_COLOR_VALID(c) { ASSERT(isColor(c)
|
|
1890
|
+
function ASSERT_COLOR_VALID(c) { ASSERT(isColor(c), 'Color is invalid.', c); }
|
|
1887
1891
|
|
|
1888
1892
|
/**
|
|
1889
1893
|
* Color object (red, green, blue, alpha) with some helpful functions
|
|
@@ -2816,11 +2820,11 @@ class EngineObject
|
|
|
2816
2820
|
constructor(pos=vec2(), size=vec2(1), tileInfo, angle=0, color=new Color, renderOrder=0)
|
|
2817
2821
|
{
|
|
2818
2822
|
// check passed in params
|
|
2819
|
-
ASSERT(isVector2(pos)
|
|
2820
|
-
ASSERT(isVector2(size)
|
|
2823
|
+
ASSERT(isVector2(pos), 'object pos should be a vec2');
|
|
2824
|
+
ASSERT(isVector2(size), 'object size should be a vec2');
|
|
2821
2825
|
ASSERT(!tileInfo || tileInfo instanceof TileInfo, 'object tileInfo should be a TileInfo or undefined');
|
|
2822
2826
|
ASSERT(typeof angle === 'number' && isFinite(angle), 'object angle should be a number');
|
|
2823
|
-
ASSERT(isColor(color)
|
|
2827
|
+
ASSERT(isColor(color), 'object color should be a valid rgba color');
|
|
2824
2828
|
ASSERT(typeof renderOrder === 'number', 'object renderOrder should be a number');
|
|
2825
2829
|
|
|
2826
2830
|
/** @property {Vector2} - World space position of the object */
|
|
@@ -3314,7 +3318,9 @@ let mainCanvasSize = vec2();
|
|
|
3314
3318
|
* @memberof Draw */
|
|
3315
3319
|
let textureInfos = [];
|
|
3316
3320
|
|
|
3317
|
-
|
|
3321
|
+
/** Keeps track of how many draw calls there were each frame for debugging
|
|
3322
|
+
* @type {number}
|
|
3323
|
+
* @memberof Draw */
|
|
3318
3324
|
let drawCount;
|
|
3319
3325
|
|
|
3320
3326
|
///////////////////////////////////////////////////////////////////////////////
|
|
@@ -3469,8 +3475,8 @@ class TextureInfo
|
|
|
3469
3475
|
function drawTile(pos, size=new Vector2(1), tileInfo, color=WHITE,
|
|
3470
3476
|
angle=0, mirror, additiveColor, useWebGL=glEnable, screenSpace, context)
|
|
3471
3477
|
{
|
|
3472
|
-
ASSERT(isVector2(pos)
|
|
3473
|
-
ASSERT(isVector2(size)
|
|
3478
|
+
ASSERT(isVector2(pos), 'drawTile pos should be a vec2');
|
|
3479
|
+
ASSERT(isVector2(size), 'drawTile size should be a vec2');
|
|
3474
3480
|
ASSERT(isColor(color) && (!additiveColor || isColor(additiveColor)), 'drawTile color is invalid');
|
|
3475
3481
|
ASSERT(isNumber(angle), 'drawTile angle should be a number');
|
|
3476
3482
|
ASSERT(!context || !useWebGL, 'context only supported in canvas 2D mode');
|
|
@@ -3518,7 +3524,7 @@ function drawTile(pos, size=new Vector2(1), tileInfo, color=WHITE,
|
|
|
3518
3524
|
else
|
|
3519
3525
|
{
|
|
3520
3526
|
// normal canvas 2D rendering method (slower)
|
|
3521
|
-
|
|
3527
|
+
++drawCount;
|
|
3522
3528
|
size = new Vector2(size.x, -size.y); // fix upside down sprites
|
|
3523
3529
|
drawCanvas2D(pos, size, angle, mirror, (context)=>
|
|
3524
3530
|
{
|
|
@@ -3554,10 +3560,124 @@ function drawRect(pos, size, color, angle, useWebGL, screenSpace, context)
|
|
|
3554
3560
|
drawTile(pos, size, undefined, color, angle, false, undefined, useWebGL, screenSpace, context);
|
|
3555
3561
|
}
|
|
3556
3562
|
|
|
3563
|
+
/** Draw a rect centered on pos with a gradient from top to bottom
|
|
3564
|
+
* @param {Vector2} pos
|
|
3565
|
+
* @param {Vector2} [size=(1,1)]
|
|
3566
|
+
* @param {Color} [colorTop=(1,1,1,1)]
|
|
3567
|
+
* @param {Color} [colorBottom=(0,0,0,1)]
|
|
3568
|
+
* @param {number} [angle]
|
|
3569
|
+
* @param {boolean} [useWebGL=glEnable]
|
|
3570
|
+
* @param {boolean} [screenSpace]
|
|
3571
|
+
* @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} [context]
|
|
3572
|
+
* @memberof Draw */
|
|
3573
|
+
function drawRectGradient(pos, size, colorTop=WHITE, colorBottom=BLACK, angle=0, useWebGL=glEnable, screenSpace=false, context)
|
|
3574
|
+
{
|
|
3575
|
+
ASSERT(isVector2(pos), 'drawRectGradient pos should be a vec2');
|
|
3576
|
+
ASSERT(isVector2(size), 'drawRectGradient size should be a vec2');
|
|
3577
|
+
ASSERT(isColor(colorTop) && isColor(colorBottom), 'drawRectGradient color is invalid');
|
|
3578
|
+
ASSERT(isNumber(angle), 'drawRectGradient angle should be a number');
|
|
3579
|
+
ASSERT(!context || !useWebGL, 'context only supported in canvas 2D mode');
|
|
3580
|
+
if (useWebGL)
|
|
3581
|
+
{
|
|
3582
|
+
if (screenSpace)
|
|
3583
|
+
{
|
|
3584
|
+
// convert to world space
|
|
3585
|
+
pos = screenToWorld(pos);
|
|
3586
|
+
size = size.scale(1/cameraScale);
|
|
3587
|
+
}
|
|
3588
|
+
// build 4 corner points for the rectangle
|
|
3589
|
+
const points = [], colors = [];
|
|
3590
|
+
const halfSizeX = size.x/2, halfSizeY = size.y/2;
|
|
3591
|
+
const colorTopInt = colorTop.rgbaInt();
|
|
3592
|
+
const colorBottomInt = colorBottom.rgbaInt();
|
|
3593
|
+
const c = Math.cos(-angle), s = Math.sin(-angle);
|
|
3594
|
+
for (let i=4; i--;)
|
|
3595
|
+
{
|
|
3596
|
+
const x = i & 1 ? halfSizeX : -halfSizeX;
|
|
3597
|
+
const y = i & 2 ? halfSizeY : -halfSizeY;
|
|
3598
|
+
const rx = x * c - y * s;
|
|
3599
|
+
const ry = x * s + y * c;
|
|
3600
|
+
const color = i & 2 ? colorTopInt : colorBottomInt;
|
|
3601
|
+
points.push(vec2(pos.x + rx, pos.y + ry));
|
|
3602
|
+
colors.push(color);
|
|
3603
|
+
}
|
|
3604
|
+
glDrawColoredPoints(points, colors);
|
|
3605
|
+
}
|
|
3606
|
+
else
|
|
3607
|
+
{
|
|
3608
|
+
// normal canvas 2D rendering method (slower)
|
|
3609
|
+
++drawCount;
|
|
3610
|
+
size = new Vector2(size.x, -size.y); // fix upside down sprites
|
|
3611
|
+
drawCanvas2D(pos, size, angle, false, (context)=>
|
|
3612
|
+
{
|
|
3613
|
+
// if no tile info, use untextured rect
|
|
3614
|
+
const gradient = context.createLinearGradient(0, -.5, 0, .5);
|
|
3615
|
+
gradient.addColorStop(0, colorTop.toString());
|
|
3616
|
+
gradient.addColorStop(1, colorBottom.toString());
|
|
3617
|
+
context.fillStyle = gradient;
|
|
3618
|
+
context.fillRect(-.5, -.5, 1, 1);
|
|
3619
|
+
}, screenSpace, context);
|
|
3620
|
+
}
|
|
3621
|
+
}
|
|
3622
|
+
|
|
3623
|
+
/** Draw connected lines between a series of points
|
|
3624
|
+
* @param {Array<Vector2>} points
|
|
3625
|
+
* @param {number} [width]
|
|
3626
|
+
* @param {Color} [color=(1,1,1,1)]
|
|
3627
|
+
* @param {boolean} [wrap] - Should the last point connect to the first?
|
|
3628
|
+
* @param {Vector2} [pos=(0,0)] - Offset to apply
|
|
3629
|
+
* @param {number} [angle] - Angle to rotate by
|
|
3630
|
+
* @param {boolean} [useWebGL=glEnable]
|
|
3631
|
+
* @param {boolean} [screenSpace]
|
|
3632
|
+
* @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} [context]
|
|
3633
|
+
* @memberof Draw */
|
|
3634
|
+
function drawLineList(points, width=.1, color, wrap=false, pos=vec2(), angle=0, useWebGL=glEnable, screenSpace, context)
|
|
3635
|
+
{
|
|
3636
|
+
ASSERT(Array.isArray(points), 'drawLineList points should be an array');
|
|
3637
|
+
ASSERT(isNumber(width), 'drawLineList width should be a number');
|
|
3638
|
+
ASSERT(isColor(color), 'drawLineList color is invalid');
|
|
3639
|
+
ASSERT(isVector2(pos), 'drawLineList pos should be a vec2');
|
|
3640
|
+
ASSERT(isNumber(angle), 'drawLineList angle should be a number');
|
|
3641
|
+
ASSERT(!context || !useWebGL, 'context only supported in canvas 2D mode');
|
|
3642
|
+
if (useWebGL)
|
|
3643
|
+
{
|
|
3644
|
+
let scale = 1;
|
|
3645
|
+
if (screenSpace)
|
|
3646
|
+
{
|
|
3647
|
+
// convert to world space
|
|
3648
|
+
pos = screenToWorld(pos);
|
|
3649
|
+
scale = 1/cameraScale;
|
|
3650
|
+
}
|
|
3651
|
+
glDrawOutlineTransform(points, color.rgbaInt(), width, pos.x, pos.y, scale, scale, angle, wrap);
|
|
3652
|
+
}
|
|
3653
|
+
else
|
|
3654
|
+
{
|
|
3655
|
+
// normal canvas 2D rendering method (slower)
|
|
3656
|
+
++drawCount;
|
|
3657
|
+
drawCanvas2D(pos, vec2(1), angle, false, (context)=>
|
|
3658
|
+
{
|
|
3659
|
+
context.strokeStyle = color.toString();
|
|
3660
|
+
context.lineWidth = width;
|
|
3661
|
+
context.beginPath();
|
|
3662
|
+
for (let i=0; i<points.length; ++i)
|
|
3663
|
+
{
|
|
3664
|
+
const point = points[i];
|
|
3665
|
+
if (i)
|
|
3666
|
+
context.lineTo(point.x, point.y);
|
|
3667
|
+
else
|
|
3668
|
+
context.moveTo(point.x, point.y);
|
|
3669
|
+
}
|
|
3670
|
+
if (wrap)
|
|
3671
|
+
context.closePath();
|
|
3672
|
+
context.stroke();
|
|
3673
|
+
}, screenSpace, context);
|
|
3674
|
+
}
|
|
3675
|
+
}
|
|
3676
|
+
|
|
3557
3677
|
/** Draw colored line between two points
|
|
3558
3678
|
* @param {Vector2} posA
|
|
3559
3679
|
* @param {Vector2} posB
|
|
3560
|
-
* @param {number} [
|
|
3680
|
+
* @param {number} [width]
|
|
3561
3681
|
* @param {Color} [color=(1,1,1,1)]
|
|
3562
3682
|
* @param {Vector2} [pos=(0,0)] - Offset to apply
|
|
3563
3683
|
* @param {number} [angle] - Angle to rotate by
|
|
@@ -3565,10 +3685,10 @@ function drawRect(pos, size, color, angle, useWebGL, screenSpace, context)
|
|
|
3565
3685
|
* @param {boolean} [screenSpace]
|
|
3566
3686
|
* @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} [context]
|
|
3567
3687
|
* @memberof Draw */
|
|
3568
|
-
function drawLine(posA, posB,
|
|
3688
|
+
function drawLine(posA, posB, width=.1, color, pos=vec2(), angle=0, useWebGL, screenSpace, context)
|
|
3569
3689
|
{
|
|
3570
3690
|
const halfDelta = vec2((posB.x - posA.x)/2, (posB.y - posA.y)/2);
|
|
3571
|
-
const size = vec2(
|
|
3691
|
+
const size = vec2(width, halfDelta.length()*2);
|
|
3572
3692
|
pos = pos.add(posA.add(halfDelta));
|
|
3573
3693
|
angle += halfDelta.angle();
|
|
3574
3694
|
drawRect(pos, size, color, angle, useWebGL, screenSpace, context);
|
|
@@ -3588,12 +3708,16 @@ function drawLine(posA, posB, thickness=.1, color, pos=vec2(), angle=0, useWebGL
|
|
|
3588
3708
|
* @memberof Draw */
|
|
3589
3709
|
function drawRegularPoly(pos, size=vec2(1), sides=3, color=WHITE, lineWidth=0, lineColor=BLACK, angle=0, useWebGL=glEnable, screenSpace=false, context)
|
|
3590
3710
|
{
|
|
3711
|
+
ASSERT(isVector2(size), 'drawRegularPoly size should be a vec2');
|
|
3712
|
+
ASSERT(isNumber(sides), 'drawRegularPoly sides should be a number');
|
|
3713
|
+
|
|
3591
3714
|
// build regular polygon points
|
|
3592
3715
|
const points = [];
|
|
3716
|
+
const sizeX = size.x/2, sizeY = size.y/2;
|
|
3593
3717
|
for (let i=sides; i--;)
|
|
3594
3718
|
{
|
|
3595
3719
|
const a = (i/sides)*PI*2;
|
|
3596
|
-
points.push(vec2(Math.sin(a)*
|
|
3720
|
+
points.push(vec2(Math.sin(a)*sizeX, Math.cos(a)*sizeY));
|
|
3597
3721
|
}
|
|
3598
3722
|
drawPoly(points, color, lineWidth, lineColor, pos, angle, useWebGL, screenSpace, context);
|
|
3599
3723
|
}
|
|
@@ -3611,7 +3735,7 @@ function drawRegularPoly(pos, size=vec2(1), sides=3, color=WHITE, lineWidth=0, l
|
|
|
3611
3735
|
* @memberof Draw */
|
|
3612
3736
|
function drawPoly(points, color=WHITE, lineWidth=0, lineColor=BLACK, pos=vec2(), angle=0, useWebGL=glEnable, screenSpace=false, context=undefined)
|
|
3613
3737
|
{
|
|
3614
|
-
ASSERT(isVector2(pos)
|
|
3738
|
+
ASSERT(isVector2(pos), 'drawPoly pos should be a vec2');
|
|
3615
3739
|
ASSERT(Array.isArray(points), 'drawPoly points should be an array');
|
|
3616
3740
|
ASSERT(isColor(color) && isColor(lineColor), 'drawPoly color is invalid');
|
|
3617
3741
|
ASSERT(isNumber(lineWidth), 'drawPoly lineWidth should be a number');
|
|
@@ -3652,7 +3776,7 @@ function drawPoly(points, color=WHITE, lineWidth=0, lineColor=BLACK, pos=vec2(),
|
|
|
3652
3776
|
|
|
3653
3777
|
/** Draw colored ellipse using passed in point
|
|
3654
3778
|
* @param {Vector2} pos
|
|
3655
|
-
* @param {Vector2} [size=(1,1)]
|
|
3779
|
+
* @param {Vector2} [size=(1,1)] - Width and height diameter
|
|
3656
3780
|
* @param {Color} [color=(1,1,1,1)]
|
|
3657
3781
|
* @param {number} [angle]
|
|
3658
3782
|
* @param {number} [lineWidth]
|
|
@@ -3663,8 +3787,8 @@ function drawPoly(points, color=WHITE, lineWidth=0, lineColor=BLACK, pos=vec2(),
|
|
|
3663
3787
|
* @memberof Draw */
|
|
3664
3788
|
function drawEllipse(pos, size=vec2(1), color=WHITE, angle=0, lineWidth=0, lineColor=BLACK, useWebGL=glEnable, screenSpace=false, context)
|
|
3665
3789
|
{
|
|
3666
|
-
ASSERT(isVector2(pos)
|
|
3667
|
-
ASSERT(isVector2(size)
|
|
3790
|
+
ASSERT(isVector2(pos), 'drawEllipse pos should be a vec2');
|
|
3791
|
+
ASSERT(isVector2(size), 'drawEllipse size should be a vec2');
|
|
3668
3792
|
ASSERT(isColor(color) && isColor(lineColor), 'drawEllipse color is invalid');
|
|
3669
3793
|
ASSERT(isNumber(angle), 'drawEllipse angle should be a number');
|
|
3670
3794
|
ASSERT(isNumber(lineWidth), 'drawEllipse lineWidth should be a number');
|
|
@@ -3682,7 +3806,7 @@ function drawEllipse(pos, size=vec2(1), color=WHITE, angle=0, lineWidth=0, lineC
|
|
|
3682
3806
|
{
|
|
3683
3807
|
context.fillStyle = color.toString();
|
|
3684
3808
|
context.beginPath();
|
|
3685
|
-
context.ellipse(0, 0, size.x, size.y, 0, 0, 9);
|
|
3809
|
+
context.ellipse(0, 0, size.x/2, size.y/2, 0, 0, 9);
|
|
3686
3810
|
context.fill();
|
|
3687
3811
|
if (lineWidth)
|
|
3688
3812
|
{
|
|
@@ -3696,7 +3820,7 @@ function drawEllipse(pos, size=vec2(1), color=WHITE, angle=0, lineWidth=0, lineC
|
|
|
3696
3820
|
|
|
3697
3821
|
/** Draw colored circle using passed in point
|
|
3698
3822
|
* @param {Vector2} pos
|
|
3699
|
-
* @param {number} [
|
|
3823
|
+
* @param {number} [size=1] - Diameter
|
|
3700
3824
|
* @param {Color} [color=(1,1,1,1)]
|
|
3701
3825
|
* @param {number} [lineWidth=0]
|
|
3702
3826
|
* @param {Color} [lineColor=(0,0,0,1)]
|
|
@@ -3704,8 +3828,11 @@ function drawEllipse(pos, size=vec2(1), color=WHITE, angle=0, lineWidth=0, lineC
|
|
|
3704
3828
|
* @param {boolean} [screenSpace]
|
|
3705
3829
|
* @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} [context]
|
|
3706
3830
|
* @memberof Draw */
|
|
3707
|
-
function drawCircle(pos,
|
|
3708
|
-
{
|
|
3831
|
+
function drawCircle(pos, size=1, color=WHITE, lineWidth=0, lineColor=BLACK, useWebGL=glEnable, screenSpace=false, context)
|
|
3832
|
+
{
|
|
3833
|
+
ASSERT(isNumber(size), 'drawCircle size should be a number');
|
|
3834
|
+
drawEllipse(pos, vec2(size), color, 0, lineWidth, lineColor, useWebGL, screenSpace, context);
|
|
3835
|
+
}
|
|
3709
3836
|
|
|
3710
3837
|
/** Draw directly to a 2d canvas context in world space
|
|
3711
3838
|
* @param {Vector2} pos
|
|
@@ -3791,7 +3918,6 @@ function drawTextScreen(text, pos, size=1, color=WHITE, lineWidth=0, lineColor=B
|
|
|
3791
3918
|
context.textAlign = textAlign;
|
|
3792
3919
|
context.font = size + 'px '+ font;
|
|
3793
3920
|
context.textBaseline = 'middle';
|
|
3794
|
-
context.lineJoin = 'round';
|
|
3795
3921
|
|
|
3796
3922
|
const lines = (text+'').split('\n');
|
|
3797
3923
|
let posY = pos.y;
|
|
@@ -3991,7 +4117,7 @@ let engineFontImage;
|
|
|
3991
4117
|
* const font = new FontImage;
|
|
3992
4118
|
*
|
|
3993
4119
|
* // draw text
|
|
3994
|
-
* font.drawTextScreen(
|
|
4120
|
+
* font.drawTextScreen('LittleJS\nHello World!', vec2(200, 50));
|
|
3995
4121
|
*/
|
|
3996
4122
|
class FontImage
|
|
3997
4123
|
{
|
|
@@ -5314,7 +5440,6 @@ function zzfxG
|
|
|
5314
5440
|
* - Caches arrays of tiles to off screen canvas for fast rendering
|
|
5315
5441
|
* - Unlimited numbers of layers, allocates canvases as needed
|
|
5316
5442
|
* - Tile layers can be drawn to using their context with canvas2d
|
|
5317
|
-
* - Drawn directly to the main canvas without using WebGL
|
|
5318
5443
|
* - Tile layers can also have collision with EngineObjects
|
|
5319
5444
|
* @namespace TileCollision
|
|
5320
5445
|
*/
|
|
@@ -6516,7 +6641,7 @@ let glAntialias = true;
|
|
|
6516
6641
|
let glShader, glPolyShader, glPolyMode, glAdditive, glBatchAdditive, glActiveTexture, glArrayBuffer, glGeometryBuffer, glPositionData, glColorData, glBatchCount;
|
|
6517
6642
|
|
|
6518
6643
|
// WebGL internal constants
|
|
6519
|
-
const gl_ARRAY_BUFFER_SIZE =
|
|
6644
|
+
const gl_ARRAY_BUFFER_SIZE = 5e5;
|
|
6520
6645
|
const gl_INDICES_PER_INSTANCE = 11;
|
|
6521
6646
|
const gl_INSTANCE_BYTE_STRIDE = gl_INDICES_PER_INSTANCE * 4;
|
|
6522
6647
|
const gl_MAX_INSTANCES = gl_ARRAY_BUFFER_SIZE / gl_INSTANCE_BYTE_STRIDE | 0;
|
|
@@ -6610,9 +6735,9 @@ function glInit()
|
|
|
6610
6735
|
glContext.bufferData(glContext.ARRAY_BUFFER, geometry, glContext.STATIC_DRAW);
|
|
6611
6736
|
}
|
|
6612
6737
|
|
|
6613
|
-
function glSetInstancedMode(
|
|
6738
|
+
function glSetInstancedMode()
|
|
6614
6739
|
{
|
|
6615
|
-
if (!glPolyMode
|
|
6740
|
+
if (!glPolyMode)
|
|
6616
6741
|
return;
|
|
6617
6742
|
|
|
6618
6743
|
// setup instanced mode
|
|
@@ -6693,7 +6818,7 @@ function glPreRender()
|
|
|
6693
6818
|
1, 1, 1, 0,
|
|
6694
6819
|
p.x, p.y, 0, 1];
|
|
6695
6820
|
|
|
6696
|
-
// set the same matrix for both shaders
|
|
6821
|
+
// set the same transform matrix for both shaders
|
|
6697
6822
|
const initUniform = (program, uniform, value) =>
|
|
6698
6823
|
{
|
|
6699
6824
|
glContext.useProgram(program);
|
|
@@ -6711,9 +6836,12 @@ function glPreRender()
|
|
|
6711
6836
|
glContext.bindTexture(glContext.TEXTURE_2D, glActiveTexture);
|
|
6712
6837
|
}
|
|
6713
6838
|
|
|
6714
|
-
// start
|
|
6715
|
-
glAdditive = glBatchAdditive =
|
|
6716
|
-
|
|
6839
|
+
// start with additive blending off
|
|
6840
|
+
glAdditive = glBatchAdditive = false;
|
|
6841
|
+
|
|
6842
|
+
// force it to enter instanced mode
|
|
6843
|
+
glPolyMode = true;
|
|
6844
|
+
glSetInstancedMode();
|
|
6717
6845
|
}
|
|
6718
6846
|
|
|
6719
6847
|
/** Clear the canvas and setup the viewport
|
|
@@ -6723,7 +6851,9 @@ function glClearCanvas()
|
|
|
6723
6851
|
if (!glContext) return;
|
|
6724
6852
|
|
|
6725
6853
|
// clear and set to same size as main canvas
|
|
6726
|
-
|
|
6854
|
+
glCanvas.width = drawCanvas.width;
|
|
6855
|
+
glCanvas.height = drawCanvas.height;
|
|
6856
|
+
glContext.viewport(0, 0, glCanvas.width, glCanvas.height);
|
|
6727
6857
|
glContext.clear(glContext.COLOR_BUFFER_BIT);
|
|
6728
6858
|
}
|
|
6729
6859
|
|
|
@@ -6858,15 +6988,17 @@ function glFlush()
|
|
|
6858
6988
|
const destBlend = glBatchAdditive ? glContext.ONE : glContext.ONE_MINUS_SRC_ALPHA;
|
|
6859
6989
|
glContext.blendFuncSeparate(glContext.SRC_ALPHA, destBlend, glContext.ONE, destBlend);
|
|
6860
6990
|
glContext.enable(glContext.BLEND);
|
|
6861
|
-
|
|
6991
|
+
|
|
6992
|
+
const byteLength = glBatchCount *
|
|
6993
|
+
(glPolyMode ? gl_INDICES_PER_POLY_VERTEX : gl_INDICES_PER_INSTANCE);
|
|
6994
|
+
glContext.bufferSubData(glContext.ARRAY_BUFFER, 0, glPositionData, 0, byteLength);
|
|
6862
6995
|
|
|
6863
6996
|
// draw the batch
|
|
6864
6997
|
if (glPolyMode)
|
|
6865
6998
|
glContext.drawArrays(glContext.TRIANGLE_STRIP, 0, glBatchCount);
|
|
6866
6999
|
else
|
|
6867
7000
|
glContext.drawArraysInstanced(glContext.TRIANGLE_STRIP, 0, 4, glBatchCount);
|
|
6868
|
-
|
|
6869
|
-
drawCount += glBatchCount;
|
|
7001
|
+
drawCount += glBatchCount;
|
|
6870
7002
|
glBatchCount = 0;
|
|
6871
7003
|
}
|
|
6872
7004
|
glBatchAdditive = glAdditive;
|
|
@@ -6930,7 +7062,7 @@ function glDraw(x, y, sizeX, sizeY, angle=0, uv0X=0, uv0Y=0, uv1X=1, uv1Y=1, rgb
|
|
|
6930
7062
|
}
|
|
6931
7063
|
|
|
6932
7064
|
/** Transform and add a polygon to the gl draw list
|
|
6933
|
-
* @param {Array} points - Array of Vector2 points
|
|
7065
|
+
* @param {Array<Vector2>} points - Array of Vector2 points
|
|
6934
7066
|
* @param {number} rgba - Color of the polygon as a 32-bit integer
|
|
6935
7067
|
* @param {number} x
|
|
6936
7068
|
* @param {number} y
|
|
@@ -6956,7 +7088,7 @@ function glDrawPointsTransform(points, rgba, x, y, sx, sy, angle, tristrip=true)
|
|
|
6956
7088
|
}
|
|
6957
7089
|
|
|
6958
7090
|
/** Transform and add a polygon to the gl draw list
|
|
6959
|
-
* @param {Array} points - Array of Vector2 points
|
|
7091
|
+
* @param {Array<Vector2>} points - Array of Vector2 points
|
|
6960
7092
|
* @param {number} rgba - Color of the polygon as a 32-bit integer
|
|
6961
7093
|
* @param {number} lineWidth - Width of the outline
|
|
6962
7094
|
* @param {number} x
|
|
@@ -6964,61 +7096,73 @@ function glDrawPointsTransform(points, rgba, x, y, sx, sy, angle, tristrip=true)
|
|
|
6964
7096
|
* @param {number} sx
|
|
6965
7097
|
* @param {number} sy
|
|
6966
7098
|
* @param {number} angle
|
|
7099
|
+
* @param {boolean} [wrap] - Should the outline connect the first and last points
|
|
6967
7100
|
* @memberof WebGL */
|
|
6968
|
-
function glDrawOutlineTransform(points, rgba, lineWidth, x, y, sx, sy, angle)
|
|
7101
|
+
function glDrawOutlineTransform(points, rgba, lineWidth, x, y, sx, sy, angle, wrap=true)
|
|
6969
7102
|
{
|
|
6970
|
-
const outlinePoints = glMakeOutline(points, lineWidth);
|
|
7103
|
+
const outlinePoints = glMakeOutline(points, lineWidth, wrap);
|
|
6971
7104
|
glDrawPointsTransform(outlinePoints, rgba, x, y, sx, sy, angle, false);
|
|
6972
7105
|
}
|
|
6973
7106
|
|
|
6974
|
-
/** Add a
|
|
6975
|
-
* @param {Array} points - Array of Vector2 points in
|
|
6976
|
-
* @param {number} rgba - Color
|
|
7107
|
+
/** Add a list of points to the gl draw list
|
|
7108
|
+
* @param {Array<Vector2>} points - Array of Vector2 points in tri strip order
|
|
7109
|
+
* @param {number} rgba - Color as a 32-bit integer
|
|
6977
7110
|
* @memberof WebGL */
|
|
6978
7111
|
function glDrawPoints(points, rgba)
|
|
6979
7112
|
{
|
|
6980
7113
|
if (!glEnable || points.length < 3)
|
|
6981
7114
|
return; // needs at least 3 points to have area
|
|
6982
7115
|
|
|
6983
|
-
// add 2 degenerate verts if batching with existing polys to separate them
|
|
6984
|
-
const needsBridge = glPolyMode && glBatchCount > 0;
|
|
6985
|
-
const bridgeVerts = needsBridge ? 2 : 0;
|
|
6986
|
-
const vertCount = points.length + bridgeVerts;
|
|
6987
|
-
|
|
6988
7116
|
// flush if there is not enough room or if different blend mode
|
|
6989
|
-
|
|
7117
|
+
const vertCount = points.length + 2;
|
|
7118
|
+
if (glBatchCount+vertCount >= gl_MAX_POLY_VERTEXES || glBatchAdditive !== glAdditive)
|
|
6990
7119
|
glFlush();
|
|
6991
7120
|
glSetPolyMode();
|
|
6992
7121
|
|
|
7122
|
+
// setup triangle strip with degenerate verts at start and end
|
|
6993
7123
|
let offset = glBatchCount * gl_INDICES_PER_POLY_VERTEX;
|
|
6994
|
-
|
|
6995
|
-
|
|
6996
|
-
|
|
6997
|
-
|
|
6998
|
-
|
|
6999
|
-
|
|
7000
|
-
glPositionData[offset++] = glPositionData[prevOffset];
|
|
7001
|
-
glPositionData[offset++] = glPositionData[prevOffset + 1];
|
|
7002
|
-
glColorData[offset++] = glColorData[prevOffset + 2];
|
|
7003
|
-
|
|
7004
|
-
// repeat first vertex of new poly
|
|
7005
|
-
glPositionData[offset++] = points[0].x;
|
|
7006
|
-
glPositionData[offset++] = points[0].y;
|
|
7124
|
+
for(let i = vertCount; i--;)
|
|
7125
|
+
{
|
|
7126
|
+
const j = clamp(i-1, 0, vertCount-3);
|
|
7127
|
+
const point = points[j];
|
|
7128
|
+
glPositionData[offset++] = point.x;
|
|
7129
|
+
glPositionData[offset++] = point.y;
|
|
7007
7130
|
glColorData[offset++] = rgba;
|
|
7008
7131
|
}
|
|
7132
|
+
glBatchCount += vertCount;
|
|
7133
|
+
}
|
|
7134
|
+
|
|
7135
|
+
/** Add a list of colored points to the gl draw list
|
|
7136
|
+
* @param {Array<Vector2>} points - Array of Vector2 points in tri strip order
|
|
7137
|
+
* @param {Array<number>} pointColors - Array of 32-bit integer colors
|
|
7138
|
+
* @memberof WebGL */
|
|
7139
|
+
function glDrawColoredPoints(points, pointColors)
|
|
7140
|
+
{
|
|
7141
|
+
if (!glEnable || points.length < 3)
|
|
7142
|
+
return; // needs at least 3 points to have area
|
|
7009
7143
|
|
|
7010
|
-
//
|
|
7011
|
-
|
|
7144
|
+
// flush if there is not enough room or if different blend mode
|
|
7145
|
+
const vertCount = points.length + 2;
|
|
7146
|
+
if (glBatchCount+vertCount >= gl_MAX_POLY_VERTEXES || glBatchAdditive !== glAdditive)
|
|
7147
|
+
glFlush();
|
|
7148
|
+
glSetPolyMode();
|
|
7149
|
+
|
|
7150
|
+
// setup triangle strip with degenerate verts at start and end
|
|
7151
|
+
let offset = glBatchCount * gl_INDICES_PER_POLY_VERTEX;
|
|
7152
|
+
for(let i = vertCount; i--;)
|
|
7012
7153
|
{
|
|
7154
|
+
const j = clamp(i-1, 0, vertCount-3);
|
|
7155
|
+
const point = points[j];
|
|
7156
|
+
const color = pointColors[j];
|
|
7013
7157
|
glPositionData[offset++] = point.x;
|
|
7014
7158
|
glPositionData[offset++] = point.y;
|
|
7015
|
-
glColorData[offset++] =
|
|
7159
|
+
glColorData[offset++] = color;
|
|
7016
7160
|
}
|
|
7017
7161
|
glBatchCount += vertCount;
|
|
7018
7162
|
}
|
|
7019
7163
|
|
|
7020
7164
|
// WebGL internal function to convert polygon to outline triangle strip
|
|
7021
|
-
function glMakeOutline(points, width)
|
|
7165
|
+
function glMakeOutline(points, width, wrap=true)
|
|
7022
7166
|
{
|
|
7023
7167
|
if (points.length < 2)
|
|
7024
7168
|
return [];
|
|
@@ -7027,12 +7171,13 @@ function glMakeOutline(points, width)
|
|
|
7027
7171
|
const strip = [];
|
|
7028
7172
|
const n = points.length;
|
|
7029
7173
|
const e = 1e-6;
|
|
7174
|
+
const miterLimit = width*100;
|
|
7030
7175
|
for (let i = 0; i < n; i++)
|
|
7031
7176
|
{
|
|
7032
7177
|
// for each vertex, calculate normal based on adjacent edges
|
|
7033
|
-
const prev = points[(i - 1 + n) % n];
|
|
7178
|
+
const prev = points[wrap ? (i - 1 + n) % n : max(i - 1, 0)];
|
|
7034
7179
|
const curr = points[i];
|
|
7035
|
-
const next = points[(i + 1) % n];
|
|
7180
|
+
const next = points[wrap ? (i + 1) % n : min(i + 1, n - 1)];
|
|
7036
7181
|
|
|
7037
7182
|
// direction from previous to current
|
|
7038
7183
|
const dx1 = curr.x - prev.x;
|
|
@@ -7071,8 +7216,8 @@ function glMakeOutline(points, width)
|
|
|
7071
7216
|
const dot = nx1 * nx + ny1 * ny;
|
|
7072
7217
|
if (dot > e)
|
|
7073
7218
|
{
|
|
7074
|
-
// scale normal by miter length
|
|
7075
|
-
const miterLength = 1 / dot;
|
|
7219
|
+
// scale normal by miter length, clamped to miterLimit
|
|
7220
|
+
const miterLength = min(1 / dot, miterLimit);
|
|
7076
7221
|
nx *= miterLength;
|
|
7077
7222
|
ny *= miterLength;
|
|
7078
7223
|
}
|
|
@@ -7084,7 +7229,7 @@ function glMakeOutline(points, width)
|
|
|
7084
7229
|
strip.push(inner);
|
|
7085
7230
|
strip.push(outer);
|
|
7086
7231
|
}
|
|
7087
|
-
if (strip.length > 1)
|
|
7232
|
+
if (strip.length > 1 && wrap)
|
|
7088
7233
|
{
|
|
7089
7234
|
// close the loop
|
|
7090
7235
|
strip.push(strip[0]);
|
|
@@ -7119,10 +7264,8 @@ function glPolyStrip(points)
|
|
|
7119
7264
|
if (signedArea(points) < 0)
|
|
7120
7265
|
points = points.reverse();
|
|
7121
7266
|
|
|
7122
|
-
// tolerance constants
|
|
7123
|
-
const e = 1e-10;
|
|
7124
|
-
|
|
7125
7267
|
// check if point is inside triangle
|
|
7268
|
+
const e = 1e-9;
|
|
7126
7269
|
const pointInTriangle = (p, a, b, c)=>
|
|
7127
7270
|
{
|
|
7128
7271
|
const c1 = cross(a, b, p);
|
|
@@ -9858,7 +10001,7 @@ class Box2dPlugin
|
|
|
9858
10001
|
case box2d.instance.b2Shape.e_circle:
|
|
9859
10002
|
{
|
|
9860
10003
|
const radius = shape.get_m_radius();
|
|
9861
|
-
drawCircle(pos, radius, color, lineWidth, lineColor);
|
|
10004
|
+
drawCircle(pos, radius*2, color, lineWidth, lineColor);
|
|
9862
10005
|
break;
|
|
9863
10006
|
}
|
|
9864
10007
|
case box2d.instance.b2Shape.e_edge:
|
|
@@ -10009,14 +10152,14 @@ async function box2dInit()
|
|
|
10009
10152
|
{
|
|
10010
10153
|
color = getDebugColor(color);
|
|
10011
10154
|
center = box2d.vec2FromPointer(center);
|
|
10012
|
-
drawCircle(center, radius, CLEAR_WHITE, debugLineWidth, color, false, false, overlayContext);
|
|
10155
|
+
drawCircle(center, radius*2, CLEAR_WHITE, debugLineWidth, color, false, false, overlayContext);
|
|
10013
10156
|
};
|
|
10014
10157
|
debugDraw.DrawSolidCircle = function(center, radius, axis, color)
|
|
10015
10158
|
{
|
|
10016
10159
|
color = getDebugColor(color);
|
|
10017
10160
|
center = box2d.vec2FromPointer(center);
|
|
10018
10161
|
axis = box2d.vec2FromPointer(axis).scale(radius);
|
|
10019
|
-
drawCircle(center, radius, color, debugLineWidth, color, false, false, overlayContext);
|
|
10162
|
+
drawCircle(center, radius*2, color, debugLineWidth, color, false, false, overlayContext);
|
|
10020
10163
|
drawLine(vec2(), axis, debugLineWidth, color, center, 0, false, false, overlayContext);
|
|
10021
10164
|
};
|
|
10022
10165
|
debugDraw.DrawTransform = function(transform)
|