littlejsengine 1.13.1 → 1.13.4
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 +15 -12
- package/dist/littlejs.d.ts +94 -74
- package/dist/littlejs.esm.js +422 -306
- package/dist/littlejs.esm.min.js +1 -1
- package/dist/littlejs.js +416 -306
- package/dist/littlejs.min.js +1 -1
- package/dist/littlejs.release.js +414 -304
- package/examples/box2d/game.js +1 -1
- package/examples/box2d/gameObjects.js +1 -1
- package/examples/box2d/scenes.js +1 -1
- package/examples/breakoutTutorial/README.md +44 -41
- package/examples/breakoutTutorial/game.js +2 -2
- package/examples/electron/build.bat +7 -0
- package/examples/electron/build.js +124 -0
- package/examples/electron/electron.js +35 -0
- package/examples/electron/game.js +140 -0
- package/examples/electron/index.html +13 -0
- package/examples/electron/package.json +12 -0
- package/examples/electron/tiles.png +0 -0
- package/examples/empty/game.js +1 -0
- package/examples/htmlMenu/game.js +1 -1
- package/examples/index.html +154 -93
- package/examples/module/game.js +5 -2
- package/examples/particles/index.html +12 -3
- package/examples/platformer/gameEffects.js +3 -3
- package/examples/shorts/base.html +1 -1
- package/examples/shorts/blending.js +9 -5
- package/examples/shorts/box2d.js +1 -1
- package/examples/shorts/box2dCar.js +1 -1
- package/examples/shorts/clock.js +1 -1
- package/examples/shorts/colors.js +2 -2
- package/examples/shorts/maze.js +1 -1
- package/examples/shorts/nineSlice.js +9 -9
- package/examples/shorts/piano.js +2 -2
- package/examples/shorts/raycasting.js +2 -2
- package/examples/shorts/shapes.js +9 -9
- package/examples/shorts/slidingPuzzle.js +2 -2
- package/examples/shorts/starfield.js +5 -7
- package/examples/shorts/systemFont.js +1 -1
- package/examples/shorts/uiSystem.js +1 -0
- package/examples/starter/build.js +9 -8
- package/examples/starter/game.js +5 -2
- package/examples/starter/index.html +2 -2
- package/examples/stress/index.html +5 -5
- package/examples/style.css +5 -2
- package/examples/typescript/build.js +1 -1
- package/examples/typescript/game.js +2 -2
- package/examples/typescript/game.ts +5 -2
- package/examples/uiSystem/game.js +2 -1
- package/package.json +2 -2
- package/plugins/box2d.js +19 -94
- package/plugins/drawUtilities.js +24 -18
- package/plugins/postProcess.js +7 -0
- package/plugins/uiSystem.js +4 -4
- package/src/engine.js +7 -2
- package/src/engineAudio.js +1 -1
- package/src/engineDebug.js +2 -2
- package/src/engineDraw.js +243 -150
- package/src/engineExport.js +6 -0
- package/src/engineInput.js +2 -2
- package/src/engineMedals.js +4 -4
- package/src/engineObject.js +3 -3
- package/src/engineParticles.js +8 -1
- package/src/engineSettings.js +55 -8
- package/src/engineUtilities.js +7 -7
- package/src/engineWebGL.js +25 -5
package/dist/littlejs.release.js
CHANGED
|
@@ -33,7 +33,7 @@ const engineName = 'LittleJS';
|
|
|
33
33
|
* @type {string}
|
|
34
34
|
* @default
|
|
35
35
|
* @memberof Engine */
|
|
36
|
-
const engineVersion = '1.13.
|
|
36
|
+
const engineVersion = '1.13.4';
|
|
37
37
|
|
|
38
38
|
/** Frames per second to update
|
|
39
39
|
* @type {number}
|
|
@@ -300,7 +300,6 @@ async function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, game
|
|
|
300
300
|
'margin:0;' + // fill the window
|
|
301
301
|
'overflow:hidden;' + // no scroll bars
|
|
302
302
|
'background:#000;' + // set background color
|
|
303
|
-
(canvasPixelated ? 'image-rendering:pixelated;' : '') + // pixel art
|
|
304
303
|
'user-select:none;' + // prevent hold to select
|
|
305
304
|
'-webkit-user-select:none;' + // compatibility for ios
|
|
306
305
|
(!touchInputEnable ? '' : // no touch css settings
|
|
@@ -328,7 +327,13 @@ async function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, game
|
|
|
328
327
|
mainCanvas.style.cssText = overlayCanvas.style.cssText = styleCanvas;
|
|
329
328
|
if (glCanvas)
|
|
330
329
|
glCanvas.style.cssText = styleCanvas;
|
|
330
|
+
setCanvasPixelated(canvasPixelated);
|
|
331
|
+
setOverlayCanvasPixelated(overlayCanvasPixelated);
|
|
331
332
|
updateCanvas();
|
|
333
|
+
|
|
334
|
+
// create offscreen canvas for image processing
|
|
335
|
+
workCanvas = new OffscreenCanvas(256, 256);
|
|
336
|
+
workContext = workCanvas.getContext('2d', { willReadFrequently: true });
|
|
332
337
|
|
|
333
338
|
// create promises for loading images
|
|
334
339
|
const promises = imageSources.map((src, textureIndex)=>
|
|
@@ -817,11 +822,12 @@ function isPowerOfTwo(value) { return !(value & (value - 1)); }
|
|
|
817
822
|
* @memberof Utilities */
|
|
818
823
|
function nearestPowerOfTwo(value) { return 2**Math.ceil(Math.log2(value)); }
|
|
819
824
|
|
|
820
|
-
/** Returns true if two axis aligned bounding boxes are overlapping
|
|
825
|
+
/** Returns true if two axis aligned bounding boxes are overlapping
|
|
826
|
+
* this can be used for simple collision detection between objects
|
|
821
827
|
* @param {Vector2} posA - Center of box A
|
|
822
828
|
* @param {Vector2} sizeA - Size of box A
|
|
823
829
|
* @param {Vector2} posB - Center of box B
|
|
824
|
-
* @param {Vector2} [sizeB=(0,0)] - Size of box B, a point if undefined
|
|
830
|
+
* @param {Vector2} [sizeB=(0,0)] - Size of box B, uses a point if undefined
|
|
825
831
|
* @return {boolean} - True if overlapping
|
|
826
832
|
* @memberof Utilities */
|
|
827
833
|
function isOverlapping(posA, sizeA, posB, sizeB=vec2())
|
|
@@ -875,10 +881,11 @@ function isIntersecting(start, end, pos, size)
|
|
|
875
881
|
* @param {number} [frequency] - Frequency of the wave in Hz
|
|
876
882
|
* @param {number} [amplitude] - Amplitude (max height) of the wave
|
|
877
883
|
* @param {number} [t=time] - Value to use for time of the wave
|
|
884
|
+
* @param {number} [offset] - Value to use for time offset of the wave
|
|
878
885
|
* @return {number} - Value waving between 0 and amplitude
|
|
879
886
|
* @memberof Utilities */
|
|
880
|
-
function wave(frequency=1, amplitude=1, t=time)
|
|
881
|
-
{ return amplitude/2 * (1 - Math.cos(t*frequency*2*PI)); }
|
|
887
|
+
function wave(frequency=1, amplitude=1, t=time, offset=0)
|
|
888
|
+
{ return amplitude/2 * (1 - Math.cos(offset + t*frequency*2*PI)); }
|
|
882
889
|
|
|
883
890
|
/** Formats seconds to mm:ss style for display purposes
|
|
884
891
|
* @param {number} t - time in seconds
|
|
@@ -1535,9 +1542,7 @@ class Color
|
|
|
1535
1542
|
/** Checks if this is a valid color
|
|
1536
1543
|
* @return {boolean} */
|
|
1537
1544
|
isValid()
|
|
1538
|
-
{
|
|
1539
|
-
return isNumber(this.r) && isNumber(this.g) && isNumber(this.b) && isNumber(this.a);
|
|
1540
|
-
}
|
|
1545
|
+
{ return isNumber(this.r) && isNumber(this.g) && isNumber(this.b) && isNumber(this.a); }
|
|
1541
1546
|
}
|
|
1542
1547
|
|
|
1543
1548
|
///////////////////////////////////////////////////////////////////////////////
|
|
@@ -1700,6 +1705,13 @@ let cameraScale = 32;
|
|
|
1700
1705
|
///////////////////////////////////////////////////////////////////////////////
|
|
1701
1706
|
// Display settings
|
|
1702
1707
|
|
|
1708
|
+
/** Enable applying color to tiles when using canvas2d
|
|
1709
|
+
* - This is slower but should be the same as webgl rendering
|
|
1710
|
+
* @type {boolean}
|
|
1711
|
+
* @default
|
|
1712
|
+
* @memberof Settings */
|
|
1713
|
+
let canvasColorTiles = true;
|
|
1714
|
+
|
|
1703
1715
|
/** The max size of the canvas, centered if window is larger
|
|
1704
1716
|
* @type {Vector2}
|
|
1705
1717
|
* @default Vector2(1920,1080)
|
|
@@ -1713,14 +1725,21 @@ let canvasMaxSize = vec2(1920, 1080);
|
|
|
1713
1725
|
* @memberof Settings */
|
|
1714
1726
|
let canvasFixedSize = vec2();
|
|
1715
1727
|
|
|
1716
|
-
/** Use nearest
|
|
1717
|
-
* - Must be set before startup to take effect
|
|
1728
|
+
/** Use nearest canvas scaling for more pixelated look
|
|
1718
1729
|
* - If enabled sets css image-rendering:pixelated
|
|
1719
1730
|
* @type {boolean}
|
|
1720
1731
|
* @default
|
|
1721
1732
|
* @memberof Settings */
|
|
1722
1733
|
let canvasPixelated = true;
|
|
1723
1734
|
|
|
1735
|
+
/** Use nearest canvas scaling for more pixelated look
|
|
1736
|
+
* - If enabled sets css image-rendering:pixelated
|
|
1737
|
+
* - This defaults to false because text looks better with smoothing
|
|
1738
|
+
* @type {boolean}
|
|
1739
|
+
* @default
|
|
1740
|
+
* @memberof Settings */
|
|
1741
|
+
let overlayCanvasPixelated = false;
|
|
1742
|
+
|
|
1724
1743
|
/** Disables texture filtering for crisper pixel art
|
|
1725
1744
|
* @type {boolean}
|
|
1726
1745
|
* @default
|
|
@@ -1961,6 +1980,14 @@ function setCameraAngle(angle) { cameraAngle = angle; }
|
|
|
1961
1980
|
* @memberof Settings */
|
|
1962
1981
|
function setCameraScale(scale) { cameraScale = scale; }
|
|
1963
1982
|
|
|
1983
|
+
/** Set if tiles should be colorized when using canvas2d
|
|
1984
|
+
* This can be slower but results should look nearly identical to webgl rendering
|
|
1985
|
+
* It can be enabled/disabled at any time
|
|
1986
|
+
* Optimized for performance, and will use faster method if color is white or untextured
|
|
1987
|
+
* @param {boolean} colorTiles
|
|
1988
|
+
* @memberof Settings */
|
|
1989
|
+
function setCanvasColorTiles(colorTiles) { canvasColorTiles = colorTiles; }
|
|
1990
|
+
|
|
1964
1991
|
/** Set max size of the canvas
|
|
1965
1992
|
* @param {Vector2} size
|
|
1966
1993
|
* @memberof Settings */
|
|
@@ -1971,10 +1998,30 @@ function setCanvasMaxSize(size) { canvasMaxSize = size; }
|
|
|
1971
1998
|
* @memberof Settings */
|
|
1972
1999
|
function setCanvasFixedSize(size) { canvasFixedSize = size; }
|
|
1973
2000
|
|
|
1974
|
-
/** Use nearest
|
|
2001
|
+
/** Use nearest scaling algorithm for canvas for more pixelated look
|
|
2002
|
+
* - If enabled sets css image-rendering:pixelated
|
|
2003
|
+
* @param {boolean} pixelated
|
|
2004
|
+
* @memberof Settings */
|
|
2005
|
+
function setCanvasPixelated(pixelated)
|
|
2006
|
+
{
|
|
2007
|
+
canvasPixelated = pixelated;
|
|
2008
|
+
if (mainCanvas)
|
|
2009
|
+
mainCanvas.style.imageRendering = pixelated ? 'pixelated' : '';
|
|
2010
|
+
if (glCanvas)
|
|
2011
|
+
glCanvas.style.imageRendering = pixelated ? 'pixelated' : '';
|
|
2012
|
+
}
|
|
2013
|
+
|
|
2014
|
+
/** Use nearest scaling algorithm for canvas for more pixelated look
|
|
2015
|
+
* - If enabled sets css image-rendering:pixelated
|
|
2016
|
+
* - This defaults to false because text looks better with smoothing
|
|
1975
2017
|
* @param {boolean} pixelated
|
|
1976
2018
|
* @memberof Settings */
|
|
1977
|
-
function
|
|
2019
|
+
function setOverlayCanvasPixelated(pixelated)
|
|
2020
|
+
{
|
|
2021
|
+
overlayCanvasPixelated = pixelated;
|
|
2022
|
+
if (overlayCanvas)
|
|
2023
|
+
overlayCanvas.style.imageRendering = pixelated ? 'pixelated' : '';
|
|
2024
|
+
}
|
|
1978
2025
|
|
|
1979
2026
|
/** Disables texture filtering for crisper pixel art
|
|
1980
2027
|
* @param {boolean} pixelated
|
|
@@ -1999,7 +2046,12 @@ function setHeadlessMode(headless) { headlessMode = headless; }
|
|
|
1999
2046
|
/** Set if webgl rendering is enabled
|
|
2000
2047
|
* @param {boolean} enable
|
|
2001
2048
|
* @memberof Settings */
|
|
2002
|
-
function setGLEnable(enable)
|
|
2049
|
+
function setGLEnable(enable)
|
|
2050
|
+
{
|
|
2051
|
+
glEnable = enable;
|
|
2052
|
+
if (glCanvas) // hide glCanvas if webgl is disabled
|
|
2053
|
+
glCanvas.style.visibility = enable ? 'visible' : 'hidden';
|
|
2054
|
+
}
|
|
2003
2055
|
|
|
2004
2056
|
/** Set default size of tiles in pixels
|
|
2005
2057
|
* @param {Vector2} size
|
|
@@ -2363,7 +2415,7 @@ class EngineObject
|
|
|
2363
2415
|
if (o.mass) // push away if not fixed
|
|
2364
2416
|
o.velocity = o.velocity.subtract(velocity);
|
|
2365
2417
|
|
|
2366
|
-
|
|
2418
|
+
debugPhysics && debugOverlap(this.pos, this.size, o.pos, o.size, '#f00');
|
|
2367
2419
|
continue;
|
|
2368
2420
|
}
|
|
2369
2421
|
|
|
@@ -2425,7 +2477,7 @@ class EngineObject
|
|
|
2425
2477
|
else // bounce if other object is fixed
|
|
2426
2478
|
this.velocity.x *= -restitution;
|
|
2427
2479
|
}
|
|
2428
|
-
|
|
2480
|
+
debugPhysics && debugOverlap(this.pos, this.size, o.pos, o.size, '#f0f');
|
|
2429
2481
|
}
|
|
2430
2482
|
}
|
|
2431
2483
|
if (this.collideTiles)
|
|
@@ -2470,7 +2522,7 @@ class EngineObject
|
|
|
2470
2522
|
this.pos.x = oldPos.x;
|
|
2471
2523
|
this.velocity.x *= -this.restitution;
|
|
2472
2524
|
}
|
|
2473
|
-
|
|
2525
|
+
debugPhysics && debugRect(this.pos, this.size, '#f00');
|
|
2474
2526
|
}
|
|
2475
2527
|
}
|
|
2476
2528
|
}
|
|
@@ -2672,6 +2724,16 @@ let drawCanvas;
|
|
|
2672
2724
|
* @memberof Draw */
|
|
2673
2725
|
let drawContext;
|
|
2674
2726
|
|
|
2727
|
+
/** Offscreen canvas that can be used for image processing
|
|
2728
|
+
* @type {OffscreenCanvas}
|
|
2729
|
+
* @memberof Draw */
|
|
2730
|
+
let workCanvas;
|
|
2731
|
+
|
|
2732
|
+
/** Offscreen canvas that can be used for image processing
|
|
2733
|
+
* @type {OffscreenCanvasRenderingContext2D}
|
|
2734
|
+
* @memberof Draw */
|
|
2735
|
+
let workContext;
|
|
2736
|
+
|
|
2675
2737
|
/** The size of the main canvas (and other secondary canvases)
|
|
2676
2738
|
* @type {Vector2}
|
|
2677
2739
|
* @memberof Draw */
|
|
@@ -2691,10 +2753,10 @@ let drawCount;
|
|
|
2691
2753
|
* Create a tile info object using a grid based system
|
|
2692
2754
|
* - This can take vecs or floats for easier use and conversion
|
|
2693
2755
|
* - If an index is passed in, the tile size and index will determine the position
|
|
2694
|
-
* @param {Vector2|number} [pos=0]
|
|
2756
|
+
* @param {Vector2|number} [pos=0] - Index of tile in sheet
|
|
2695
2757
|
* @param {Vector2|number} [size=tileSizeDefault] - Size of tile in pixels
|
|
2696
|
-
* @param {number} [textureIndex]
|
|
2697
|
-
* @param {number} [padding]
|
|
2758
|
+
* @param {number} [textureIndex] - Texture index to use
|
|
2759
|
+
* @param {number} [padding] - How many pixels padding around tiles
|
|
2698
2760
|
* @return {TileInfo}
|
|
2699
2761
|
* @example
|
|
2700
2762
|
* tile(2) // a tile at index 2 using the default tile size of 16
|
|
@@ -2821,55 +2883,7 @@ class TextureInfo
|
|
|
2821
2883
|
}
|
|
2822
2884
|
|
|
2823
2885
|
///////////////////////////////////////////////////////////////////////////////
|
|
2824
|
-
|
|
2825
|
-
/** Convert from screen to world space coordinates
|
|
2826
|
-
* @param {Vector2} screenPos
|
|
2827
|
-
* @return {Vector2}
|
|
2828
|
-
* @memberof Draw */
|
|
2829
|
-
function screenToWorld(screenPos)
|
|
2830
|
-
{
|
|
2831
|
-
let cameraPosRelativeX = (screenPos.x - mainCanvasSize.x/2 + .5) / cameraScale;
|
|
2832
|
-
let cameraPosRelativeY = (screenPos.y - mainCanvasSize.y/2 + .5) / -cameraScale;
|
|
2833
|
-
if (cameraAngle)
|
|
2834
|
-
{
|
|
2835
|
-
// apply camera rotation
|
|
2836
|
-
const cos = Math.cos(-cameraAngle), sin = Math.sin(-cameraAngle);
|
|
2837
|
-
const rotatedX = cameraPosRelativeX * cos - cameraPosRelativeY * sin;
|
|
2838
|
-
const rotatedY = cameraPosRelativeX * sin + cameraPosRelativeY * cos;
|
|
2839
|
-
cameraPosRelativeX = rotatedX;
|
|
2840
|
-
cameraPosRelativeY = rotatedY;
|
|
2841
|
-
}
|
|
2842
|
-
return new Vector2(cameraPosRelativeX + cameraPos.x, cameraPosRelativeY + cameraPos.y);
|
|
2843
|
-
}
|
|
2844
|
-
|
|
2845
|
-
/** Convert from world to screen space coordinates
|
|
2846
|
-
* @param {Vector2} worldPos
|
|
2847
|
-
* @return {Vector2}
|
|
2848
|
-
* @memberof Draw */
|
|
2849
|
-
function worldToScreen(worldPos)
|
|
2850
|
-
{
|
|
2851
|
-
let cameraPosRelativeX = worldPos.x - cameraPos.x;
|
|
2852
|
-
let cameraPosRelativeY = worldPos.y - cameraPos.y;
|
|
2853
|
-
if (cameraAngle)
|
|
2854
|
-
{
|
|
2855
|
-
// apply inverse camera rotation
|
|
2856
|
-
const cos = Math.cos(cameraAngle), sin = Math.sin(cameraAngle);
|
|
2857
|
-
const rotatedX = cameraPosRelativeX * cos - cameraPosRelativeY * sin;
|
|
2858
|
-
const rotatedY = cameraPosRelativeX * sin + cameraPosRelativeY * cos;
|
|
2859
|
-
cameraPosRelativeX = rotatedX;
|
|
2860
|
-
cameraPosRelativeY = rotatedY;
|
|
2861
|
-
}
|
|
2862
|
-
return new Vector2
|
|
2863
|
-
(
|
|
2864
|
-
cameraPosRelativeX * cameraScale + mainCanvasSize.x/2 - .5,
|
|
2865
|
-
cameraPosRelativeY * -cameraScale + mainCanvasSize.y/2 - .5
|
|
2866
|
-
);
|
|
2867
|
-
}
|
|
2868
|
-
|
|
2869
|
-
/** Get the camera's visible area in world space
|
|
2870
|
-
* @return {Vector2}
|
|
2871
|
-
* @memberof Draw */
|
|
2872
|
-
function getCameraSize() { return mainCanvasSize.scale(1/cameraScale); }
|
|
2886
|
+
// Drawing functions
|
|
2873
2887
|
|
|
2874
2888
|
/** Draw textured tile centered in world space, with color applied if using WebGL
|
|
2875
2889
|
* @param {Vector2} pos - Center of the tile in world space
|
|
@@ -2892,6 +2906,9 @@ function drawTile(pos, size=new Vector2(1), tileInfo, color=new Color,
|
|
|
2892
2906
|
ASSERT(isColor(color) && (!additiveColor || isColor(additiveColor)), 'drawTile color is invalid');
|
|
2893
2907
|
ASSERT(isNumber(angle), 'drawTile angle should be a number');
|
|
2894
2908
|
|
|
2909
|
+
if (color.a <= 0 && (!additiveColor || additiveColor.a <= 0) || !size.x || !size.y)
|
|
2910
|
+
return; // completely invisible, skip render
|
|
2911
|
+
|
|
2895
2912
|
const textureInfo = tileInfo && tileInfo.textureInfo;
|
|
2896
2913
|
if (useWebGL)
|
|
2897
2914
|
{
|
|
@@ -2942,18 +2959,15 @@ function drawTile(pos, size=new Vector2(1), tileInfo, color=new Color,
|
|
|
2942
2959
|
if (textureInfo)
|
|
2943
2960
|
{
|
|
2944
2961
|
// calculate uvs and render
|
|
2945
|
-
const x = tileInfo.pos.x
|
|
2946
|
-
const
|
|
2947
|
-
|
|
2948
|
-
const h = tileInfo.size.y - 2*tileFixBleedScale;
|
|
2949
|
-
context.globalAlpha = color.a; // only alpha is supported
|
|
2950
|
-
context.drawImage(textureInfo.image, x, y, w, h, -.5, -.5, 1, 1);
|
|
2951
|
-
context.globalAlpha = 1; // set back to full alpha
|
|
2962
|
+
const x = tileInfo.pos.x, y = tileInfo.pos.y;
|
|
2963
|
+
const w = tileInfo.size.x, h = tileInfo.size.y;
|
|
2964
|
+
drawImageColor(context, textureInfo.image, x, y, w, h, -.5, -.5, 1, 1, color, additiveColor);
|
|
2952
2965
|
}
|
|
2953
2966
|
else
|
|
2954
2967
|
{
|
|
2955
|
-
// if no tile info,
|
|
2956
|
-
|
|
2968
|
+
// if no tile info, use untextured rect
|
|
2969
|
+
const c = additiveColor ? color.add(additiveColor) : color;
|
|
2970
|
+
context.fillStyle = c.toString();
|
|
2957
2971
|
context.fillRect(-.5, -.5, 1, 1);
|
|
2958
2972
|
}
|
|
2959
2973
|
}, screenSpace, context);
|
|
@@ -2966,7 +2980,7 @@ function drawTile(pos, size=new Vector2(1), tileInfo, color=new Color,
|
|
|
2966
2980
|
* @param {Color} [color=(1,1,1,1)]
|
|
2967
2981
|
* @param {number} [angle]
|
|
2968
2982
|
* @param {boolean} [useWebGL=glEnable]
|
|
2969
|
-
* @param {boolean} [screenSpace
|
|
2983
|
+
* @param {boolean} [screenSpace]
|
|
2970
2984
|
* @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} [context]
|
|
2971
2985
|
* @memberof Draw */
|
|
2972
2986
|
function drawRect(pos, size, color, angle, useWebGL, screenSpace, context)
|
|
@@ -2979,73 +2993,90 @@ function drawRect(pos, size, color, angle, useWebGL, screenSpace, context)
|
|
|
2979
2993
|
* @param {Vector2} posB
|
|
2980
2994
|
* @param {number} [thickness]
|
|
2981
2995
|
* @param {Color} [color=(1,1,1,1)]
|
|
2996
|
+
* @param {Vector2} [pos=(0,0)] - Offset to apply
|
|
2997
|
+
* @param {number} [angle] - Angle to rotate by
|
|
2982
2998
|
* @param {boolean} [useWebGL=glEnable]
|
|
2983
|
-
* @param {boolean} [screenSpace
|
|
2999
|
+
* @param {boolean} [screenSpace]
|
|
2984
3000
|
* @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} [context]
|
|
2985
3001
|
* @memberof Draw */
|
|
2986
|
-
function drawLine(posA, posB, thickness=.1, color, useWebGL, screenSpace, context)
|
|
3002
|
+
function drawLine(posA, posB, thickness=.1, color, pos=vec2(), angle=0, useWebGL, screenSpace, context)
|
|
2987
3003
|
{
|
|
2988
3004
|
const halfDelta = vec2((posB.x - posA.x)/2, (posB.y - posA.y)/2);
|
|
2989
3005
|
const size = vec2(thickness, halfDelta.length()*2);
|
|
2990
|
-
|
|
3006
|
+
pos = pos.add(posA.add(halfDelta));
|
|
3007
|
+
angle += halfDelta.angle();
|
|
3008
|
+
drawRect(pos, size, color, angle, useWebGL, screenSpace, context);
|
|
2991
3009
|
}
|
|
2992
3010
|
|
|
2993
3011
|
/** Draw colored polygon using passed in points
|
|
2994
|
-
* @param {Array<Vector2>}
|
|
3012
|
+
* @param {Array<Vector2>} points - Array of Vector2 points
|
|
2995
3013
|
* @param {Color} [color=(1,1,1,1)]
|
|
2996
|
-
* @param {number} [lineWidth
|
|
3014
|
+
* @param {number} [lineWidth]
|
|
2997
3015
|
* @param {Color} [lineColor=(0,0,0,1)]
|
|
2998
|
-
* @param {
|
|
3016
|
+
* @param {Vector2} [pos=(0,0)] - Offset to apply
|
|
3017
|
+
* @param {number} [angle] - Angle to rotate by
|
|
3018
|
+
* @param {boolean} [useWebGL] - Webgl not supported
|
|
3019
|
+
* @param {boolean} [screenSpace]
|
|
2999
3020
|
* @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} [context=drawContext]
|
|
3000
3021
|
* @memberof Draw */
|
|
3001
|
-
function drawPoly(points, color=new Color, lineWidth=0, lineColor=
|
|
3022
|
+
function drawPoly(points, color=new Color, lineWidth=0, lineColor=BLACK, pos=vec2(), angle=0, useWebGL=false, screenSpace=false, context=drawContext)
|
|
3002
3023
|
{
|
|
3003
|
-
ASSERT(
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
if (lineWidth)
|
|
3024
|
+
ASSERT(isVector2(pos) && pos.isValid(), 'drawPoly pos should be a vec2');
|
|
3025
|
+
ASSERT(Array.isArray(points), 'drawPoly points should be an array');
|
|
3026
|
+
ASSERT(isColor(color) && isColor(lineColor), 'drawPoly color is invalid');
|
|
3027
|
+
ASSERT(isNumber(lineWidth), 'drawPoly lineWidth should be a number');
|
|
3028
|
+
ASSERT(isNumber(angle), 'drawPoly angle should be a number');
|
|
3029
|
+
ASSERT(!useWebGL, 'drawPoly webgl not supported');
|
|
3030
|
+
drawCanvas2D(pos, vec2(1), angle, false, context=>
|
|
3011
3031
|
{
|
|
3012
|
-
context.
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
|
|
3032
|
+
context.beginPath();
|
|
3033
|
+
for (const point of points)
|
|
3034
|
+
context.lineTo(point.x, point.y);
|
|
3035
|
+
context.closePath();
|
|
3036
|
+
context.fillStyle = color.toString();
|
|
3037
|
+
context.fill();
|
|
3038
|
+
if (lineWidth)
|
|
3039
|
+
{
|
|
3040
|
+
context.strokeStyle = lineColor.toString();
|
|
3041
|
+
context.lineWidth = lineWidth;
|
|
3042
|
+
context.stroke();
|
|
3043
|
+
}
|
|
3044
|
+
}, screenSpace, context);
|
|
3016
3045
|
}
|
|
3017
3046
|
|
|
3018
3047
|
/** Draw colored ellipse using passed in point
|
|
3019
3048
|
* @param {Vector2} pos
|
|
3020
|
-
* @param {
|
|
3021
|
-
* @param {number} [height=1]
|
|
3022
|
-
* @param {number} [angle=0]
|
|
3049
|
+
* @param {Vector2} [size=(1,1)]
|
|
3023
3050
|
* @param {Color} [color=(1,1,1,1)]
|
|
3024
|
-
* @param {number} [
|
|
3051
|
+
* @param {number} [angle]
|
|
3052
|
+
* @param {number} [lineWidth]
|
|
3025
3053
|
* @param {Color} [lineColor=(0,0,0,1)]
|
|
3026
|
-
* @param {boolean} [
|
|
3054
|
+
* @param {boolean} [useWebGL] - Webgl not supported
|
|
3055
|
+
* @param {boolean} [screenSpace]
|
|
3027
3056
|
* @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} [context=drawContext]
|
|
3028
3057
|
* @memberof Draw */
|
|
3029
|
-
function drawEllipse(pos,
|
|
3058
|
+
function drawEllipse(pos, size=vec2(1), color=new Color, angle=0, lineWidth=0, lineColor=BLACK, useWebGL=false, screenSpace=false, context=drawContext)
|
|
3030
3059
|
{
|
|
3031
|
-
ASSERT(
|
|
3032
|
-
|
|
3033
|
-
|
|
3034
|
-
|
|
3035
|
-
|
|
3036
|
-
|
|
3037
|
-
|
|
3038
|
-
|
|
3039
|
-
context.fillStyle = color.toString();
|
|
3040
|
-
context.beginPath();
|
|
3041
|
-
context.ellipse(pos.x, pos.y, width, height, angle, 0, 9);
|
|
3042
|
-
context.fill();
|
|
3043
|
-
if (lineWidth)
|
|
3060
|
+
ASSERT(isVector2(pos) && pos.isValid(), 'drawEllipse pos should be a vec2');
|
|
3061
|
+
ASSERT(isVector2(size) && size.isValid(), 'drawEllipse size should be a vec2');
|
|
3062
|
+
ASSERT(isColor(color) && isColor(lineColor), 'drawEllipse color is invalid');
|
|
3063
|
+
ASSERT(isNumber(angle), 'drawEllipse angle should be a number');
|
|
3064
|
+
ASSERT(isNumber(lineWidth), 'drawEllipse lineWidth should be a number');
|
|
3065
|
+
ASSERT(lineWidth>=0 && lineWidth < size.x && lineWidth < size.y, 'drawEllipse invalid lineWidth');
|
|
3066
|
+
ASSERT(!useWebGL, 'drawEllipse webgl not supported');
|
|
3067
|
+
drawCanvas2D(pos, vec2(1), angle, false, context=>
|
|
3044
3068
|
{
|
|
3045
|
-
context.
|
|
3046
|
-
context.
|
|
3047
|
-
context.
|
|
3048
|
-
|
|
3069
|
+
context.beginPath();
|
|
3070
|
+
context.ellipse(0, 0, size.y, size.x, 0, 0, 9);
|
|
3071
|
+
context.fillStyle = color.toString();
|
|
3072
|
+
context.fill();
|
|
3073
|
+
if (lineWidth)
|
|
3074
|
+
{
|
|
3075
|
+
context.strokeStyle = lineColor.toString();
|
|
3076
|
+
context.lineWidth = lineWidth;
|
|
3077
|
+
context.stroke();
|
|
3078
|
+
}
|
|
3079
|
+
}, screenSpace, context);
|
|
3049
3080
|
}
|
|
3050
3081
|
|
|
3051
3082
|
/** Draw colored circle using passed in point
|
|
@@ -3054,11 +3085,12 @@ function drawEllipse(pos, width=1, height=1, angle=0, color=new Color, lineWidth
|
|
|
3054
3085
|
* @param {Color} [color=(1,1,1,1)]
|
|
3055
3086
|
* @param {number} [lineWidth=0]
|
|
3056
3087
|
* @param {Color} [lineColor=(0,0,0,1)]
|
|
3088
|
+
* @param {boolean} [useWebGL] - Webgl not supported
|
|
3057
3089
|
* @param {boolean} [screenSpace=false]
|
|
3058
3090
|
* @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} [context=drawContext]
|
|
3059
3091
|
* @memberof Draw */
|
|
3060
|
-
function drawCircle(pos, radius=1, color=new Color, lineWidth=0, lineColor=
|
|
3061
|
-
{ drawEllipse(pos, radius,
|
|
3092
|
+
function drawCircle(pos, radius=1, color=new Color, lineWidth=0, lineColor=BLACK, useWebGL=false, screenSpace, context=drawContext)
|
|
3093
|
+
{ drawEllipse(pos, vec2(radius), color, 0, lineWidth, lineColor, useWebGL, screenSpace, context); }
|
|
3062
3094
|
|
|
3063
3095
|
/** Draw directly to a 2d canvas context in world space
|
|
3064
3096
|
* @param {Vector2} pos
|
|
@@ -3085,6 +3117,9 @@ function drawCanvas2D(pos, size, angle=0, mirror=false, drawFunction, screenSpac
|
|
|
3085
3117
|
context.restore();
|
|
3086
3118
|
}
|
|
3087
3119
|
|
|
3120
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
3121
|
+
// Text Drawing Functions
|
|
3122
|
+
|
|
3088
3123
|
/** Draw text on main canvas in world space
|
|
3089
3124
|
* Automatically splits new lines into rows
|
|
3090
3125
|
* @param {string} text
|
|
@@ -3133,7 +3168,7 @@ function drawTextOverlay(text, pos, size=1, color, lineWidth=0, lineColor, textA
|
|
|
3133
3168
|
* @param {number} [maxWidth]
|
|
3134
3169
|
* @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} [context=overlayContext]
|
|
3135
3170
|
* @memberof Draw */
|
|
3136
|
-
function drawTextScreen(text, pos, size=1, color=new Color, lineWidth=0, lineColor=
|
|
3171
|
+
function drawTextScreen(text, pos, size=1, color=new Color, lineWidth=0, lineColor=BLACK, textAlign='center', font=fontDefault, maxWidth=undefined, context=overlayContext)
|
|
3137
3172
|
{
|
|
3138
3173
|
context.fillStyle = color.toString();
|
|
3139
3174
|
context.strokeStyle = lineColor.toString();
|
|
@@ -3154,22 +3189,67 @@ function drawTextScreen(text, pos, size=1, color=new Color, lineWidth=0, lineCol
|
|
|
3154
3189
|
});
|
|
3155
3190
|
}
|
|
3156
3191
|
|
|
3192
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
3193
|
+
// Drawing utilities
|
|
3194
|
+
|
|
3195
|
+
/** Convert from screen to world space coordinates
|
|
3196
|
+
* @param {Vector2} screenPos
|
|
3197
|
+
* @return {Vector2}
|
|
3198
|
+
* @memberof Draw */
|
|
3199
|
+
function screenToWorld(screenPos)
|
|
3200
|
+
{
|
|
3201
|
+
let cameraPosRelativeX = (screenPos.x - mainCanvasSize.x/2 + .5) / cameraScale;
|
|
3202
|
+
let cameraPosRelativeY = (screenPos.y - mainCanvasSize.y/2 + .5) / -cameraScale;
|
|
3203
|
+
if (cameraAngle)
|
|
3204
|
+
{
|
|
3205
|
+
// apply camera rotation
|
|
3206
|
+
const cos = Math.cos(-cameraAngle), sin = Math.sin(-cameraAngle);
|
|
3207
|
+
const rotatedX = cameraPosRelativeX * cos - cameraPosRelativeY * sin;
|
|
3208
|
+
const rotatedY = cameraPosRelativeX * sin + cameraPosRelativeY * cos;
|
|
3209
|
+
cameraPosRelativeX = rotatedX;
|
|
3210
|
+
cameraPosRelativeY = rotatedY;
|
|
3211
|
+
}
|
|
3212
|
+
return new Vector2(cameraPosRelativeX + cameraPos.x, cameraPosRelativeY + cameraPos.y);
|
|
3213
|
+
}
|
|
3214
|
+
|
|
3215
|
+
/** Convert from world to screen space coordinates
|
|
3216
|
+
* @param {Vector2} worldPos
|
|
3217
|
+
* @return {Vector2}
|
|
3218
|
+
* @memberof Draw */
|
|
3219
|
+
function worldToScreen(worldPos)
|
|
3220
|
+
{
|
|
3221
|
+
let cameraPosRelativeX = worldPos.x - cameraPos.x;
|
|
3222
|
+
let cameraPosRelativeY = worldPos.y - cameraPos.y;
|
|
3223
|
+
if (cameraAngle)
|
|
3224
|
+
{
|
|
3225
|
+
// apply inverse camera rotation
|
|
3226
|
+
const cos = Math.cos(cameraAngle), sin = Math.sin(cameraAngle);
|
|
3227
|
+
const rotatedX = cameraPosRelativeX * cos - cameraPosRelativeY * sin;
|
|
3228
|
+
const rotatedY = cameraPosRelativeX * sin + cameraPosRelativeY * cos;
|
|
3229
|
+
cameraPosRelativeX = rotatedX;
|
|
3230
|
+
cameraPosRelativeY = rotatedY;
|
|
3231
|
+
}
|
|
3232
|
+
return new Vector2
|
|
3233
|
+
(
|
|
3234
|
+
cameraPosRelativeX * cameraScale + mainCanvasSize.x/2 - .5,
|
|
3235
|
+
cameraPosRelativeY * -cameraScale + mainCanvasSize.y/2 - .5
|
|
3236
|
+
);
|
|
3237
|
+
}
|
|
3238
|
+
|
|
3239
|
+
/** Get the camera's visible area in world space
|
|
3240
|
+
* @return {Vector2}
|
|
3241
|
+
* @memberof Draw */
|
|
3242
|
+
function getCameraSize() { return mainCanvasSize.scale(1/cameraScale); }
|
|
3243
|
+
|
|
3157
3244
|
/** Enable normal or additive blend mode
|
|
3158
3245
|
* @param {boolean} [additive]
|
|
3159
|
-
* @param {boolean} [useWebGL=glEnable]
|
|
3160
3246
|
* @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} [context]
|
|
3161
3247
|
* @memberof Draw */
|
|
3162
|
-
function setBlendMode(additive=false,
|
|
3248
|
+
function setBlendMode(additive=false, context)
|
|
3163
3249
|
{
|
|
3164
|
-
|
|
3165
|
-
|
|
3166
|
-
|
|
3167
|
-
else
|
|
3168
|
-
{
|
|
3169
|
-
if (!context)
|
|
3170
|
-
context = drawContext;
|
|
3171
|
-
context.globalCompositeOperation = additive ? 'lighter' : 'source-over';
|
|
3172
|
-
}
|
|
3250
|
+
glAdditive = additive;
|
|
3251
|
+
context ||= drawContext;
|
|
3252
|
+
context.globalCompositeOperation = additive ? 'lighter' : 'source-over';
|
|
3173
3253
|
}
|
|
3174
3254
|
|
|
3175
3255
|
/** Combines all LittleJS canvases onto the main canvas and clears them
|
|
@@ -3186,6 +3266,102 @@ function combineCanvases()
|
|
|
3186
3266
|
overlayCanvas.width |= 0;
|
|
3187
3267
|
}
|
|
3188
3268
|
|
|
3269
|
+
/** Helper function to draw an image with color and additive color applied
|
|
3270
|
+
* This is slower then normal drawImage when color is applied
|
|
3271
|
+
* @param {CanvasRenderingContext2D|OffscreenCanvasRenderingContext2D} context
|
|
3272
|
+
* @param {HTMLImageElement|OffscreenCanvas} image
|
|
3273
|
+
* @param {number} sx
|
|
3274
|
+
* @param {number} sy
|
|
3275
|
+
* @param {number} sWidth
|
|
3276
|
+
* @param {number} sHeight
|
|
3277
|
+
* @param {number} dx
|
|
3278
|
+
* @param {number} dy
|
|
3279
|
+
* @param {number} dWidth
|
|
3280
|
+
* @param {number} dHeight
|
|
3281
|
+
* @param {Color} color
|
|
3282
|
+
* @param {Color} [additiveColor]
|
|
3283
|
+
* @memberof Draw */
|
|
3284
|
+
function drawImageColor(context, image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight, color, additiveColor)
|
|
3285
|
+
{
|
|
3286
|
+
function isWhite(c) { return c.r >= 1 && c.g >= 1 && c.b >= 1; }
|
|
3287
|
+
function isBlack(c) { return c.r <= 0 && c.g <= 0 && c.b <= 0 && c.a <= 0; }
|
|
3288
|
+
const sx2 = tileFixBleedScale;
|
|
3289
|
+
const sy2 = tileFixBleedScale;
|
|
3290
|
+
const sWidth2 = sWidth - 2*tileFixBleedScale;
|
|
3291
|
+
const sHeight2 = sHeight - 2*tileFixBleedScale;
|
|
3292
|
+
if (!canvasColorTiles || (additiveColor ? isWhite(color.add(additiveColor)) && additiveColor.a <= 0 : isWhite(color)))
|
|
3293
|
+
{
|
|
3294
|
+
// white texture with no additive alpha, no need to tint
|
|
3295
|
+
context.globalAlpha = color.a;
|
|
3296
|
+
context.drawImage(image, sx+sx2, sy+sy2, sWidth2, sHeight2, dx, dy, dWidth, dHeight);
|
|
3297
|
+
context.globalAlpha = 1;
|
|
3298
|
+
}
|
|
3299
|
+
else
|
|
3300
|
+
{
|
|
3301
|
+
// copy to offscreen canvas
|
|
3302
|
+
workCanvas.width = sWidth;
|
|
3303
|
+
workCanvas.height = sHeight;
|
|
3304
|
+
workContext.drawImage(image, sx, sy, sWidth, sHeight, 0, 0, sWidth, sHeight);
|
|
3305
|
+
|
|
3306
|
+
// tint image using offscreen work context
|
|
3307
|
+
const imageData = workContext.getImageData(0, 0, sWidth, sHeight);
|
|
3308
|
+
const data = imageData.data;
|
|
3309
|
+
if (additiveColor && !isBlack(additiveColor))
|
|
3310
|
+
{
|
|
3311
|
+
// slower path with additive color
|
|
3312
|
+
const colorMultiply = [color.r, color.g, color.b, color.a];
|
|
3313
|
+
const colorAdd = [additiveColor.r * 255, additiveColor.g * 255, additiveColor.b * 255, additiveColor.a * 255];
|
|
3314
|
+
for (let i = 0; i < data.length; ++i)
|
|
3315
|
+
data[i] = data[i] * colorMultiply[i&3] + colorAdd[i&3] |0;
|
|
3316
|
+
workContext.putImageData(imageData, 0, 0);
|
|
3317
|
+
context.drawImage(workCanvas, sx2, sy2, sWidth2, sHeight2, dx, dy, dWidth, dHeight);
|
|
3318
|
+
}
|
|
3319
|
+
else
|
|
3320
|
+
{
|
|
3321
|
+
// faster path with no additive color
|
|
3322
|
+
for (let i = 0; i < data.length; i+=4)
|
|
3323
|
+
{
|
|
3324
|
+
data[i ] *= color.r;
|
|
3325
|
+
data[i+1] *= color.g;
|
|
3326
|
+
data[i+2] *= color.b;
|
|
3327
|
+
}
|
|
3328
|
+
workContext.putImageData(imageData, 0, 0);
|
|
3329
|
+
context.globalAlpha = color.a;
|
|
3330
|
+
context.drawImage(workCanvas, sx2, sy2, sWidth2, sHeight2, dx, dy, dWidth, dHeight);
|
|
3331
|
+
context.globalAlpha = 1;
|
|
3332
|
+
}
|
|
3333
|
+
}
|
|
3334
|
+
}
|
|
3335
|
+
|
|
3336
|
+
|
|
3337
|
+
/** Returns true if fullscreen mode is active
|
|
3338
|
+
* @return {boolean}
|
|
3339
|
+
* @memberof Draw */
|
|
3340
|
+
function isFullscreen() { return !!document.fullscreenElement; }
|
|
3341
|
+
|
|
3342
|
+
/** Toggle fullscreen mode
|
|
3343
|
+
* @memberof Draw */
|
|
3344
|
+
function toggleFullscreen()
|
|
3345
|
+
{
|
|
3346
|
+
const rootElement = mainCanvas.parentElement;
|
|
3347
|
+
if (isFullscreen())
|
|
3348
|
+
{
|
|
3349
|
+
if (document.exitFullscreen)
|
|
3350
|
+
document.exitFullscreen();
|
|
3351
|
+
}
|
|
3352
|
+
else if (rootElement.requestFullscreen)
|
|
3353
|
+
rootElement.requestFullscreen();
|
|
3354
|
+
}
|
|
3355
|
+
|
|
3356
|
+
/** Set the cursor style
|
|
3357
|
+
* @param {string} cursorStyle - CSS cursor style (auto, none, crosshair, etc)
|
|
3358
|
+
* @memberof Draw */
|
|
3359
|
+
function setCursor(cursorStyle = 'auto')
|
|
3360
|
+
{
|
|
3361
|
+
const rootElement = mainCanvas.parentElement;
|
|
3362
|
+
rootElement.style.cursor = cursorStyle;
|
|
3363
|
+
}
|
|
3364
|
+
|
|
3189
3365
|
///////////////////////////////////////////////////////////////////////////////
|
|
3190
3366
|
|
|
3191
3367
|
let engineFontImage;
|
|
@@ -3253,7 +3429,7 @@ class FontImage
|
|
|
3253
3429
|
(text+'').split('\n').forEach((line, i)=>
|
|
3254
3430
|
{
|
|
3255
3431
|
const centerOffset = center ? line.length * size.x * scale / 2 |0 : 0;
|
|
3256
|
-
for(let j=line.length; j--;)
|
|
3432
|
+
for (let j=line.length; j--;)
|
|
3257
3433
|
{
|
|
3258
3434
|
// draw each character
|
|
3259
3435
|
let charCode = line[j].charCodeAt(0);
|
|
@@ -3272,37 +3448,6 @@ class FontImage
|
|
|
3272
3448
|
|
|
3273
3449
|
context.restore();
|
|
3274
3450
|
}
|
|
3275
|
-
}
|
|
3276
|
-
|
|
3277
|
-
///////////////////////////////////////////////////////////////////////////////
|
|
3278
|
-
// Display functions
|
|
3279
|
-
|
|
3280
|
-
/** Returns true if fullscreen mode is active
|
|
3281
|
-
* @return {boolean}
|
|
3282
|
-
* @memberof Draw */
|
|
3283
|
-
function isFullscreen() { return !!document.fullscreenElement; }
|
|
3284
|
-
|
|
3285
|
-
/** Toggle fullscreen mode
|
|
3286
|
-
* @memberof Draw */
|
|
3287
|
-
function toggleFullscreen()
|
|
3288
|
-
{
|
|
3289
|
-
const rootElement = mainCanvas.parentElement;
|
|
3290
|
-
if (isFullscreen())
|
|
3291
|
-
{
|
|
3292
|
-
if (document.exitFullscreen)
|
|
3293
|
-
document.exitFullscreen();
|
|
3294
|
-
}
|
|
3295
|
-
else if (rootElement.requestFullscreen)
|
|
3296
|
-
rootElement.requestFullscreen();
|
|
3297
|
-
}
|
|
3298
|
-
|
|
3299
|
-
/** Set the cursor style
|
|
3300
|
-
* @param {string} cursorStyle - CSS cursor style (auto, none, crosshair, etc)
|
|
3301
|
-
* @memberof Draw */
|
|
3302
|
-
function setCursor(cursorStyle = 'auto')
|
|
3303
|
-
{
|
|
3304
|
-
const rootElement = mainCanvas.parentElement;
|
|
3305
|
-
rootElement.style.cursor = cursorStyle;
|
|
3306
3451
|
}
|
|
3307
3452
|
/**
|
|
3308
3453
|
* LittleJS Input System
|
|
@@ -3854,7 +3999,7 @@ function touchGamepadRender()
|
|
|
3854
3999
|
}
|
|
3855
4000
|
else // draw cross shaped gamepad
|
|
3856
4001
|
{
|
|
3857
|
-
for(let i=10; i--;)
|
|
4002
|
+
for (let i=10; i--;)
|
|
3858
4003
|
{
|
|
3859
4004
|
const angle = i*PI/4;
|
|
3860
4005
|
context.arc(leftCenter.x, leftCenter.y,touchGamepadSize*.6, angle + PI/8, angle + PI/8);
|
|
@@ -3898,7 +4043,7 @@ function pointerLockExit() { document.exitPointerLock && document.exitPointerLoc
|
|
|
3898
4043
|
/** Check if pointer is locked (true if locked)
|
|
3899
4044
|
* @return {boolean}
|
|
3900
4045
|
* @memberof Input */
|
|
3901
|
-
function pointerLockIsActive() { return document.pointerLockElement == mainCanvas }
|
|
4046
|
+
function pointerLockIsActive() { return document.pointerLockElement == mainCanvas; }
|
|
3902
4047
|
/**
|
|
3903
4048
|
* LittleJS Audio System
|
|
3904
4049
|
* - <a href=https://killedbyapixel.github.io/ZzFX/>ZzFX Sound Effects</a> - ZzFX Sound Effect Generator
|
|
@@ -4322,7 +4467,7 @@ function zzfxG
|
|
|
4322
4467
|
repeatTime = repeatTime * sampleRate | 0;
|
|
4323
4468
|
|
|
4324
4469
|
// generate waveform
|
|
4325
|
-
for(length = attack + decay + sustain + release + delay | 0;
|
|
4470
|
+
for (length = attack + decay + sustain + release + delay | 0;
|
|
4326
4471
|
i < length; b[i++] = s * volume) // sample
|
|
4327
4472
|
{
|
|
4328
4473
|
if (!(++crush%(bitCrush*100|0))) // bit crush
|
|
@@ -5215,10 +5360,17 @@ class ParticleEmitter extends EngineObject
|
|
|
5215
5360
|
const particle = new Particle(pos, this.tileInfo, angle, colorStart, colorEnd, particleTime, sizeStart, sizeEnd, this.fadeRate, this.additive, this.trailScale, this.localSpace && this, this.particleDestroyCallback);
|
|
5216
5361
|
particle.velocity = vec2().setAngle(velocityAngle, speed);
|
|
5217
5362
|
particle.angleVelocity = angleSpeed;
|
|
5363
|
+
if (!this.localSpace)
|
|
5364
|
+
{
|
|
5365
|
+
// apply emitter velocity to particle
|
|
5366
|
+
particle.velocity.x += this.velocity.x;
|
|
5367
|
+
particle.velocity.y += this.velocity.y;
|
|
5368
|
+
particle.angleVelocity += this.angleVelocity;
|
|
5369
|
+
}
|
|
5218
5370
|
particle.fadeRate = this.fadeRate;
|
|
5219
5371
|
particle.damping = this.damping;
|
|
5220
5372
|
particle.angleDamping = this.angleDamping;
|
|
5221
|
-
particle.restitution
|
|
5373
|
+
particle.restitution = this.restitution;
|
|
5222
5374
|
particle.friction = this.friction;
|
|
5223
5375
|
particle.gravityScale = this.gravityScale;
|
|
5224
5376
|
particle.collideTiles = this.collideTiles;
|
|
@@ -5505,7 +5657,7 @@ class Medal
|
|
|
5505
5657
|
context.save();
|
|
5506
5658
|
context.beginPath();
|
|
5507
5659
|
context.fillStyle = new Color(.9,.9,.9).toString();
|
|
5508
|
-
context.strokeStyle =
|
|
5660
|
+
context.strokeStyle = BLACK.toString();
|
|
5509
5661
|
context.lineWidth = 3;
|
|
5510
5662
|
context.rect(x, y, width, height);
|
|
5511
5663
|
context.fill();
|
|
@@ -5522,11 +5674,11 @@ class Medal
|
|
|
5522
5674
|
const descriptionSize = height*.3;
|
|
5523
5675
|
const pos = vec2(x + medalDisplayIconSize + 2*gap.x, y + gap.y*2 + nameSize/2);
|
|
5524
5676
|
const textWidth = width - medalDisplayIconSize - 3*gap.x;
|
|
5525
|
-
drawTextScreen(this.name, pos, nameSize,
|
|
5677
|
+
drawTextScreen(this.name, pos, nameSize, BLACK, 0, undefined, 'left', undefined, textWidth);
|
|
5526
5678
|
|
|
5527
5679
|
// draw the description
|
|
5528
5680
|
pos.y = y + height - gap.y*2 - descriptionSize/2;
|
|
5529
|
-
drawTextScreen(this.description, pos, descriptionSize,
|
|
5681
|
+
drawTextScreen(this.description, pos, descriptionSize, BLACK, 0, undefined, 'left', undefined, textWidth);
|
|
5530
5682
|
context.restore();
|
|
5531
5683
|
}
|
|
5532
5684
|
|
|
@@ -5540,7 +5692,7 @@ class Medal
|
|
|
5540
5692
|
if (this.image)
|
|
5541
5693
|
overlayContext.drawImage(this.image, pos.x-size/2, pos.y-size/2, size, size);
|
|
5542
5694
|
else
|
|
5543
|
-
drawTextScreen(this.icon, pos, size*.7,
|
|
5695
|
+
drawTextScreen(this.icon, pos, size*.7, BLACK);
|
|
5544
5696
|
}
|
|
5545
5697
|
|
|
5546
5698
|
// Get local storage key used by the medal
|
|
@@ -5549,12 +5701,13 @@ class Medal
|
|
|
5549
5701
|
/**
|
|
5550
5702
|
* LittleJS WebGL Interface
|
|
5551
5703
|
* - All webgl used by the engine is wrapped up here
|
|
5704
|
+
* - Will fall back to 2D canvas rendering if webgl is not supported
|
|
5552
5705
|
* - For normal stuff you won't need to see or call anything in this file
|
|
5553
5706
|
* - For advanced stuff there are helper functions to create shaders, textures, etc
|
|
5554
5707
|
* - Can be disabled with glEnable to revert to 2D canvas rendering
|
|
5555
5708
|
* - Batches sprite rendering on GPU for incredibly fast performance
|
|
5556
5709
|
* - Sprite transform math is done in the shader where possible
|
|
5557
|
-
* - Supports shadertoy style post processing shaders
|
|
5710
|
+
* - Supports shadertoy style post processing shaders via plugin
|
|
5558
5711
|
* @namespace WebGL
|
|
5559
5712
|
*/
|
|
5560
5713
|
|
|
@@ -5593,6 +5746,14 @@ function glInit()
|
|
|
5593
5746
|
glCanvas = document.createElement('canvas');
|
|
5594
5747
|
glContext = glCanvas.getContext('webgl2', {antialias:glAntialias});
|
|
5595
5748
|
|
|
5749
|
+
if (!glContext)
|
|
5750
|
+
{
|
|
5751
|
+
console.warn('WebGL2 not supported, falling back to 2D canvas rendering!');
|
|
5752
|
+
glCanvas = glContext = undefined;
|
|
5753
|
+
glEnable = false;
|
|
5754
|
+
return;
|
|
5755
|
+
}
|
|
5756
|
+
|
|
5596
5757
|
// create the webgl canvas
|
|
5597
5758
|
const rootElement = mainCanvas.parentElement;
|
|
5598
5759
|
rootElement.appendChild(glCanvas);
|
|
@@ -5642,7 +5803,7 @@ function glInit()
|
|
|
5642
5803
|
// Also used by tile layer rendering when redrawing tiles
|
|
5643
5804
|
function glPreRender()
|
|
5644
5805
|
{
|
|
5645
|
-
if (!glEnable ||
|
|
5806
|
+
if (!glEnable || !glContext) return;
|
|
5646
5807
|
|
|
5647
5808
|
// set up the shader and canvas
|
|
5648
5809
|
glClearCanvas();
|
|
@@ -5693,6 +5854,8 @@ function glPreRender()
|
|
|
5693
5854
|
* @memberof WebGL */
|
|
5694
5855
|
function glClearCanvas()
|
|
5695
5856
|
{
|
|
5857
|
+
if (!glContext) return;
|
|
5858
|
+
|
|
5696
5859
|
// clear and set to same size as main canvas
|
|
5697
5860
|
glContext.viewport(0, 0, glCanvas.width=drawCanvas.width, glCanvas.height=drawCanvas.height);
|
|
5698
5861
|
glContext.clear(glContext.COLOR_BUFFER_BIT);
|
|
@@ -5706,7 +5869,7 @@ function glClearCanvas()
|
|
|
5706
5869
|
function glSetTexture(texture, wrap=false)
|
|
5707
5870
|
{
|
|
5708
5871
|
// must flush cache with the old texture to set a new one
|
|
5709
|
-
if (
|
|
5872
|
+
if (!glContext || texture == glActiveTexture)
|
|
5710
5873
|
return;
|
|
5711
5874
|
|
|
5712
5875
|
glFlush();
|
|
@@ -5725,6 +5888,8 @@ function glSetTexture(texture, wrap=false)
|
|
|
5725
5888
|
* @memberof WebGL */
|
|
5726
5889
|
function glCompileShader(source, type)
|
|
5727
5890
|
{
|
|
5891
|
+
if (!glContext) return;
|
|
5892
|
+
|
|
5728
5893
|
// build the shader
|
|
5729
5894
|
const shader = glContext.createShader(type);
|
|
5730
5895
|
glContext.shaderSource(shader, source);
|
|
@@ -5743,6 +5908,8 @@ function glCompileShader(source, type)
|
|
|
5743
5908
|
* @memberof WebGL */
|
|
5744
5909
|
function glCreateProgram(vsSource, fsSource)
|
|
5745
5910
|
{
|
|
5911
|
+
if (!glContext) return;
|
|
5912
|
+
|
|
5746
5913
|
// build the program
|
|
5747
5914
|
const program = glContext.createProgram();
|
|
5748
5915
|
glContext.attachShader(program, glCompileShader(vsSource, glContext.VERTEX_SHADER));
|
|
@@ -5761,6 +5928,8 @@ function glCreateProgram(vsSource, fsSource)
|
|
|
5761
5928
|
* @memberof WebGL */
|
|
5762
5929
|
function glCreateTexture(image)
|
|
5763
5930
|
{
|
|
5931
|
+
if (!glContext) return;
|
|
5932
|
+
|
|
5764
5933
|
// build the texture
|
|
5765
5934
|
const texture = glContext.createTexture();
|
|
5766
5935
|
glContext.bindTexture(glContext.TEXTURE_2D, texture);
|
|
@@ -5796,6 +5965,7 @@ function glCreateTexture(image)
|
|
|
5796
5965
|
* @memberof WebGL */
|
|
5797
5966
|
function glDeleteTexture(texture)
|
|
5798
5967
|
{
|
|
5968
|
+
if (!glContext) return;
|
|
5799
5969
|
glContext.deleteTexture(texture);
|
|
5800
5970
|
}
|
|
5801
5971
|
|
|
@@ -5805,6 +5975,8 @@ function glDeleteTexture(texture)
|
|
|
5805
5975
|
* @memberof WebGL */
|
|
5806
5976
|
function glSetTextureData(texture, image)
|
|
5807
5977
|
{
|
|
5978
|
+
if (!glContext) return;
|
|
5979
|
+
|
|
5808
5980
|
// build the texture
|
|
5809
5981
|
ASSERT(!!image && image.width > 0, 'Invalid image data.');
|
|
5810
5982
|
glContext.bindTexture(glContext.TEXTURE_2D, texture);
|
|
@@ -5815,7 +5987,7 @@ function glSetTextureData(texture, image)
|
|
|
5815
5987
|
* @memberof WebGL */
|
|
5816
5988
|
function glFlush()
|
|
5817
5989
|
{
|
|
5818
|
-
if (!glEnable || !glInstanceCount) return;
|
|
5990
|
+
if (!glEnable || !glContext || !glInstanceCount) return;
|
|
5819
5991
|
|
|
5820
5992
|
const destBlend = glBatchAdditive ? glContext.ONE : glContext.ONE_MINUS_SRC_ALPHA;
|
|
5821
5993
|
glContext.blendFuncSeparate(glContext.SRC_ALPHA, destBlend, glContext.ONE, destBlend);
|
|
@@ -5835,7 +6007,7 @@ function glFlush()
|
|
|
5835
6007
|
* @memberof WebGL */
|
|
5836
6008
|
function glCopyToContext(context)
|
|
5837
6009
|
{
|
|
5838
|
-
if (!glEnable)
|
|
6010
|
+
if (!glEnable || !glContext)
|
|
5839
6011
|
return;
|
|
5840
6012
|
|
|
5841
6013
|
glFlush();
|
|
@@ -6090,6 +6262,13 @@ class PostProcessPlugin
|
|
|
6090
6262
|
postProcess = this;
|
|
6091
6263
|
|
|
6092
6264
|
if (headlessMode) return;
|
|
6265
|
+
|
|
6266
|
+
if (!glEnable)
|
|
6267
|
+
{
|
|
6268
|
+
console.warn('PostProcessPlugin: WebGL not enabled!');
|
|
6269
|
+
return;
|
|
6270
|
+
}
|
|
6271
|
+
|
|
6093
6272
|
if (!shaderCode) // default shader pass through
|
|
6094
6273
|
shaderCode = 'void mainImage(out vec4 c,vec2 p){c=texture(iChannel0,p/iResolution.xy);}';
|
|
6095
6274
|
|
|
@@ -6399,7 +6578,7 @@ class UISystemPlugin
|
|
|
6399
6578
|
|
|
6400
6579
|
function updateInvisible(o)
|
|
6401
6580
|
{
|
|
6402
|
-
for(const c of o.children)
|
|
6581
|
+
for (const c of o.children)
|
|
6403
6582
|
updateInvisible(c);
|
|
6404
6583
|
o.updateInvisible();
|
|
6405
6584
|
}
|
|
@@ -6415,7 +6594,7 @@ class UISystemPlugin
|
|
|
6415
6594
|
if (o.parent)
|
|
6416
6595
|
o.pos = o.localPos.add(o.parent.pos);
|
|
6417
6596
|
// update in reverse order to detect mouse enter/leave
|
|
6418
|
-
for(let i=o.children.length; i--;)
|
|
6597
|
+
for (let i=o.children.length; i--;)
|
|
6419
6598
|
updateObject(o.children[i]);
|
|
6420
6599
|
o.update();
|
|
6421
6600
|
}
|
|
@@ -6433,7 +6612,7 @@ class UISystemPlugin
|
|
|
6433
6612
|
if (o.parent)
|
|
6434
6613
|
o.pos = o.localPos.add(o.parent.pos);
|
|
6435
6614
|
o.render();
|
|
6436
|
-
for(const c of o.children)
|
|
6615
|
+
for (const c of o.children)
|
|
6437
6616
|
renderObject(c);
|
|
6438
6617
|
}
|
|
6439
6618
|
uiSystem.uiObjects.forEach(o=> o.parent || renderObject(o));
|
|
@@ -6490,7 +6669,7 @@ class UISystemPlugin
|
|
|
6490
6669
|
* @param {boolean} [mirror] */
|
|
6491
6670
|
drawTile(pos, size, tileInfo, color=uiSystem.defaultColor, angle=0, mirror=false)
|
|
6492
6671
|
{
|
|
6493
|
-
drawTile(pos, size, tileInfo, color, angle, mirror,
|
|
6672
|
+
drawTile(pos, size, tileInfo, color, angle, mirror, CLEAR_BLACK, false, true, uiSystem.uiContext);
|
|
6494
6673
|
}
|
|
6495
6674
|
|
|
6496
6675
|
/** Draw text to the UI context
|
|
@@ -6940,7 +7119,7 @@ class Box2dObject extends EngineObject
|
|
|
6940
7119
|
bodyDef.set_angle(-angle);
|
|
6941
7120
|
this.body = box2d.world.CreateBody(bodyDef);
|
|
6942
7121
|
this.body.object = this;
|
|
6943
|
-
this.
|
|
7122
|
+
this.lineColor = BLACK;
|
|
6944
7123
|
}
|
|
6945
7124
|
|
|
6946
7125
|
/** Destroy this object and it's physics body */
|
|
@@ -6967,7 +7146,7 @@ class Box2dObject extends EngineObject
|
|
|
6967
7146
|
if (this.tileInfo)
|
|
6968
7147
|
super.render();
|
|
6969
7148
|
else
|
|
6970
|
-
this.drawFixtures(this.color, this.
|
|
7149
|
+
this.drawFixtures(this.color, this.lineColor, this.lineWidth, mainContext);
|
|
6971
7150
|
}
|
|
6972
7151
|
|
|
6973
7152
|
/** Render debug info */
|
|
@@ -6981,13 +7160,13 @@ class Box2dObject extends EngineObject
|
|
|
6981
7160
|
|
|
6982
7161
|
/** Draws all this object's fixtures
|
|
6983
7162
|
* @param {Color} [color]
|
|
6984
|
-
* @param {Color} [
|
|
7163
|
+
* @param {Color} [lineColor]
|
|
6985
7164
|
* @param {number} [lineWidth]
|
|
6986
7165
|
* @param {CanvasRenderingContext2D} [context] */
|
|
6987
|
-
drawFixtures(color=WHITE,
|
|
7166
|
+
drawFixtures(color=WHITE, lineColor, lineWidth=.1, context)
|
|
6988
7167
|
{
|
|
6989
7168
|
this.getFixtureList().forEach(fixture=>
|
|
6990
|
-
box2d.drawFixture(fixture, this.pos, this.angle, color,
|
|
7169
|
+
box2d.drawFixture(fixture, this.pos, this.angle, color, lineColor, lineWidth, context));
|
|
6991
7170
|
}
|
|
6992
7171
|
|
|
6993
7172
|
///////////////////////////////////////////////////////////////////////////////
|
|
@@ -8468,10 +8647,10 @@ class Box2dPlugin
|
|
|
8468
8647
|
* @param {Vector2} pos
|
|
8469
8648
|
* @param {number} angle
|
|
8470
8649
|
* @param {Color} [color]
|
|
8471
|
-
* @param {Color} [
|
|
8650
|
+
* @param {Color} [lineColor]
|
|
8472
8651
|
* @param {number} [lineWidth]
|
|
8473
8652
|
* @param {CanvasRenderingContext2D} [context] */
|
|
8474
|
-
drawFixture(fixture, pos, angle, color=WHITE,
|
|
8653
|
+
drawFixture(fixture, pos, angle, color=WHITE, lineColor=BLACK, lineWidth=.1, context=drawContext)
|
|
8475
8654
|
{
|
|
8476
8655
|
const shape = box2d.castObjectType(fixture.GetShape());
|
|
8477
8656
|
switch (shape.GetType())
|
|
@@ -8481,101 +8660,25 @@ class Box2dPlugin
|
|
|
8481
8660
|
let points = [];
|
|
8482
8661
|
for (let i=shape.GetVertexCount(); i--;)
|
|
8483
8662
|
points.push(box2d.vec2From(shape.GetVertex(i)));
|
|
8484
|
-
|
|
8663
|
+
drawPoly(points, color, lineWidth, lineColor, pos, angle, false, false, context);
|
|
8485
8664
|
break;
|
|
8486
8665
|
}
|
|
8487
8666
|
case box2d.instance.b2Shape.e_circle:
|
|
8488
8667
|
{
|
|
8489
8668
|
const radius = shape.get_m_radius();
|
|
8490
|
-
|
|
8669
|
+
drawCircle(pos, radius, color, lineWidth, lineColor, false, false, context);
|
|
8491
8670
|
break;
|
|
8492
8671
|
}
|
|
8493
8672
|
case box2d.instance.b2Shape.e_edge:
|
|
8494
8673
|
{
|
|
8495
8674
|
const v1 = box2d.vec2From(shape.get_m_vertex1());
|
|
8496
8675
|
const v2 = box2d.vec2From(shape.get_m_vertex2());
|
|
8497
|
-
|
|
8676
|
+
drawLine(v1, v2, lineWidth, lineColor, pos, angle, false, false, context);
|
|
8498
8677
|
break;
|
|
8499
8678
|
}
|
|
8500
8679
|
}
|
|
8501
8680
|
}
|
|
8502
8681
|
|
|
8503
|
-
/** draws a circle
|
|
8504
|
-
* @param {Vector2} pos
|
|
8505
|
-
* @param {number} radius
|
|
8506
|
-
* @param {Color} [color]
|
|
8507
|
-
* @param {Color} [outlineColor]
|
|
8508
|
-
* @param {number} [lineWidth]
|
|
8509
|
-
* @param {CanvasRenderingContext2D} [context] */
|
|
8510
|
-
drawCircle(pos, radius, color=WHITE, outlineColor=BLACK, lineWidth=.1, context=drawContext)
|
|
8511
|
-
{
|
|
8512
|
-
drawCanvas2D(pos, vec2(1), 0, 0, context=>
|
|
8513
|
-
{
|
|
8514
|
-
context.beginPath();
|
|
8515
|
-
context.arc(0, 0, radius, 0, 9);
|
|
8516
|
-
box2d.drawFillStroke(color, outlineColor, lineWidth, context);
|
|
8517
|
-
}, 0, context);
|
|
8518
|
-
}
|
|
8519
|
-
|
|
8520
|
-
/** draws a polygon
|
|
8521
|
-
* @param {Vector2} pos
|
|
8522
|
-
* @param {number} angle
|
|
8523
|
-
* @param {Array<Vector2>} points
|
|
8524
|
-
* @param {Color} [color]
|
|
8525
|
-
* @param {Color} [outlineColor]
|
|
8526
|
-
* @param {number} [lineWidth]
|
|
8527
|
-
* @param {CanvasRenderingContext2D} [context] */
|
|
8528
|
-
drawPoly(pos, angle, points, color=WHITE, outlineColor=BLACK, lineWidth=.1, context=drawContext)
|
|
8529
|
-
{
|
|
8530
|
-
drawCanvas2D(pos, vec2(1), angle, 0, context=>
|
|
8531
|
-
{
|
|
8532
|
-
context.beginPath();
|
|
8533
|
-
points.forEach(p=>context.lineTo(p.x, p.y));
|
|
8534
|
-
context.closePath();
|
|
8535
|
-
box2d.drawFillStroke(color, outlineColor, lineWidth, context);
|
|
8536
|
-
}, 0, context);
|
|
8537
|
-
}
|
|
8538
|
-
|
|
8539
|
-
/** draws a line
|
|
8540
|
-
* @param {Vector2} pos
|
|
8541
|
-
* @param {number} angle
|
|
8542
|
-
* @param {Vector2} posA
|
|
8543
|
-
* @param {Vector2} posB
|
|
8544
|
-
* @param {Color} [color]
|
|
8545
|
-
* @param {number} [lineWidth]
|
|
8546
|
-
* @param {CanvasRenderingContext2D} [context] */
|
|
8547
|
-
drawLine(pos, angle, posA, posB, color=WHITE, lineWidth=.1, context=drawContext)
|
|
8548
|
-
{
|
|
8549
|
-
drawCanvas2D(pos, vec2(1), angle, 0, context=>
|
|
8550
|
-
{
|
|
8551
|
-
context.beginPath();
|
|
8552
|
-
context.lineTo(posA.x, posA.y);
|
|
8553
|
-
context.lineTo(posB.x, posB.y);
|
|
8554
|
-
box2d.drawFillStroke(0, color, lineWidth, context);
|
|
8555
|
-
}, 0, context);
|
|
8556
|
-
}
|
|
8557
|
-
|
|
8558
|
-
/** performs a fill or stroke as a helper to the other draw functions
|
|
8559
|
-
* @param {Color} [color]
|
|
8560
|
-
* @param {Color} [outlineColor]
|
|
8561
|
-
* @param {number} [lineWidth]
|
|
8562
|
-
* @param {CanvasRenderingContext2D} [context] */
|
|
8563
|
-
drawFillStroke(color=WHITE, outlineColor=BLACK, lineWidth=.1, context=drawContext)
|
|
8564
|
-
{
|
|
8565
|
-
if (color)
|
|
8566
|
-
{
|
|
8567
|
-
context.fillStyle = color.toString();
|
|
8568
|
-
context.fill();
|
|
8569
|
-
}
|
|
8570
|
-
if (outlineColor && lineWidth)
|
|
8571
|
-
{
|
|
8572
|
-
context.lineWidth = lineWidth;
|
|
8573
|
-
context.lineJoin = context.lineCap = 'round';
|
|
8574
|
-
context.strokeStyle = outlineColor.toString();
|
|
8575
|
-
context.stroke();
|
|
8576
|
-
}
|
|
8577
|
-
}
|
|
8578
|
-
|
|
8579
8682
|
///////////////////////////////////////////////////////////////////////////////
|
|
8580
8683
|
// helper functions
|
|
8581
8684
|
|
|
@@ -8676,6 +8779,7 @@ async function box2dInit()
|
|
|
8676
8779
|
function setupDebugDraw()
|
|
8677
8780
|
{
|
|
8678
8781
|
// setup debug draw
|
|
8782
|
+
const debugLineWidth = .1;
|
|
8679
8783
|
const debugDraw = new box2d.instance.JSDraw();
|
|
8680
8784
|
const box2dColor = (c)=> new Color(c.get_r(), c.get_g(), c.get_b());
|
|
8681
8785
|
const box2dColorPointer = (c)=>
|
|
@@ -8693,33 +8797,33 @@ async function box2dInit()
|
|
|
8693
8797
|
color = getDebugColor(color);
|
|
8694
8798
|
point1 = box2d.vec2FromPointer(point1);
|
|
8695
8799
|
point2 = box2d.vec2FromPointer(point2);
|
|
8696
|
-
|
|
8800
|
+
drawLine(point1, point2, debugLineWidth, color, vec2(), 0, false, false, overlayContext);
|
|
8697
8801
|
};
|
|
8698
8802
|
debugDraw.DrawPolygon = function(vertices, vertexCount, color)
|
|
8699
8803
|
{
|
|
8700
8804
|
color = getDebugColor(color);
|
|
8701
8805
|
const points = getPointsList(vertices, vertexCount);
|
|
8702
|
-
|
|
8806
|
+
drawPoly(points, CLEAR_WHITE, debugLineWidth, color, vec2(), 0, false, false, overlayContext);
|
|
8703
8807
|
};
|
|
8704
8808
|
debugDraw.DrawSolidPolygon = function(vertices, vertexCount, color)
|
|
8705
8809
|
{
|
|
8706
8810
|
color = getDebugColor(color);
|
|
8707
8811
|
const points = getPointsList(vertices, vertexCount);
|
|
8708
|
-
|
|
8812
|
+
drawPoly(points, color, 0, color, vec2(), 0, false, false, overlayContext);
|
|
8709
8813
|
};
|
|
8710
8814
|
debugDraw.DrawCircle = function(center, radius, color)
|
|
8711
8815
|
{
|
|
8712
8816
|
color = getDebugColor(color);
|
|
8713
8817
|
center = box2d.vec2FromPointer(center);
|
|
8714
|
-
|
|
8818
|
+
drawCircle(center, radius, CLEAR_WHITE, debugLineWidth, color, false, false, overlayContext);
|
|
8715
8819
|
};
|
|
8716
8820
|
debugDraw.DrawSolidCircle = function(center, radius, axis, color)
|
|
8717
8821
|
{
|
|
8718
8822
|
color = getDebugColor(color);
|
|
8719
8823
|
center = box2d.vec2FromPointer(center);
|
|
8720
8824
|
axis = box2d.vec2FromPointer(axis).scale(radius);
|
|
8721
|
-
|
|
8722
|
-
|
|
8825
|
+
drawCircle(center, radius, color, debugLineWidth, color, false, false, overlayContext);
|
|
8826
|
+
drawLine(vec2(), axis, debugLineWidth, color, center, 0, false, false, overlayContext);
|
|
8723
8827
|
};
|
|
8724
8828
|
debugDraw.DrawTransform = function(transform)
|
|
8725
8829
|
{
|
|
@@ -8728,8 +8832,8 @@ async function box2dInit()
|
|
|
8728
8832
|
const angle = -transform.get_q().GetAngle();
|
|
8729
8833
|
const p1 = vec2(1,0), c1 = rgb(.75,0,0,.8);
|
|
8730
8834
|
const p2 = vec2(0,1), c2 = rgb(0,.75,0,.8);
|
|
8731
|
-
|
|
8732
|
-
|
|
8835
|
+
drawLine(vec2(), p1, debugLineWidth, c1, pos, angle, false, false, overlayContext);
|
|
8836
|
+
drawLine(vec2(), p2, debugLineWidth, c2, pos, angle, false, false, overlayContext);
|
|
8733
8837
|
}
|
|
8734
8838
|
|
|
8735
8839
|
debugDraw.AppendFlags(box2d.instance.b2Draw.e_shapeBit);
|
|
@@ -8754,12 +8858,13 @@ async function box2dInit()
|
|
|
8754
8858
|
* @param {Vector2} pos - Screen space position
|
|
8755
8859
|
* @param {Vector2} size - Screen space size
|
|
8756
8860
|
* @param {TileInfo} startTile - Starting tile for the nine-slice pattern
|
|
8757
|
-
* @param {number} [borderSize
|
|
8758
|
-
* @param {number} [extraSpace
|
|
8861
|
+
* @param {number} [borderSize] - Width of the border sections
|
|
8862
|
+
* @param {number} [extraSpace] - Extra spacing adjustment
|
|
8863
|
+
* @param {number} [angle] - Angle to rotate by
|
|
8759
8864
|
* @memberof DrawUtilities */
|
|
8760
|
-
function drawNineSliceScreen(pos, size, startTile, borderSize=32, extraSpace=
|
|
8865
|
+
function drawNineSliceScreen(pos, size, startTile, borderSize=32, extraSpace=2, angle=0)
|
|
8761
8866
|
{
|
|
8762
|
-
drawNineSlice(pos, size, startTile, WHITE, borderSize, BLACK, extraSpace, false, true, overlayContext);
|
|
8867
|
+
drawNineSlice(pos, size, startTile, WHITE, borderSize, BLACK, extraSpace, angle, false, true, overlayContext);
|
|
8763
8868
|
}
|
|
8764
8869
|
|
|
8765
8870
|
/** Draw a scalable nine-slice UI element in world space
|
|
@@ -8768,14 +8873,15 @@ function drawNineSliceScreen(pos, size, startTile, borderSize=32, extraSpace=1)
|
|
|
8768
8873
|
* @param {Vector2} size - World space size
|
|
8769
8874
|
* @param {TileInfo} startTile - Starting tile for the nine-slice pattern
|
|
8770
8875
|
* @param {Color} [color] - Color to modulate with
|
|
8771
|
-
* @param {number} [borderSize
|
|
8876
|
+
* @param {number} [borderSize] - Width of the border sections
|
|
8772
8877
|
* @param {Color} [additiveColor] - Additive color
|
|
8773
|
-
* @param {number} [extraSpace
|
|
8878
|
+
* @param {number} [extraSpace] - Extra spacing adjustment
|
|
8879
|
+
* @param {number} [angle] - Angle to rotate by
|
|
8774
8880
|
* @param {boolean} [useWebGL=glEnable] - Use WebGL for rendering
|
|
8775
8881
|
* @param {boolean} [screenSpace] - Use screen space coordinates
|
|
8776
8882
|
* @param {CanvasRenderingContext2D} [context] - Canvas context to use
|
|
8777
8883
|
* @memberof DrawUtilities */
|
|
8778
|
-
function drawNineSlice(pos, size, startTile, color, borderSize=1, additiveColor, extraSpace=.
|
|
8884
|
+
function drawNineSlice(pos, size, startTile, color, borderSize=1, additiveColor, extraSpace=.05, angle=0, useWebGL=glEnable, screenSpace, context)
|
|
8779
8885
|
{
|
|
8780
8886
|
// setup nine slice tiles
|
|
8781
8887
|
const centerTile = startTile.offset(startTile.size);
|
|
@@ -8783,26 +8889,27 @@ function drawNineSlice(pos, size, startTile, color, borderSize=1, additiveColor,
|
|
|
8783
8889
|
const cornerSize = vec2(borderSize);
|
|
8784
8890
|
const cornerOffset = size.scale(.5).subtract(cornerSize.scale(.5));
|
|
8785
8891
|
const flip = screenSpace ? -1 : 1;
|
|
8892
|
+
const rotateAngle = screenSpace ? -angle : angle;
|
|
8786
8893
|
|
|
8787
8894
|
// center
|
|
8788
|
-
drawTile(pos, centerSize, centerTile, color,
|
|
8789
|
-
for(let i=4; i--;)
|
|
8895
|
+
drawTile(pos, centerSize, centerTile, color, angle, false, additiveColor, useWebGL, screenSpace, context);
|
|
8896
|
+
for (let i=4; i--;)
|
|
8790
8897
|
{
|
|
8791
8898
|
// sides
|
|
8792
8899
|
const horizontal = i%2;
|
|
8793
8900
|
const sidePos = cornerOffset.multiply(vec2(horizontal?i==1?1:-1:0, horizontal?0:i?-1:1));
|
|
8794
8901
|
const sideSize = vec2(horizontal ? borderSize : centerSize.x, horizontal ? centerSize.y : borderSize);
|
|
8795
8902
|
const sideTile = centerTile.offset(startTile.size.multiply(vec2(i==1?1:i==3?-1:0,i==0?-flip:i==2?flip:0)))
|
|
8796
|
-
drawTile(pos.add(sidePos), sideSize, sideTile, color,
|
|
8903
|
+
drawTile(pos.add(sidePos.rotate(rotateAngle)), sideSize, sideTile, color, angle, false, additiveColor, useWebGL, screenSpace, context);
|
|
8797
8904
|
}
|
|
8798
|
-
for(let i=4; i--;)
|
|
8905
|
+
for (let i=4; i--;)
|
|
8799
8906
|
{
|
|
8800
8907
|
// corners
|
|
8801
8908
|
const flipX = i>1;
|
|
8802
8909
|
const flipY = i && i<3;
|
|
8803
8910
|
const cornerPos = cornerOffset.multiply(vec2(flipX?-1:1, flipY?-1:1));
|
|
8804
8911
|
const cornerTile = centerTile.offset(startTile.size.multiply(vec2(flipX?-1:1,flipY?flip:-flip)));
|
|
8805
|
-
drawTile(pos.add(cornerPos), cornerSize, cornerTile, color,
|
|
8912
|
+
drawTile(pos.add(cornerPos.rotate(rotateAngle)), cornerSize, cornerTile, color, angle, false, additiveColor, useWebGL, screenSpace, context);
|
|
8806
8913
|
}
|
|
8807
8914
|
}
|
|
8808
8915
|
|
|
@@ -8811,12 +8918,13 @@ function drawNineSlice(pos, size, startTile, color, borderSize=1, additiveColor,
|
|
|
8811
8918
|
* @param {Vector2} pos - Screen space position
|
|
8812
8919
|
* @param {Vector2} size - Screen space size
|
|
8813
8920
|
* @param {TileInfo} startTile - Starting tile for the three-slice pattern
|
|
8814
|
-
* @param {number} [borderSize
|
|
8815
|
-
* @param {number} [extraSpace
|
|
8921
|
+
* @param {number} [borderSize] - Width of the border sections
|
|
8922
|
+
* @param {number} [extraSpace] - Extra spacing adjustment
|
|
8923
|
+
* @param {number} [angle] - Angle to rotate by
|
|
8816
8924
|
* @memberof DrawUtilities */
|
|
8817
|
-
function drawThreeSliceScreen(pos, size, startTile, borderSize=32, extraSpace=
|
|
8925
|
+
function drawThreeSliceScreen(pos, size, startTile, borderSize=32, extraSpace=2, angle=0)
|
|
8818
8926
|
{
|
|
8819
|
-
drawThreeSlice(pos, size, startTile, WHITE, borderSize, BLACK, extraSpace, false, true, overlayContext);
|
|
8927
|
+
drawThreeSlice(pos, size, startTile, WHITE, borderSize, BLACK, extraSpace, angle, false, true, overlayContext);
|
|
8820
8928
|
}
|
|
8821
8929
|
|
|
8822
8930
|
/** Draw a scalable three-slice UI element in world space
|
|
@@ -8825,14 +8933,15 @@ function drawThreeSliceScreen(pos, size, startTile, borderSize=32, extraSpace=1)
|
|
|
8825
8933
|
* @param {Vector2} size - World space size
|
|
8826
8934
|
* @param {TileInfo} startTile - Starting tile for the three-slice pattern
|
|
8827
8935
|
* @param {Color} [color] - Color to modulate with
|
|
8828
|
-
* @param {number} [borderSize
|
|
8936
|
+
* @param {number} [borderSize] - Width of the border sections
|
|
8829
8937
|
* @param {Color} [additiveColor] - Additive color
|
|
8830
|
-
* @param {number} [extraSpace
|
|
8938
|
+
* @param {number} [extraSpace] - Extra spacing adjustment
|
|
8939
|
+
* @param {number} [angle] - Angle to rotate by
|
|
8831
8940
|
* @param {boolean} [useWebGL=glEnable] - Use WebGL for rendering
|
|
8832
8941
|
* @param {boolean} [screenSpace] - Use screen space coordinates
|
|
8833
8942
|
* @param {CanvasRenderingContext2D} [context] - Canvas context to use
|
|
8834
8943
|
* @memberof DrawUtilities */
|
|
8835
|
-
function drawThreeSlice(pos, size, startTile, color, borderSize=1, additiveColor, extraSpace=.
|
|
8944
|
+
function drawThreeSlice(pos, size, startTile, color, borderSize=1, additiveColor, extraSpace=.05, angle=0, useWebGL=glEnable, screenSpace, context)
|
|
8836
8945
|
{
|
|
8837
8946
|
// setup three slice tiles
|
|
8838
8947
|
const cornerTile = startTile.frame(0);
|
|
@@ -8842,25 +8951,26 @@ function drawThreeSlice(pos, size, startTile, color, borderSize=1, additiveColor
|
|
|
8842
8951
|
const cornerSize = vec2(borderSize);
|
|
8843
8952
|
const cornerOffset = size.scale(.5).subtract(cornerSize.scale(.5));
|
|
8844
8953
|
const flip = screenSpace ? -1 : 1;
|
|
8954
|
+
const rotateAngle = screenSpace ? -angle : angle;
|
|
8845
8955
|
|
|
8846
8956
|
// center
|
|
8847
|
-
drawTile(pos, centerSize, centerTile, color,
|
|
8848
|
-
for(let i=4; i--;)
|
|
8957
|
+
drawTile(pos, centerSize, centerTile, color, angle, false, additiveColor, useWebGL, screenSpace, context);
|
|
8958
|
+
for (let i=4; i--;)
|
|
8849
8959
|
{
|
|
8850
8960
|
// sides
|
|
8851
|
-
const
|
|
8961
|
+
const a = angle + i*PI/2;
|
|
8852
8962
|
const horizontal = i%2;
|
|
8853
8963
|
const sidePos = cornerOffset.multiply(vec2(horizontal?i==1?1:-1:0, horizontal?0:i?-flip:flip));
|
|
8854
8964
|
const sideSize = vec2(horizontal ? centerSize.y : centerSize.x, borderSize);
|
|
8855
|
-
drawTile(pos.add(sidePos), sideSize, sideTile, color,
|
|
8965
|
+
drawTile(pos.add(sidePos.rotate(rotateAngle)), sideSize, sideTile, color, a, false, additiveColor, useWebGL, screenSpace, context);
|
|
8856
8966
|
}
|
|
8857
|
-
for(let i=4; i--;)
|
|
8967
|
+
for (let i=4; i--;)
|
|
8858
8968
|
{
|
|
8859
8969
|
// corners
|
|
8860
|
-
const
|
|
8970
|
+
const a = angle + i*PI/2;
|
|
8861
8971
|
const flipX = !i || i>2;
|
|
8862
8972
|
const flipY = i>1;
|
|
8863
8973
|
const cornerPos = cornerOffset.multiply(vec2(flipX?-1:1, flipY?-flip:flip));
|
|
8864
|
-
drawTile(pos.add(cornerPos), cornerSize, cornerTile, color,
|
|
8974
|
+
drawTile(pos.add(cornerPos.rotate(rotateAngle)), cornerSize, cornerTile, color, a, false, additiveColor, useWebGL, screenSpace, context);
|
|
8865
8975
|
}
|
|
8866
8976
|
}
|