littlejsengine 1.4.0 → 1.4.6
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/build.bat +1 -1
- package/buildSetup.bat +2 -2
- package/engine/engine.all.js +244 -161
- package/engine/engine.all.min.js +1 -1
- package/engine/engine.all.module.js +4812 -0
- package/engine/engine.all.release.js +228 -138
- package/engine/engine.all.release.module.js +4457 -0
- package/engine/engine.js +12 -8
- package/engine/engineBuild.bat +21 -2
- package/engine/engineDebug.js +16 -23
- package/engine/engineDraw.js +13 -13
- package/engine/engineExport.js +333 -0
- package/engine/engineInput.js +8 -7
- package/engine/engineMedals.js +10 -6
- package/engine/engineObject.js +4 -4
- package/engine/engineParticles.js +45 -21
- package/engine/engineTileLayer.js +1 -1
- package/engine/engineUtilities.js +21 -25
- package/engine/engineWebGL.js +114 -54
- package/engine/index.d.ts +41 -30
- package/examples/breakout/game.js +63 -11
- package/examples/breakout/gameObjects.js +14 -12
- package/examples/breakout/index.html +3 -3
- package/examples/empty/game.js +35 -0
- package/examples/empty/index.html +9 -0
- package/examples/empty/tiles.png +0 -0
- package/examples/module/game.js +122 -0
- package/examples/module/index.html +9 -0
- package/examples/module/tiles.png +0 -0
- package/examples/particles/index.html +14 -14
- package/examples/particles/tiles.png +0 -0
- package/examples/platformer/gameObjects.js +5 -5
- package/examples/platformer/gamePlayer.js +7 -5
- package/examples/platformer/index.html +6 -6
- package/examples/puzzle/index.html +2 -2
- package/examples/stress/index.html +2 -2
- package/game.js +9 -11
- package/index.html +13 -13
- package/package.json +35 -25
- package/README.md +0 -54
package/engine/engine.all.js
CHANGED
|
@@ -233,55 +233,49 @@ const debugRender = ()=>
|
|
|
233
233
|
|
|
234
234
|
if (debugOverlay)
|
|
235
235
|
{
|
|
236
|
+
const saveContext = mainContext;
|
|
237
|
+
mainContext = overlayContext;
|
|
238
|
+
|
|
236
239
|
// mouse pick
|
|
237
240
|
let bestDistance = Infinity, bestObject;
|
|
238
241
|
for (const o of engineObjects)
|
|
239
242
|
{
|
|
240
243
|
if (o.canvas || o.destroyed)
|
|
241
|
-
continue;
|
|
242
|
-
|
|
243
|
-
const size = o.size.copy();
|
|
244
|
-
if (!size.x || !size.y)
|
|
244
|
+
continue;
|
|
245
|
+
if (!o.size.x || !o.size.y)
|
|
245
246
|
continue;
|
|
246
247
|
|
|
247
248
|
const distance = mousePos.distanceSquared(o.pos);
|
|
248
249
|
if (distance < bestDistance)
|
|
249
250
|
{
|
|
250
251
|
bestDistance = distance;
|
|
251
|
-
bestObject = o
|
|
252
|
+
bestObject = o;
|
|
252
253
|
}
|
|
253
254
|
|
|
254
255
|
// show object info
|
|
255
|
-
const
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
size.y = max(size.y, .2);
|
|
262
|
-
drawRect(o.pos, size, color);
|
|
263
|
-
drawRect(o.pos, size.scale(.8), o.parent ? new Color(1,1,1,.5) : new Color(0,0,0,.8));
|
|
264
|
-
o.parent && drawLine(o.pos, o.parent.pos, .1, new Color(0,0,1,.5));
|
|
256
|
+
const size = vec2(max(o.size.x, .2), max(o.size.y, .2));
|
|
257
|
+
const color1 = new Color(!!o.collideTiles, !!o.collideSolidObjects, !!o.isSolid, o.parent?.2:.5);
|
|
258
|
+
const color2 = o.parent ? new Color(1,1,1,.5) : new Color(0,0,0,.8);
|
|
259
|
+
drawRect(o.pos, size, color1, o.angle, 0);
|
|
260
|
+
drawRect(o.pos, size.scale(.8), color2, o.angle, 0);
|
|
261
|
+
o.parent && drawLine(o.pos, o.parent.pos, .1, new Color(0,0,1,.5), 0);
|
|
265
262
|
}
|
|
266
263
|
|
|
267
264
|
if (bestObject)
|
|
268
265
|
{
|
|
269
|
-
const saveContext = mainContext;
|
|
270
|
-
mainContext = overlayContext
|
|
271
266
|
const raycastHitPos = tileCollisionRaycast(bestObject.pos, mousePos);
|
|
272
267
|
raycastHitPos && drawRect(raycastHitPos.floor().add(vec2(.5)), vec2(1), new Color(0,1,1,.3));
|
|
273
|
-
drawRect(mousePos.floor().add(vec2(.5)), vec2(1), new Color(0,0,1,.5));
|
|
274
|
-
drawLine(mousePos, bestObject.pos, .1,
|
|
268
|
+
drawRect(mousePos.floor().add(vec2(.5)), vec2(1), new Color(0,0,1,.5), 0, 0);
|
|
269
|
+
drawLine(mousePos, bestObject.pos, .1, raycastHitPos ? new Color(1,0,0,.5) : new Color(0,1,0,.5), 0);
|
|
275
270
|
|
|
276
271
|
const debugText = 'mouse pos = ' + mousePos +
|
|
277
272
|
'\nmouse collision = ' + getTileCollisionData(mousePos) +
|
|
278
273
|
'\n\n--- object info ---\n' +
|
|
279
274
|
bestObject.toString();
|
|
280
|
-
drawTextScreen(debugText, mousePosScreen, 24, new Color, .05,
|
|
281
|
-
mainContext = saveContext;
|
|
275
|
+
drawTextScreen(debugText, mousePosScreen, 24, new Color, .05, 0, 0, 'monospace');
|
|
282
276
|
}
|
|
283
277
|
|
|
284
|
-
glCopyToContext(mainContext);
|
|
278
|
+
glCopyToContext(mainContext = saveContext);
|
|
285
279
|
}
|
|
286
280
|
|
|
287
281
|
{
|
|
@@ -294,7 +288,6 @@ const debugRender = ()=>
|
|
|
294
288
|
|
|
295
289
|
// create canvas transform from world space to screen space
|
|
296
290
|
const pos = worldToScreen(p.pos);
|
|
297
|
-
|
|
298
291
|
overlayContext.translate(pos.x|0, pos.y|0);
|
|
299
292
|
overlayContext.rotate(p.angle);
|
|
300
293
|
overlayContext.fillStyle = overlayContext.strokeStyle = p.color;
|
|
@@ -830,10 +823,10 @@ class Color
|
|
|
830
823
|
* @return {Array} */
|
|
831
824
|
getHSLA()
|
|
832
825
|
{
|
|
833
|
-
const r = this.r;
|
|
834
|
-
const g = this.g;
|
|
835
|
-
const b = this.b;
|
|
836
|
-
const a = this.a;
|
|
826
|
+
const r = clamp(this.r);
|
|
827
|
+
const g = clamp(this.g);
|
|
828
|
+
const b = clamp(this.b);
|
|
829
|
+
const a = clamp(this.a);
|
|
837
830
|
const max = Math.max(r, g, b);
|
|
838
831
|
const min = Math.min(r, g, b);
|
|
839
832
|
const l = (max + min) / 2;
|
|
@@ -869,20 +862,13 @@ class Color
|
|
|
869
862
|
).clamp();
|
|
870
863
|
}
|
|
871
864
|
|
|
872
|
-
/** Returns this color expressed as
|
|
865
|
+
/** Returns this color expressed as a hex color code
|
|
866
|
+
* @param {Boolean} [useAlpha=1] - if alpha should be included in result
|
|
873
867
|
* @return {String} */
|
|
874
|
-
toString()
|
|
868
|
+
toString(useAlpha = 1)
|
|
875
869
|
{
|
|
876
|
-
|
|
877
|
-
return
|
|
878
|
-
}
|
|
879
|
-
|
|
880
|
-
/** Returns this color expressed as 32 bit integer RGBA value
|
|
881
|
-
* @return {Number} */
|
|
882
|
-
rgbaInt()
|
|
883
|
-
{
|
|
884
|
-
ASSERT(this.r>=0 && this.r<=1 && this.g>=0 && this.g<=1 && this.b>=0 && this.b<=1 && this.a>=0 && this.a<=1);
|
|
885
|
-
return (this.r*255|0) + (this.g*255<<8) + (this.b*255<<16) + (this.a*255<<24);
|
|
870
|
+
const toHex = (c)=> ((c=c*255|0)<16 ? '0' : '') + c.toString(16);
|
|
871
|
+
return '#' + toHex(this.r) + toHex(this.g) + toHex(this.b) + (useAlpha ? toHex(this.a) : '');
|
|
886
872
|
}
|
|
887
873
|
|
|
888
874
|
/** Set this color from a hex code
|
|
@@ -890,21 +876,24 @@ class Color
|
|
|
890
876
|
* @return {Color} */
|
|
891
877
|
setHex(hex)
|
|
892
878
|
{
|
|
893
|
-
const fromHex = (
|
|
879
|
+
const fromHex = (c)=> clamp(parseInt(hex.slice(c,c+2),16)/255);
|
|
894
880
|
this.r = fromHex(1);
|
|
895
881
|
this.g = fromHex(3),
|
|
896
882
|
this.b = fromHex(5);
|
|
897
|
-
this.a = 1;
|
|
898
|
-
ASSERT(this.r>=0 && this.r<=1 && this.g>=0 && this.g<=1 && this.b>=0 && this.b<=1);
|
|
883
|
+
this.a = hex.length > 7 ? fromHex(7) : 1;
|
|
899
884
|
return this;
|
|
900
885
|
}
|
|
901
|
-
|
|
902
|
-
/** Returns this color expressed as
|
|
903
|
-
* @return {
|
|
904
|
-
|
|
886
|
+
|
|
887
|
+
/** Returns this color expressed as 32 bit RGBA value
|
|
888
|
+
* @return {Number} */
|
|
889
|
+
rgbaInt()
|
|
905
890
|
{
|
|
906
|
-
const
|
|
907
|
-
|
|
891
|
+
const toByte = (c)=> clamp(c)*255|0;
|
|
892
|
+
const r = toByte(this.r);
|
|
893
|
+
const g = toByte(this.g)<<8;
|
|
894
|
+
const b = toByte(this.b)<<16;
|
|
895
|
+
const a = toByte(this.a)<<24;
|
|
896
|
+
return r + g + b + a;
|
|
908
897
|
}
|
|
909
898
|
}
|
|
910
899
|
|
|
@@ -1481,7 +1470,7 @@ class EngineObject
|
|
|
1481
1470
|
* @return {Boolean} - true if the raycast should hit */
|
|
1482
1471
|
collideWithTileRaycast(tileData, pos) { return tileData > 0; }
|
|
1483
1472
|
|
|
1484
|
-
/** Called to check if a
|
|
1473
|
+
/** Called to check if a object collision should be resolved
|
|
1485
1474
|
* @param {EngineObject} object - the object to test against
|
|
1486
1475
|
* @return {Boolean} - true if the collision should be resolved
|
|
1487
1476
|
*/
|
|
@@ -1526,10 +1515,10 @@ class EngineObject
|
|
|
1526
1515
|
}
|
|
1527
1516
|
|
|
1528
1517
|
/** Set how this object collides
|
|
1529
|
-
* @param {boolean} [collideSolidObjects=
|
|
1530
|
-
* @param {boolean} [isSolid=
|
|
1518
|
+
* @param {boolean} [collideSolidObjects=1] - Does it collide with solid objects
|
|
1519
|
+
* @param {boolean} [isSolid=1] - Does it collide with and block other objects (expensive in large numbers)
|
|
1531
1520
|
* @param {boolean} [collideTiles=1] - Does it collide with the tile collision */
|
|
1532
|
-
setCollision(collideSolidObjects=
|
|
1521
|
+
setCollision(collideSolidObjects=1, isSolid=1, collideTiles=1)
|
|
1533
1522
|
{
|
|
1534
1523
|
ASSERT(collideSolidObjects || !isSolid); // solid objects must be set to collide
|
|
1535
1524
|
|
|
@@ -1792,21 +1781,21 @@ function setBlendMode(additive, useWebGL=glEnable)
|
|
|
1792
1781
|
* @param {Color} [lineColor=new Color(0,0,0)]
|
|
1793
1782
|
* @param {String} [textAlign='center']
|
|
1794
1783
|
* @memberof Draw */
|
|
1795
|
-
function drawTextScreen(text, pos, size=1, color=new Color, lineWidth=0, lineColor=new Color(0,0,0), textAlign='center', font=fontDefault)
|
|
1784
|
+
function drawTextScreen(text, pos, size=1, color=new Color, lineWidth=0, lineColor=new Color(0,0,0), textAlign='center', font=fontDefault, context=overlayContext)
|
|
1796
1785
|
{
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1786
|
+
context.fillStyle = color;
|
|
1787
|
+
context.lineWidth = lineWidth;
|
|
1788
|
+
context.strokeStyle = lineColor;
|
|
1789
|
+
context.textAlign = textAlign;
|
|
1790
|
+
context.font = size + 'px '+ font;
|
|
1791
|
+
context.textBaseline = 'middle';
|
|
1792
|
+
context.lineJoin = 'round';
|
|
1804
1793
|
|
|
1805
1794
|
pos = pos.copy();
|
|
1806
1795
|
(text+'').split('\n').forEach(line=>
|
|
1807
1796
|
{
|
|
1808
|
-
lineWidth &&
|
|
1809
|
-
|
|
1797
|
+
lineWidth && context.strokeText(line, pos.x, pos.y);
|
|
1798
|
+
context.fillText(line, pos.x, pos.y);
|
|
1810
1799
|
pos.y += size;
|
|
1811
1800
|
});
|
|
1812
1801
|
}
|
|
@@ -1823,7 +1812,7 @@ function drawTextScreen(text, pos, size=1, color=new Color, lineWidth=0, lineCol
|
|
|
1823
1812
|
* @memberof Draw */
|
|
1824
1813
|
function drawText(text, pos, size=1, color, lineWidth, lineColor, textAlign, font)
|
|
1825
1814
|
{
|
|
1826
|
-
drawTextScreen(text, worldToScreen(pos), size*cameraScale, color, lineWidth*cameraScale, lineColor, textAlign, font);
|
|
1815
|
+
drawTextScreen(text, worldToScreen(pos), size*cameraScale, color, lineWidth*cameraScale, lineColor, textAlign, font, mainContext);
|
|
1827
1816
|
}
|
|
1828
1817
|
|
|
1829
1818
|
///////////////////////////////////////////////////////////////////////////////
|
|
@@ -1846,7 +1835,7 @@ let engineFontImage;
|
|
|
1846
1835
|
class FontImage
|
|
1847
1836
|
{
|
|
1848
1837
|
/** Create an image font
|
|
1849
|
-
* @param {
|
|
1838
|
+
* @param {HTMLImageElement} [image] - The image the font is stored in, if undefined the default font is used
|
|
1850
1839
|
* @param {Vector2} [tileSize=vec2(8)] - The size of the font source tiles
|
|
1851
1840
|
* @param {Vector2} [paddingSize=vec2(0,1)] - How much extra space to add between characters
|
|
1852
1841
|
* @param {Number} [startTileIndex=0] - Tile index in image where font starts
|
|
@@ -1945,6 +1934,7 @@ function toggleFullscreen()
|
|
|
1945
1934
|
document.body.mozRequestFullScreen();
|
|
1946
1935
|
}
|
|
1947
1936
|
}
|
|
1937
|
+
|
|
1948
1938
|
/**
|
|
1949
1939
|
* LittleJS Input System
|
|
1950
1940
|
* <br> - Tracks key down, pressed, and released
|
|
@@ -2059,7 +2049,7 @@ let inputData = [[]];
|
|
|
2059
2049
|
function inputUpdate()
|
|
2060
2050
|
{
|
|
2061
2051
|
// clear input when lost focus (prevent stuck keys)
|
|
2062
|
-
document.hasFocus() || clearInput();
|
|
2052
|
+
isTouchDevice || document.hasFocus() || clearInput();
|
|
2063
2053
|
|
|
2064
2054
|
// update mouse world space position
|
|
2065
2055
|
mousePos = screenToWorld(mousePosScreen);
|
|
@@ -2134,7 +2124,7 @@ function gamepadsUpdate()
|
|
|
2134
2124
|
}
|
|
2135
2125
|
}
|
|
2136
2126
|
|
|
2137
|
-
if (!gamepadsEnable || !navigator.getGamepads || !document.hasFocus() && !debug)
|
|
2127
|
+
if (!gamepadsEnable || !navigator || !navigator.getGamepads || !document.hasFocus() && !debug)
|
|
2138
2128
|
return;
|
|
2139
2129
|
|
|
2140
2130
|
// poll gamepads
|
|
@@ -2183,7 +2173,7 @@ function gamepadsUpdate()
|
|
|
2183
2173
|
/** Pulse the vibration hardware if it exists
|
|
2184
2174
|
* @param {Number} [pattern=100] - a single value in miliseconds or vibration interval array
|
|
2185
2175
|
* @memberof Input */
|
|
2186
|
-
const vibrate = (pattern)=> vibrateEnable &&
|
|
2176
|
+
const vibrate = (pattern)=> vibrateEnable && navigator && navigator.vibrate && navigator.vibrate(pattern);
|
|
2187
2177
|
|
|
2188
2178
|
/** Cancel any ongoing vibration
|
|
2189
2179
|
* @memberof Input */
|
|
@@ -2201,7 +2191,7 @@ const isTouchDevice = window.ontouchstart !== undefined;
|
|
|
2201
2191
|
if (isTouchDevice)
|
|
2202
2192
|
{
|
|
2203
2193
|
// handle all touch events the same way
|
|
2204
|
-
let wasTouching,
|
|
2194
|
+
let wasTouching, hadTouch;
|
|
2205
2195
|
ontouchstart = ontouchmove = ontouchend = (e)=>
|
|
2206
2196
|
{
|
|
2207
2197
|
e.button = 0; // all touches are left click
|
|
@@ -2210,7 +2200,8 @@ if (isTouchDevice)
|
|
|
2210
2200
|
const touching = e.touches.length;
|
|
2211
2201
|
if (touching)
|
|
2212
2202
|
{
|
|
2213
|
-
|
|
2203
|
+
// fix mobile audio, force it to play a sound on first touch
|
|
2204
|
+
hadTouch || zzfx(0, hadTouch=1);
|
|
2214
2205
|
|
|
2215
2206
|
// set event pos and pass it along
|
|
2216
2207
|
e.x = e.touches[0].clientX;
|
|
@@ -2223,8 +2214,8 @@ if (isTouchDevice)
|
|
|
2223
2214
|
// set was touching
|
|
2224
2215
|
wasTouching = touching;
|
|
2225
2216
|
|
|
2226
|
-
//
|
|
2227
|
-
return
|
|
2217
|
+
// must return true so the document will get focus
|
|
2218
|
+
return true;
|
|
2228
2219
|
}
|
|
2229
2220
|
}
|
|
2230
2221
|
|
|
@@ -3081,7 +3072,7 @@ constructor(pos, size=tileCollisionSize, tileSize=tileSizeDefault, scale=vec2(1)
|
|
|
3081
3072
|
redrawEnd()
|
|
3082
3073
|
{
|
|
3083
3074
|
ASSERT(mainContext == this.context); // must call redrawStart() before drawing tiles
|
|
3084
|
-
glCopyToContext(mainContext, 1);
|
|
3075
|
+
glEnable && glCopyToContext(mainContext, 1);
|
|
3085
3076
|
//debugSaveCanvas(this.canvas);
|
|
3086
3077
|
|
|
3087
3078
|
// set stuff back to normal
|
|
@@ -3225,6 +3216,7 @@ class ParticleEmitter extends EngineObject
|
|
|
3225
3216
|
* @param {Boolean} [additive=0] - Should particles use addtive blend
|
|
3226
3217
|
* @param {Boolean} [randomColorLinear=1] - Should color be randomized linearly or across each component
|
|
3227
3218
|
* @param {Number} [renderOrder=0] - Render order for particles (additive is above other stuff by default)
|
|
3219
|
+
* @param {Boolean} [localSpace=0] - Should it be in local space of emitter (world space is default)
|
|
3228
3220
|
*/
|
|
3229
3221
|
constructor
|
|
3230
3222
|
(
|
|
@@ -3254,7 +3246,8 @@ class ParticleEmitter extends EngineObject
|
|
|
3254
3246
|
collideTiles,
|
|
3255
3247
|
additive,
|
|
3256
3248
|
randomColorLinear = 1,
|
|
3257
|
-
renderOrder = additive ? 1e9 : 0
|
|
3249
|
+
renderOrder = additive ? 1e9 : 0,
|
|
3250
|
+
localSpace
|
|
3258
3251
|
)
|
|
3259
3252
|
{
|
|
3260
3253
|
super(pos, new Vector2, tileIndex, tileSize, angle, undefined, renderOrder);
|
|
@@ -3308,6 +3301,8 @@ class ParticleEmitter extends EngineObject
|
|
|
3308
3301
|
this.collideTiles = collideTiles;
|
|
3309
3302
|
/** @property {Number} - Should particles use addtive blend */
|
|
3310
3303
|
this.additive = additive;
|
|
3304
|
+
/** @property {Boolean} - Should it be in local space of emitter */
|
|
3305
|
+
this.localSpace = localSpace;
|
|
3311
3306
|
/** @property {Number} - If set the partile is drawn as a trail, stretched in the drection of velocity */
|
|
3312
3307
|
this.trailScale = 0;
|
|
3313
3308
|
|
|
@@ -3343,30 +3338,38 @@ class ParticleEmitter extends EngineObject
|
|
|
3343
3338
|
emitParticle()
|
|
3344
3339
|
{
|
|
3345
3340
|
// spawn a particle
|
|
3346
|
-
|
|
3347
|
-
(new Vector2(rand(-.5,.5), rand(-.5,.5)))
|
|
3348
|
-
|
|
3349
|
-
|
|
3350
|
-
|
|
3341
|
+
let pos = this.emitSize.x != undefined ? // check if vec2 was used for size
|
|
3342
|
+
(new Vector2(rand(-.5,.5), rand(-.5,.5)))
|
|
3343
|
+
.multiply(this.emitSize).rotate(this.angle) // box emitter
|
|
3344
|
+
: randInCircle(this.emitSize * .5); // circle emitter
|
|
3345
|
+
let angle = rand(this.particleConeAngle, -this.particleConeAngle);
|
|
3346
|
+
if (!this.localSpace)
|
|
3347
|
+
{
|
|
3348
|
+
pos = this.pos.add(pos);
|
|
3349
|
+
angle += this.angle;
|
|
3350
|
+
}
|
|
3351
|
+
|
|
3352
|
+
const particle = new Particle(pos, this.tileIndex, this.tileSize, angle);
|
|
3351
3353
|
|
|
3352
3354
|
// randomness scales each paremeter by a percentage
|
|
3353
3355
|
const randomness = this.randomness;
|
|
3354
3356
|
const randomizeScale = (v)=> v + v*rand(randomness, -randomness);
|
|
3355
3357
|
|
|
3356
3358
|
// randomize particle settings
|
|
3357
|
-
const particleTime
|
|
3358
|
-
const sizeStart
|
|
3359
|
-
const sizeEnd
|
|
3360
|
-
const speed
|
|
3361
|
-
const angleSpeed
|
|
3362
|
-
const coneAngle
|
|
3363
|
-
const colorStart
|
|
3364
|
-
const colorEnd
|
|
3359
|
+
const particleTime = randomizeScale(this.particleTime);
|
|
3360
|
+
const sizeStart = randomizeScale(this.sizeStart);
|
|
3361
|
+
const sizeEnd = randomizeScale(this.sizeEnd);
|
|
3362
|
+
const speed = randomizeScale(this.speed);
|
|
3363
|
+
const angleSpeed = randomizeScale(this.angleSpeed) * randSign();
|
|
3364
|
+
const coneAngle = rand(this.emitConeAngle, -this.emitConeAngle);
|
|
3365
|
+
const colorStart = randColor(this.colorStartA, this.colorStartB, this.randomColorLinear);
|
|
3366
|
+
const colorEnd = randColor(this.colorEndA, this.colorEndB, this.randomColorLinear);
|
|
3367
|
+
const velocityAngle = this.localSpace ? coneAngle : this.angle + coneAngle;
|
|
3365
3368
|
|
|
3366
3369
|
// build particle settings
|
|
3367
3370
|
particle.colorStart = colorStart;
|
|
3368
3371
|
particle.colorEndDelta = colorEnd.subtract(colorStart);
|
|
3369
|
-
particle.velocity = (new Vector2).setAngle(
|
|
3372
|
+
particle.velocity = (new Vector2).setAngle(velocityAngle, speed);
|
|
3370
3373
|
particle.angleVelocity = angleSpeed;
|
|
3371
3374
|
particle.lifeTime = particleTime;
|
|
3372
3375
|
particle.sizeStart = sizeStart;
|
|
@@ -3382,6 +3385,7 @@ class ParticleEmitter extends EngineObject
|
|
|
3382
3385
|
particle.renderOrder = this.renderOrder;
|
|
3383
3386
|
particle.trailScale = this.trailScale;
|
|
3384
3387
|
particle.mirror = rand()<.5;
|
|
3388
|
+
particle.localSpaceEmitter = this.localSpace && this;
|
|
3385
3389
|
|
|
3386
3390
|
// setup callbacks for particles
|
|
3387
3391
|
particle.destroyCallback = this.particleDestroyCallback;
|
|
@@ -3428,20 +3432,31 @@ class Particle extends EngineObject
|
|
|
3428
3432
|
|
|
3429
3433
|
// draw the particle
|
|
3430
3434
|
this.additive && setBlendMode(1);
|
|
3435
|
+
|
|
3436
|
+
let pos = this.pos, angle = this.angle;
|
|
3437
|
+
if (this.localSpaceEmitter)
|
|
3438
|
+
{
|
|
3439
|
+
// in local space of emitter
|
|
3440
|
+
pos = this.localSpaceEmitter.pos.add(pos.rotate(-this.localSpaceEmitter.angle));
|
|
3441
|
+
angle += this.localSpaceEmitter.angle;
|
|
3442
|
+
}
|
|
3431
3443
|
if (this.trailScale)
|
|
3432
3444
|
{
|
|
3433
3445
|
// trail style particles
|
|
3434
|
-
|
|
3435
|
-
|
|
3446
|
+
let velocity = this.velocity;
|
|
3447
|
+
if (this.localSpaceEmitter)
|
|
3448
|
+
velocity = velocity.rotate(-this.localSpaceEmitter.angle);
|
|
3449
|
+
const speed = velocity.length();
|
|
3450
|
+
const direction = velocity.scale(1/speed);
|
|
3436
3451
|
const trailLength = speed * this.trailScale;
|
|
3437
3452
|
size.y = max(size.x, trailLength);
|
|
3438
|
-
|
|
3439
|
-
drawTile(
|
|
3453
|
+
angle = direction.angle();
|
|
3454
|
+
drawTile(pos.add(direction.multiply(vec2(0,-trailLength/2))), size, this.tileIndex, this.tileSize, color, angle, this.mirror);
|
|
3440
3455
|
}
|
|
3441
3456
|
else
|
|
3442
|
-
drawTile(
|
|
3457
|
+
drawTile(pos, size, this.tileIndex, this.tileSize, color, angle, this.mirror);
|
|
3443
3458
|
this.additive && setBlendMode();
|
|
3444
|
-
debugParticles && debugRect(
|
|
3459
|
+
debugParticles && debugRect(pos, size, '#f005', 0, angle);
|
|
3445
3460
|
|
|
3446
3461
|
if (p == 1)
|
|
3447
3462
|
{
|
|
@@ -3471,11 +3486,6 @@ const medals = [];
|
|
|
3471
3486
|
* @memberof Medals */
|
|
3472
3487
|
let medalsPreventUnlock;
|
|
3473
3488
|
|
|
3474
|
-
/** This can used to enable Newgrounds functionality
|
|
3475
|
-
* @type {Newgrounds}
|
|
3476
|
-
* @memberof Medals */
|
|
3477
|
-
let newgrounds;
|
|
3478
|
-
|
|
3479
3489
|
// Engine internal variables not exposed to documentation
|
|
3480
3490
|
let medalsDisplayQueue = [], medalsSaveName, medalsDisplayTimeLast;
|
|
3481
3491
|
|
|
@@ -3490,7 +3500,7 @@ function medalsInit(saveName)
|
|
|
3490
3500
|
{
|
|
3491
3501
|
// check if medals are unlocked
|
|
3492
3502
|
medalsSaveName = saveName;
|
|
3493
|
-
debugMedals || medals.forEach(medal=> localStorage[medal.storageKey()]);
|
|
3503
|
+
debugMedals || medals.forEach(medal=> medal.unlocked = (localStorage[medal.storageKey()] | 0));
|
|
3494
3504
|
}
|
|
3495
3505
|
|
|
3496
3506
|
/**
|
|
@@ -3623,6 +3633,15 @@ function medalsRender()
|
|
|
3623
3633
|
|
|
3624
3634
|
///////////////////////////////////////////////////////////////////////////////
|
|
3625
3635
|
|
|
3636
|
+
// global Newgrounds object
|
|
3637
|
+
let newgrounds;
|
|
3638
|
+
|
|
3639
|
+
/** This can used to enable Newgrounds functionality
|
|
3640
|
+
* @param {Number} app_id - The newgrounds App ID
|
|
3641
|
+
* @param {String} [cipher] - The encryption Key (AES-128/Base64)
|
|
3642
|
+
* @memberof Medals */
|
|
3643
|
+
function newgroundsInit(app_id, cipher) { newgrounds = new Newgrounds(app_id, cipher); }
|
|
3644
|
+
|
|
3626
3645
|
/**
|
|
3627
3646
|
* Newgrounds API wrapper object
|
|
3628
3647
|
* @example
|
|
@@ -3783,15 +3802,13 @@ let glContext;
|
|
|
3783
3802
|
let glTileTexture;
|
|
3784
3803
|
|
|
3785
3804
|
// WebGL internal variables not exposed to documentation
|
|
3786
|
-
let glActiveTexture, glShader, glPositionData, glColorData, glBatchCount, glBatchAdditive, glAdditive;
|
|
3805
|
+
let glActiveTexture, glShader, glArrayBuffer, glVertexData, glPositionData, glColorData, glBatchCount, glBatchAdditive, glAdditive;
|
|
3787
3806
|
|
|
3788
3807
|
///////////////////////////////////////////////////////////////////////////////
|
|
3789
3808
|
|
|
3790
3809
|
// Init WebGL, called automatically by the engine
|
|
3791
3810
|
function glInit()
|
|
3792
3811
|
{
|
|
3793
|
-
if (!glEnable) return;
|
|
3794
|
-
|
|
3795
3812
|
// create the canvas and tile texture
|
|
3796
3813
|
glCanvas = document.createElement('canvas');
|
|
3797
3814
|
glContext = glCanvas.getContext('webgl', {antialias: false});
|
|
@@ -3824,24 +3841,11 @@ function glInit()
|
|
|
3824
3841
|
);
|
|
3825
3842
|
|
|
3826
3843
|
// init buffers
|
|
3827
|
-
|
|
3828
|
-
|
|
3844
|
+
glVertexData = new ArrayBuffer(gl_MAX_BATCH * gl_VERTICES_PER_QUAD * gl_VERTEX_BYTE_STRIDE);
|
|
3845
|
+
glArrayBuffer = glContext.createBuffer();
|
|
3829
3846
|
glPositionData = new Float32Array(glVertexData);
|
|
3830
3847
|
glColorData = new Uint32Array(glVertexData);
|
|
3831
|
-
|
|
3832
|
-
// setup the vertex data array
|
|
3833
|
-
let offset = glBatchCount = 0;
|
|
3834
|
-
const initVertexAttribArray = (name, type, typeSize, size, normalize=0)=>
|
|
3835
|
-
{
|
|
3836
|
-
const location = glContext.getAttribLocation(glShader, name);
|
|
3837
|
-
glContext.enableVertexAttribArray(location);
|
|
3838
|
-
glContext.vertexAttribPointer(location, size, type, normalize, gl_VERTEX_BYTE_STRIDE, offset);
|
|
3839
|
-
offset += size*typeSize;
|
|
3840
|
-
}
|
|
3841
|
-
initVertexAttribArray('p', gl_FLOAT, 4, 2); // position
|
|
3842
|
-
initVertexAttribArray('t', gl_FLOAT, 4, 2); // texture coords
|
|
3843
|
-
initVertexAttribArray('c', gl_UNSIGNED_BYTE, 1, 4, 1); // color
|
|
3844
|
-
initVertexAttribArray('a', gl_UNSIGNED_BYTE, 1, 4, 1); // additiveColor
|
|
3848
|
+
glBatchCount = 0;
|
|
3845
3849
|
}
|
|
3846
3850
|
|
|
3847
3851
|
/** Set the WebGl blend mode, normally you should call setBlendMode instead
|
|
@@ -3849,8 +3853,6 @@ function glInit()
|
|
|
3849
3853
|
* @memberof WebGL */
|
|
3850
3854
|
function glSetBlendMode(additive)
|
|
3851
3855
|
{
|
|
3852
|
-
if (!glEnable) return;
|
|
3853
|
-
|
|
3854
3856
|
// setup blending
|
|
3855
3857
|
glAdditive = additive;
|
|
3856
3858
|
}
|
|
@@ -3861,8 +3863,6 @@ function glSetBlendMode(additive)
|
|
|
3861
3863
|
* @memberof WebGL */
|
|
3862
3864
|
function glSetTexture(texture=glTileTexture)
|
|
3863
3865
|
{
|
|
3864
|
-
if (!glEnable) return;
|
|
3865
|
-
|
|
3866
3866
|
// must flush cache with the old texture to set a new one
|
|
3867
3867
|
if (texture != glActiveTexture)
|
|
3868
3868
|
glFlush();
|
|
@@ -3877,8 +3877,6 @@ function glSetTexture(texture=glTileTexture)
|
|
|
3877
3877
|
* @memberof WebGL */
|
|
3878
3878
|
function glCompileShader(source, type)
|
|
3879
3879
|
{
|
|
3880
|
-
if (!glEnable) return;
|
|
3881
|
-
|
|
3882
3880
|
// build the shader
|
|
3883
3881
|
const shader = glContext.createShader(type);
|
|
3884
3882
|
glContext.shaderSource(shader, source);
|
|
@@ -3897,8 +3895,6 @@ function glCompileShader(source, type)
|
|
|
3897
3895
|
* @memberof WebGL */
|
|
3898
3896
|
function glCreateProgram(vsSource, fsSource)
|
|
3899
3897
|
{
|
|
3900
|
-
if (!glEnable) return;
|
|
3901
|
-
|
|
3902
3898
|
// build the program
|
|
3903
3899
|
const program = glContext.createProgram();
|
|
3904
3900
|
glContext.attachShader(program, glCompileShader(vsSource, gl_VERTEX_SHADER));
|
|
@@ -3911,35 +3907,16 @@ function glCreateProgram(vsSource, fsSource)
|
|
|
3911
3907
|
return program;
|
|
3912
3908
|
}
|
|
3913
3909
|
|
|
3914
|
-
/** Create WebGL buffer
|
|
3915
|
-
* @param bufferType
|
|
3916
|
-
* @param size
|
|
3917
|
-
* @param usage
|
|
3918
|
-
* @return {WebGLBuffer}
|
|
3919
|
-
* @memberof WebGL */
|
|
3920
|
-
function glCreateBuffer(bufferType, size, usage)
|
|
3921
|
-
{
|
|
3922
|
-
if (!glEnable) return;
|
|
3923
|
-
|
|
3924
|
-
// build the buffer
|
|
3925
|
-
const buffer = glContext.createBuffer();
|
|
3926
|
-
glContext.bindBuffer(bufferType, buffer);
|
|
3927
|
-
glContext.bufferData(bufferType, size, usage);
|
|
3928
|
-
return buffer;
|
|
3929
|
-
}
|
|
3930
|
-
|
|
3931
3910
|
/** Create WebGL texture from an image and set the texture settings
|
|
3932
3911
|
* @param {Image} image
|
|
3933
3912
|
* @return {WebGLTexture}
|
|
3934
3913
|
* @memberof WebGL */
|
|
3935
3914
|
function glCreateTexture(image)
|
|
3936
3915
|
{
|
|
3937
|
-
if (!glEnable || !image || !image.width) return;
|
|
3938
|
-
|
|
3939
3916
|
// build the texture
|
|
3940
3917
|
const texture = glContext.createTexture();
|
|
3941
3918
|
glContext.bindTexture(gl_TEXTURE_2D, texture);
|
|
3942
|
-
glContext.texImage2D(gl_TEXTURE_2D, 0, gl_RGBA, gl_RGBA, gl_UNSIGNED_BYTE, image);
|
|
3919
|
+
image && image.width && glContext.texImage2D(gl_TEXTURE_2D, 0, gl_RGBA, gl_RGBA, gl_UNSIGNED_BYTE, image);
|
|
3943
3920
|
|
|
3944
3921
|
// use point filtering for pixelated rendering
|
|
3945
3922
|
glContext.texParameteri(gl_TEXTURE_2D, gl_TEXTURE_MIN_FILTER, cavasPixelated ? gl_NEAREST : gl_LINEAR);
|
|
@@ -3952,16 +3929,31 @@ function glCreateTexture(image)
|
|
|
3952
3929
|
// called automatically by engine before render
|
|
3953
3930
|
function glPreRender(width, height, cameraX, cameraY, cameraScale)
|
|
3954
3931
|
{
|
|
3955
|
-
if (!glEnable) return;
|
|
3956
|
-
|
|
3957
3932
|
// clear and set to same size as main canvas
|
|
3958
3933
|
glContext.viewport(0, 0, glCanvas.width = width, glCanvas.height = height);
|
|
3959
3934
|
glContext.clear(gl_COLOR_BUFFER_BIT);
|
|
3960
3935
|
|
|
3961
3936
|
// set up the shader
|
|
3962
|
-
glContext.bindTexture(gl_TEXTURE_2D, glActiveTexture = glTileTexture);
|
|
3963
3937
|
glContext.useProgram(glShader);
|
|
3938
|
+
glContext.activeTexture(gl_TEXTURE0);
|
|
3939
|
+
glContext.bindTexture(gl_TEXTURE_2D, glActiveTexture = glTileTexture);
|
|
3940
|
+
glContext.bindBuffer(gl_ARRAY_BUFFER, glArrayBuffer);
|
|
3941
|
+
glContext.bufferData(gl_ARRAY_BUFFER, glVertexData.byteLength, gl_DYNAMIC_DRAW);
|
|
3964
3942
|
glSetBlendMode();
|
|
3943
|
+
|
|
3944
|
+
// set vertex attributes
|
|
3945
|
+
let offset = 0;
|
|
3946
|
+
const initVertexAttribArray = (name, type, typeSize, size, normalize=0)=>
|
|
3947
|
+
{
|
|
3948
|
+
const location = glContext.getAttribLocation(glShader, name);
|
|
3949
|
+
glContext.enableVertexAttribArray(location);
|
|
3950
|
+
glContext.vertexAttribPointer(location, size, type, normalize, gl_VERTEX_BYTE_STRIDE, offset);
|
|
3951
|
+
offset += size*typeSize;
|
|
3952
|
+
}
|
|
3953
|
+
initVertexAttribArray('p', gl_FLOAT, 4, 2); // position
|
|
3954
|
+
initVertexAttribArray('t', gl_FLOAT, 4, 2); // texture coords
|
|
3955
|
+
initVertexAttribArray('c', gl_UNSIGNED_BYTE, 1, 4, 1); // color
|
|
3956
|
+
initVertexAttribArray('a', gl_UNSIGNED_BYTE, 1, 4, 1); // additiveColor
|
|
3965
3957
|
|
|
3966
3958
|
// build the transform matrix
|
|
3967
3959
|
const sx = 2 * cameraScale / width;
|
|
@@ -3980,7 +3972,7 @@ function glPreRender(width, height, cameraX, cameraY, cameraScale)
|
|
|
3980
3972
|
* @memberof WebGL */
|
|
3981
3973
|
function glFlush()
|
|
3982
3974
|
{
|
|
3983
|
-
if (!
|
|
3975
|
+
if (!glBatchCount) return;
|
|
3984
3976
|
|
|
3985
3977
|
const destBlend = glBatchAdditive ? gl_ONE : gl_ONE_MINUS_SRC_ALPHA;
|
|
3986
3978
|
glContext.blendFuncSeparate(gl_SRC_ALPHA, destBlend, gl_ONE, destBlend);
|
|
@@ -4000,7 +3992,7 @@ function glFlush()
|
|
|
4000
3992
|
* @memberof WebGL */
|
|
4001
3993
|
function glCopyToContext(context, forceDraw)
|
|
4002
3994
|
{
|
|
4003
|
-
if (!
|
|
3995
|
+
if (!glBatchCount && !forceDraw) return;
|
|
4004
3996
|
|
|
4005
3997
|
glFlush();
|
|
4006
3998
|
|
|
@@ -4024,8 +4016,6 @@ function glCopyToContext(context, forceDraw)
|
|
|
4024
4016
|
* @memberof WebGL */
|
|
4025
4017
|
function glDraw(x, y, sizeX, sizeY, angle, uv0X, uv0Y, uv1X, uv1Y, rgba=0xffffffff, rgbaAdditive=0)
|
|
4026
4018
|
{
|
|
4027
|
-
if (!glEnable) return;
|
|
4028
|
-
|
|
4029
4019
|
// flush if there is no room for more verts or if different blend mode
|
|
4030
4020
|
if (glBatchCount == gl_MAX_BATCH || glBatchAdditive != glAdditive)
|
|
4031
4021
|
glFlush();
|
|
@@ -4074,6 +4064,90 @@ function glDraw(x, y, sizeX, sizeY, angle, uv0X, uv0Y, uv1X, uv1Y, rgba=0xffffff
|
|
|
4074
4064
|
glColorData[offset++] = rgba; glColorData[offset++] = rgbaAdditive;
|
|
4075
4065
|
}
|
|
4076
4066
|
|
|
4067
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
4068
|
+
// post processing - can be enabled to pass other canvases through a final shader
|
|
4069
|
+
|
|
4070
|
+
let glPostShader, glPostArrayBuffer, glPostTexture;
|
|
4071
|
+
|
|
4072
|
+
/** Set up a post processing shader
|
|
4073
|
+
* @param {String} shaderCode
|
|
4074
|
+
* @memberof WebGL */
|
|
4075
|
+
function glInitPostProcess(shaderCode)
|
|
4076
|
+
{
|
|
4077
|
+
ASSERT(!glPostShader); // can only have 1 post effects shader
|
|
4078
|
+
|
|
4079
|
+
if (!shaderCode) // default shader
|
|
4080
|
+
shaderCode = 'void mainImage(out vec4 c,vec2 p){c=texture2D(iChannel0,p/iResolution.xy);}';
|
|
4081
|
+
|
|
4082
|
+
// create the shader
|
|
4083
|
+
glPostShader = glCreateProgram(
|
|
4084
|
+
'precision highp float;'+ // use highp for better accuracy
|
|
4085
|
+
'attribute vec2 p;'+ // position
|
|
4086
|
+
'void main(){'+ // shader entry point
|
|
4087
|
+
'gl_Position=vec4(p,1,1);'+ // set position
|
|
4088
|
+
'}' // end of shader
|
|
4089
|
+
,
|
|
4090
|
+
'precision highp float;'+ // use highp for better accuracy
|
|
4091
|
+
'uniform sampler2D iChannel0;'+ // input texture
|
|
4092
|
+
'uniform vec3 iResolution;'+ // size of output texture
|
|
4093
|
+
'uniform float iTime;'+ // time passed
|
|
4094
|
+
'\n' + shaderCode + '\n'+ // insert custom shader code
|
|
4095
|
+
'void main(){'+ // shader entry point
|
|
4096
|
+
'mainImage(gl_FragColor,gl_FragCoord.xy);'+ // call post process function
|
|
4097
|
+
'gl_FragColor.a=1.;'+ // always use full alpha
|
|
4098
|
+
'}' // end of shader
|
|
4099
|
+
);
|
|
4100
|
+
|
|
4101
|
+
// create buffer and texture
|
|
4102
|
+
glPostArrayBuffer = glContext.createBuffer();
|
|
4103
|
+
glPostTexture = glCreateTexture();
|
|
4104
|
+
|
|
4105
|
+
// hide the original 2d canvas
|
|
4106
|
+
mainCanvas.style.visibility = 'hidden';
|
|
4107
|
+
}
|
|
4108
|
+
|
|
4109
|
+
// Render the post processing shader, called automatically by the engine
|
|
4110
|
+
function glRenderPostProcess()
|
|
4111
|
+
{
|
|
4112
|
+
if (!glPostShader)
|
|
4113
|
+
return;
|
|
4114
|
+
|
|
4115
|
+
// prepare to render post process shader
|
|
4116
|
+
const width = mainCanvas.width, height = mainCanvas.height;
|
|
4117
|
+
if (glEnable)
|
|
4118
|
+
{
|
|
4119
|
+
glFlush(); // clear out the buffer
|
|
4120
|
+
mainContext.drawImage(glCanvas, 0, 0); // copy to the main canvas
|
|
4121
|
+
}
|
|
4122
|
+
else
|
|
4123
|
+
glContext.viewport(0, 0, glCanvas.width = width, glCanvas.height = height); // set viewport
|
|
4124
|
+
|
|
4125
|
+
// setup shader program to draw one triangle
|
|
4126
|
+
glContext.useProgram(glPostShader);
|
|
4127
|
+
glContext.disable(gl_BLEND);
|
|
4128
|
+
glContext.bindBuffer(gl_ARRAY_BUFFER, glPostArrayBuffer);
|
|
4129
|
+
glContext.bufferData(gl_ARRAY_BUFFER, new Float32Array([-3,1,1,-3,1,1]), gl_STATIC_DRAW);
|
|
4130
|
+
glContext.pixelStorei(gl_UNPACK_FLIP_Y_WEBGL, true);
|
|
4131
|
+
|
|
4132
|
+
// set textures, pass in the 2d canvas and gl canvas in separate texture channels
|
|
4133
|
+
glContext.activeTexture(gl_TEXTURE0);
|
|
4134
|
+
glContext.bindTexture(gl_TEXTURE_2D, glPostTexture);
|
|
4135
|
+
glContext.texImage2D(gl_TEXTURE_2D, 0, gl_RGBA, gl_RGBA, gl_UNSIGNED_BYTE, mainCanvas);
|
|
4136
|
+
|
|
4137
|
+
// set vertex position attribute
|
|
4138
|
+
const vertexByteStride = 8;
|
|
4139
|
+
const pLocation = glContext.getAttribLocation(glPostShader, 'p');
|
|
4140
|
+
glContext.enableVertexAttribArray(pLocation);
|
|
4141
|
+
glContext.vertexAttribPointer(pLocation, 2, gl_FLOAT, 0, vertexByteStride, 0);
|
|
4142
|
+
|
|
4143
|
+
// set uniforms and draw
|
|
4144
|
+
const uniformLocation = (name)=>glContext.getUniformLocation(glPostShader, name);
|
|
4145
|
+
glContext.uniform1i(uniformLocation('iChannel0'), 0);
|
|
4146
|
+
glContext.uniform1f(uniformLocation('iTime'), time);
|
|
4147
|
+
glContext.uniform3f(uniformLocation('iResolution'), width, height, 1);
|
|
4148
|
+
glContext.drawArrays(gl_TRIANGLES, 0, 3);
|
|
4149
|
+
}
|
|
4150
|
+
|
|
4077
4151
|
///////////////////////////////////////////////////////////////////////////////
|
|
4078
4152
|
// store gl constants as integers so their name doesn't use space in minifed
|
|
4079
4153
|
const
|
|
@@ -4084,6 +4158,7 @@ gl_ONE_MINUS_SRC_ALPHA = 771,
|
|
|
4084
4158
|
gl_BLEND = 3042,
|
|
4085
4159
|
gl_TEXTURE_2D = 3553,
|
|
4086
4160
|
gl_UNSIGNED_BYTE = 5121,
|
|
4161
|
+
gl_BYTE = 5120,
|
|
4087
4162
|
gl_FLOAT = 5126,
|
|
4088
4163
|
gl_RGBA = 6408,
|
|
4089
4164
|
gl_NEAREST = 9728,
|
|
@@ -4094,12 +4169,16 @@ gl_TEXTURE_WRAP_S = 10242,
|
|
|
4094
4169
|
gl_TEXTURE_WRAP_T = 10243,
|
|
4095
4170
|
gl_COLOR_BUFFER_BIT = 16384,
|
|
4096
4171
|
gl_CLAMP_TO_EDGE = 33071,
|
|
4172
|
+
gl_TEXTURE0 = 33984,
|
|
4173
|
+
gl_TEXTURE1 = 33985,
|
|
4097
4174
|
gl_ARRAY_BUFFER = 34962,
|
|
4175
|
+
gl_STATIC_DRAW = 35044,
|
|
4098
4176
|
gl_DYNAMIC_DRAW = 35048,
|
|
4099
4177
|
gl_FRAGMENT_SHADER = 35632,
|
|
4100
4178
|
gl_VERTEX_SHADER = 35633,
|
|
4101
4179
|
gl_COMPILE_STATUS = 35713,
|
|
4102
4180
|
gl_LINK_STATUS = 35714,
|
|
4181
|
+
gl_UNPACK_FLIP_Y_WEBGL = 37440,
|
|
4103
4182
|
|
|
4104
4183
|
// constants for batch rendering
|
|
4105
4184
|
gl_VERTICES_PER_QUAD = 6,
|
|
@@ -4130,7 +4209,7 @@ gl_VERTEX_BYTE_STRIDE = (4 * 2) * 2 + (4) * 2; // vec2 * 2 + (char * 4) * 2
|
|
|
4130
4209
|
const engineName = 'LittleJS';
|
|
4131
4210
|
|
|
4132
4211
|
/** Version of engine */
|
|
4133
|
-
const engineVersion = '1.4.
|
|
4212
|
+
const engineVersion = '1.4.6';
|
|
4134
4213
|
|
|
4135
4214
|
/** Frames per second to update objects
|
|
4136
4215
|
* @default */
|
|
@@ -4165,8 +4244,7 @@ let frameTimeLastMS = 0, frameTimeBufferMS = 0, tileImageSize, tileImageFixBleed
|
|
|
4165
4244
|
let averageFPS, drawCount;
|
|
4166
4245
|
|
|
4167
4246
|
// css text used for elements created by engine
|
|
4168
|
-
const styleBody = 'margin:0;overflow:hidden;background:#000'
|
|
4169
|
-
';touch-action:none;user-select:none;-webkit-user-select:none;-moz-user-select:none';
|
|
4247
|
+
const styleBody = 'margin:0;overflow:hidden;background:#000';
|
|
4170
4248
|
const styleCanvas = 'position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)';
|
|
4171
4249
|
|
|
4172
4250
|
///////////////////////////////////////////////////////////////////////////////
|
|
@@ -4196,7 +4274,7 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
|
|
|
4196
4274
|
|
|
4197
4275
|
// init stuff and start engine
|
|
4198
4276
|
debugInit();
|
|
4199
|
-
glInit();
|
|
4277
|
+
glEnable && glInit();
|
|
4200
4278
|
|
|
4201
4279
|
// create overlay canvas for hud to appear above gl canvas
|
|
4202
4280
|
document.body.appendChild(overlayCanvas = document.createElement('canvas'));
|
|
@@ -4216,10 +4294,14 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
|
|
|
4216
4294
|
frameTimeLastMS = frameTimeMS;
|
|
4217
4295
|
if (debug || showWatermark)
|
|
4218
4296
|
averageFPS = lerp(.05, averageFPS || 0, 1e3/(frameTimeDeltaMS||1));
|
|
4297
|
+
const debugSpeedUp = debug && keyIsDown(107); // +
|
|
4298
|
+
const debugSpeedDown = debug && keyIsDown(109); // -
|
|
4219
4299
|
if (debug)
|
|
4220
|
-
frameTimeDeltaMS *=
|
|
4300
|
+
frameTimeDeltaMS *= debugSpeedUp ? 5 : debugSpeedDown ? .2 : 1; // +/- to speed/slow time
|
|
4221
4301
|
timeReal += frameTimeDeltaMS / 1e3;
|
|
4222
|
-
frameTimeBufferMS
|
|
4302
|
+
frameTimeBufferMS += !paused * frameTimeDeltaMS;
|
|
4303
|
+
if (!debugSpeedUp)
|
|
4304
|
+
frameTimeBufferMS = min(frameTimeBufferMS, 50); // clamp incase of slow framerate
|
|
4223
4305
|
|
|
4224
4306
|
if (canvasFixedSize.x)
|
|
4225
4307
|
{
|
|
@@ -4292,10 +4374,11 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
|
|
|
4292
4374
|
for (const o of engineObjects)
|
|
4293
4375
|
o.destroyed || o.render();
|
|
4294
4376
|
gameRenderPost();
|
|
4377
|
+
glRenderPostProcess();
|
|
4295
4378
|
medalsRender();
|
|
4296
4379
|
touchGamepadRender();
|
|
4297
4380
|
debugRender();
|
|
4298
|
-
glCopyToContext(mainContext);
|
|
4381
|
+
glEnable && glCopyToContext(mainContext);
|
|
4299
4382
|
|
|
4300
4383
|
if (showWatermark)
|
|
4301
4384
|
{
|
|
@@ -4330,7 +4413,7 @@ function enginePreRender()
|
|
|
4330
4413
|
mainContext.imageSmoothingEnabled = !cavasPixelated;
|
|
4331
4414
|
|
|
4332
4415
|
// setup gl rendering if enabled
|
|
4333
|
-
glPreRender(mainCanvas.width, mainCanvas.height, cameraPos.x, cameraPos.y, cameraScale);
|
|
4416
|
+
glEnable && glPreRender(mainCanvas.width, mainCanvas.height, cameraPos.x, cameraPos.y, cameraScale);
|
|
4334
4417
|
}
|
|
4335
4418
|
|
|
4336
4419
|
///////////////////////////////////////////////////////////////////////////////
|