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
|
@@ -468,10 +468,10 @@ class Color
|
|
|
468
468
|
* @return {Array} */
|
|
469
469
|
getHSLA()
|
|
470
470
|
{
|
|
471
|
-
const r = this.r;
|
|
472
|
-
const g = this.g;
|
|
473
|
-
const b = this.b;
|
|
474
|
-
const a = this.a;
|
|
471
|
+
const r = clamp(this.r);
|
|
472
|
+
const g = clamp(this.g);
|
|
473
|
+
const b = clamp(this.b);
|
|
474
|
+
const a = clamp(this.a);
|
|
475
475
|
const max = Math.max(r, g, b);
|
|
476
476
|
const min = Math.min(r, g, b);
|
|
477
477
|
const l = (max + min) / 2;
|
|
@@ -507,20 +507,13 @@ class Color
|
|
|
507
507
|
).clamp();
|
|
508
508
|
}
|
|
509
509
|
|
|
510
|
-
/** Returns this color expressed as
|
|
510
|
+
/** Returns this color expressed as a hex color code
|
|
511
|
+
* @param {Boolean} [useAlpha=1] - if alpha should be included in result
|
|
511
512
|
* @return {String} */
|
|
512
|
-
toString()
|
|
513
|
+
toString(useAlpha = 1)
|
|
513
514
|
{
|
|
514
|
-
|
|
515
|
-
return
|
|
516
|
-
}
|
|
517
|
-
|
|
518
|
-
/** Returns this color expressed as 32 bit integer RGBA value
|
|
519
|
-
* @return {Number} */
|
|
520
|
-
rgbaInt()
|
|
521
|
-
{
|
|
522
|
-
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);
|
|
523
|
-
return (this.r*255|0) + (this.g*255<<8) + (this.b*255<<16) + (this.a*255<<24);
|
|
515
|
+
const toHex = (c)=> ((c=c*255|0)<16 ? '0' : '') + c.toString(16);
|
|
516
|
+
return '#' + toHex(this.r) + toHex(this.g) + toHex(this.b) + (useAlpha ? toHex(this.a) : '');
|
|
524
517
|
}
|
|
525
518
|
|
|
526
519
|
/** Set this color from a hex code
|
|
@@ -528,21 +521,24 @@ class Color
|
|
|
528
521
|
* @return {Color} */
|
|
529
522
|
setHex(hex)
|
|
530
523
|
{
|
|
531
|
-
const fromHex = (
|
|
524
|
+
const fromHex = (c)=> clamp(parseInt(hex.slice(c,c+2),16)/255);
|
|
532
525
|
this.r = fromHex(1);
|
|
533
526
|
this.g = fromHex(3),
|
|
534
527
|
this.b = fromHex(5);
|
|
535
|
-
this.a = 1;
|
|
536
|
-
ASSERT(this.r>=0 && this.r<=1 && this.g>=0 && this.g<=1 && this.b>=0 && this.b<=1);
|
|
528
|
+
this.a = hex.length > 7 ? fromHex(7) : 1;
|
|
537
529
|
return this;
|
|
538
530
|
}
|
|
539
|
-
|
|
540
|
-
/** Returns this color expressed as
|
|
541
|
-
* @return {
|
|
542
|
-
|
|
531
|
+
|
|
532
|
+
/** Returns this color expressed as 32 bit RGBA value
|
|
533
|
+
* @return {Number} */
|
|
534
|
+
rgbaInt()
|
|
543
535
|
{
|
|
544
|
-
const
|
|
545
|
-
|
|
536
|
+
const toByte = (c)=> clamp(c)*255|0;
|
|
537
|
+
const r = toByte(this.r);
|
|
538
|
+
const g = toByte(this.g)<<8;
|
|
539
|
+
const b = toByte(this.b)<<16;
|
|
540
|
+
const a = toByte(this.a)<<24;
|
|
541
|
+
return r + g + b + a;
|
|
546
542
|
}
|
|
547
543
|
}
|
|
548
544
|
|
|
@@ -845,7 +841,7 @@ let medalDisplayIconSize = 50;
|
|
|
845
841
|
const engineName = 'LittleJS';
|
|
846
842
|
|
|
847
843
|
/** Version of engine */
|
|
848
|
-
const engineVersion = '1.4.
|
|
844
|
+
const engineVersion = '1.4.6';
|
|
849
845
|
|
|
850
846
|
/** Frames per second to update objects
|
|
851
847
|
* @default */
|
|
@@ -880,8 +876,7 @@ let frameTimeLastMS = 0, frameTimeBufferMS = 0, tileImageSize, tileImageFixBleed
|
|
|
880
876
|
let averageFPS, drawCount;
|
|
881
877
|
|
|
882
878
|
// css text used for elements created by engine
|
|
883
|
-
const styleBody = 'margin:0;overflow:hidden;background:#000'
|
|
884
|
-
';touch-action:none;user-select:none;-webkit-user-select:none;-moz-user-select:none';
|
|
879
|
+
const styleBody = 'margin:0;overflow:hidden;background:#000';
|
|
885
880
|
const styleCanvas = 'position:absolute;top:50%;left:50%;transform:translate(-50%,-50%)';
|
|
886
881
|
|
|
887
882
|
///////////////////////////////////////////////////////////////////////////////
|
|
@@ -911,7 +906,7 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
|
|
|
911
906
|
|
|
912
907
|
// init stuff and start engine
|
|
913
908
|
debugInit();
|
|
914
|
-
glInit();
|
|
909
|
+
glEnable && glInit();
|
|
915
910
|
|
|
916
911
|
// create overlay canvas for hud to appear above gl canvas
|
|
917
912
|
document.body.appendChild(overlayCanvas = document.createElement('canvas'));
|
|
@@ -931,10 +926,14 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
|
|
|
931
926
|
frameTimeLastMS = frameTimeMS;
|
|
932
927
|
if (debug || showWatermark)
|
|
933
928
|
averageFPS = lerp(.05, averageFPS || 0, 1e3/(frameTimeDeltaMS||1));
|
|
929
|
+
const debugSpeedUp = debug && keyIsDown(107); // +
|
|
930
|
+
const debugSpeedDown = debug && keyIsDown(109); // -
|
|
934
931
|
if (debug)
|
|
935
|
-
frameTimeDeltaMS *=
|
|
932
|
+
frameTimeDeltaMS *= debugSpeedUp ? 5 : debugSpeedDown ? .2 : 1; // +/- to speed/slow time
|
|
936
933
|
timeReal += frameTimeDeltaMS / 1e3;
|
|
937
|
-
frameTimeBufferMS
|
|
934
|
+
frameTimeBufferMS += !paused * frameTimeDeltaMS;
|
|
935
|
+
if (!debugSpeedUp)
|
|
936
|
+
frameTimeBufferMS = min(frameTimeBufferMS, 50); // clamp incase of slow framerate
|
|
938
937
|
|
|
939
938
|
if (canvasFixedSize.x)
|
|
940
939
|
{
|
|
@@ -1007,10 +1006,11 @@ function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRender
|
|
|
1007
1006
|
for (const o of engineObjects)
|
|
1008
1007
|
o.destroyed || o.render();
|
|
1009
1008
|
gameRenderPost();
|
|
1009
|
+
glRenderPostProcess();
|
|
1010
1010
|
medalsRender();
|
|
1011
1011
|
touchGamepadRender();
|
|
1012
1012
|
debugRender();
|
|
1013
|
-
glCopyToContext(mainContext);
|
|
1013
|
+
glEnable && glCopyToContext(mainContext);
|
|
1014
1014
|
|
|
1015
1015
|
if (showWatermark)
|
|
1016
1016
|
{
|
|
@@ -1045,7 +1045,7 @@ function enginePreRender()
|
|
|
1045
1045
|
mainContext.imageSmoothingEnabled = !cavasPixelated;
|
|
1046
1046
|
|
|
1047
1047
|
// setup gl rendering if enabled
|
|
1048
|
-
glPreRender(mainCanvas.width, mainCanvas.height, cameraPos.x, cameraPos.y, cameraScale);
|
|
1048
|
+
glEnable && glPreRender(mainCanvas.width, mainCanvas.height, cameraPos.x, cameraPos.y, cameraScale);
|
|
1049
1049
|
}
|
|
1050
1050
|
|
|
1051
1051
|
///////////////////////////////////////////////////////////////////////////////
|
|
@@ -1406,7 +1406,7 @@ class EngineObject
|
|
|
1406
1406
|
* @return {Boolean} - true if the raycast should hit */
|
|
1407
1407
|
collideWithTileRaycast(tileData, pos) { return tileData > 0; }
|
|
1408
1408
|
|
|
1409
|
-
/** Called to check if a
|
|
1409
|
+
/** Called to check if a object collision should be resolved
|
|
1410
1410
|
* @param {EngineObject} object - the object to test against
|
|
1411
1411
|
* @return {Boolean} - true if the collision should be resolved
|
|
1412
1412
|
*/
|
|
@@ -1451,10 +1451,10 @@ class EngineObject
|
|
|
1451
1451
|
}
|
|
1452
1452
|
|
|
1453
1453
|
/** Set how this object collides
|
|
1454
|
-
* @param {boolean} [collideSolidObjects=
|
|
1455
|
-
* @param {boolean} [isSolid=
|
|
1454
|
+
* @param {boolean} [collideSolidObjects=1] - Does it collide with solid objects
|
|
1455
|
+
* @param {boolean} [isSolid=1] - Does it collide with and block other objects (expensive in large numbers)
|
|
1456
1456
|
* @param {boolean} [collideTiles=1] - Does it collide with the tile collision */
|
|
1457
|
-
setCollision(collideSolidObjects=
|
|
1457
|
+
setCollision(collideSolidObjects=1, isSolid=1, collideTiles=1)
|
|
1458
1458
|
{
|
|
1459
1459
|
ASSERT(collideSolidObjects || !isSolid); // solid objects must be set to collide
|
|
1460
1460
|
|
|
@@ -1717,21 +1717,21 @@ function setBlendMode(additive, useWebGL=glEnable)
|
|
|
1717
1717
|
* @param {Color} [lineColor=new Color(0,0,0)]
|
|
1718
1718
|
* @param {String} [textAlign='center']
|
|
1719
1719
|
* @memberof Draw */
|
|
1720
|
-
function drawTextScreen(text, pos, size=1, color=new Color, lineWidth=0, lineColor=new Color(0,0,0), textAlign='center', font=fontDefault)
|
|
1720
|
+
function drawTextScreen(text, pos, size=1, color=new Color, lineWidth=0, lineColor=new Color(0,0,0), textAlign='center', font=fontDefault, context=overlayContext)
|
|
1721
1721
|
{
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1722
|
+
context.fillStyle = color;
|
|
1723
|
+
context.lineWidth = lineWidth;
|
|
1724
|
+
context.strokeStyle = lineColor;
|
|
1725
|
+
context.textAlign = textAlign;
|
|
1726
|
+
context.font = size + 'px '+ font;
|
|
1727
|
+
context.textBaseline = 'middle';
|
|
1728
|
+
context.lineJoin = 'round';
|
|
1729
1729
|
|
|
1730
1730
|
pos = pos.copy();
|
|
1731
1731
|
(text+'').split('\n').forEach(line=>
|
|
1732
1732
|
{
|
|
1733
|
-
lineWidth &&
|
|
1734
|
-
|
|
1733
|
+
lineWidth && context.strokeText(line, pos.x, pos.y);
|
|
1734
|
+
context.fillText(line, pos.x, pos.y);
|
|
1735
1735
|
pos.y += size;
|
|
1736
1736
|
});
|
|
1737
1737
|
}
|
|
@@ -1748,7 +1748,7 @@ function drawTextScreen(text, pos, size=1, color=new Color, lineWidth=0, lineCol
|
|
|
1748
1748
|
* @memberof Draw */
|
|
1749
1749
|
function drawText(text, pos, size=1, color, lineWidth, lineColor, textAlign, font)
|
|
1750
1750
|
{
|
|
1751
|
-
drawTextScreen(text, worldToScreen(pos), size*cameraScale, color, lineWidth*cameraScale, lineColor, textAlign, font);
|
|
1751
|
+
drawTextScreen(text, worldToScreen(pos), size*cameraScale, color, lineWidth*cameraScale, lineColor, textAlign, font, mainContext);
|
|
1752
1752
|
}
|
|
1753
1753
|
|
|
1754
1754
|
///////////////////////////////////////////////////////////////////////////////
|
|
@@ -1771,7 +1771,7 @@ let engineFontImage;
|
|
|
1771
1771
|
class FontImage
|
|
1772
1772
|
{
|
|
1773
1773
|
/** Create an image font
|
|
1774
|
-
* @param {
|
|
1774
|
+
* @param {HTMLImageElement} [image] - The image the font is stored in, if undefined the default font is used
|
|
1775
1775
|
* @param {Vector2} [tileSize=vec2(8)] - The size of the font source tiles
|
|
1776
1776
|
* @param {Vector2} [paddingSize=vec2(0,1)] - How much extra space to add between characters
|
|
1777
1777
|
* @param {Number} [startTileIndex=0] - Tile index in image where font starts
|
|
@@ -1870,6 +1870,7 @@ function toggleFullscreen()
|
|
|
1870
1870
|
document.body.mozRequestFullScreen();
|
|
1871
1871
|
}
|
|
1872
1872
|
}
|
|
1873
|
+
|
|
1873
1874
|
/**
|
|
1874
1875
|
* LittleJS Input System
|
|
1875
1876
|
* <br> - Tracks key down, pressed, and released
|
|
@@ -1984,7 +1985,7 @@ let inputData = [[]];
|
|
|
1984
1985
|
function inputUpdate()
|
|
1985
1986
|
{
|
|
1986
1987
|
// clear input when lost focus (prevent stuck keys)
|
|
1987
|
-
document.hasFocus() || clearInput();
|
|
1988
|
+
isTouchDevice || document.hasFocus() || clearInput();
|
|
1988
1989
|
|
|
1989
1990
|
// update mouse world space position
|
|
1990
1991
|
mousePos = screenToWorld(mousePosScreen);
|
|
@@ -2059,7 +2060,7 @@ function gamepadsUpdate()
|
|
|
2059
2060
|
}
|
|
2060
2061
|
}
|
|
2061
2062
|
|
|
2062
|
-
if (!gamepadsEnable || !navigator.getGamepads || !document.hasFocus() && !debug)
|
|
2063
|
+
if (!gamepadsEnable || !navigator || !navigator.getGamepads || !document.hasFocus() && !debug)
|
|
2063
2064
|
return;
|
|
2064
2065
|
|
|
2065
2066
|
// poll gamepads
|
|
@@ -2108,7 +2109,7 @@ function gamepadsUpdate()
|
|
|
2108
2109
|
/** Pulse the vibration hardware if it exists
|
|
2109
2110
|
* @param {Number} [pattern=100] - a single value in miliseconds or vibration interval array
|
|
2110
2111
|
* @memberof Input */
|
|
2111
|
-
const vibrate = (pattern)=> vibrateEnable &&
|
|
2112
|
+
const vibrate = (pattern)=> vibrateEnable && navigator && navigator.vibrate && navigator.vibrate(pattern);
|
|
2112
2113
|
|
|
2113
2114
|
/** Cancel any ongoing vibration
|
|
2114
2115
|
* @memberof Input */
|
|
@@ -2126,7 +2127,7 @@ const isTouchDevice = window.ontouchstart !== undefined;
|
|
|
2126
2127
|
if (isTouchDevice)
|
|
2127
2128
|
{
|
|
2128
2129
|
// handle all touch events the same way
|
|
2129
|
-
let wasTouching,
|
|
2130
|
+
let wasTouching, hadTouch;
|
|
2130
2131
|
ontouchstart = ontouchmove = ontouchend = (e)=>
|
|
2131
2132
|
{
|
|
2132
2133
|
e.button = 0; // all touches are left click
|
|
@@ -2135,7 +2136,8 @@ if (isTouchDevice)
|
|
|
2135
2136
|
const touching = e.touches.length;
|
|
2136
2137
|
if (touching)
|
|
2137
2138
|
{
|
|
2138
|
-
|
|
2139
|
+
// fix mobile audio, force it to play a sound on first touch
|
|
2140
|
+
hadTouch || zzfx(0, hadTouch=1);
|
|
2139
2141
|
|
|
2140
2142
|
// set event pos and pass it along
|
|
2141
2143
|
e.x = e.touches[0].clientX;
|
|
@@ -2148,8 +2150,8 @@ if (isTouchDevice)
|
|
|
2148
2150
|
// set was touching
|
|
2149
2151
|
wasTouching = touching;
|
|
2150
2152
|
|
|
2151
|
-
//
|
|
2152
|
-
return
|
|
2153
|
+
// must return true so the document will get focus
|
|
2154
|
+
return true;
|
|
2153
2155
|
}
|
|
2154
2156
|
}
|
|
2155
2157
|
|
|
@@ -3006,7 +3008,7 @@ constructor(pos, size=tileCollisionSize, tileSize=tileSizeDefault, scale=vec2(1)
|
|
|
3006
3008
|
redrawEnd()
|
|
3007
3009
|
{
|
|
3008
3010
|
ASSERT(mainContext == this.context); // must call redrawStart() before drawing tiles
|
|
3009
|
-
glCopyToContext(mainContext, 1);
|
|
3011
|
+
glEnable && glCopyToContext(mainContext, 1);
|
|
3010
3012
|
//debugSaveCanvas(this.canvas);
|
|
3011
3013
|
|
|
3012
3014
|
// set stuff back to normal
|
|
@@ -3150,6 +3152,7 @@ class ParticleEmitter extends EngineObject
|
|
|
3150
3152
|
* @param {Boolean} [additive=0] - Should particles use addtive blend
|
|
3151
3153
|
* @param {Boolean} [randomColorLinear=1] - Should color be randomized linearly or across each component
|
|
3152
3154
|
* @param {Number} [renderOrder=0] - Render order for particles (additive is above other stuff by default)
|
|
3155
|
+
* @param {Boolean} [localSpace=0] - Should it be in local space of emitter (world space is default)
|
|
3153
3156
|
*/
|
|
3154
3157
|
constructor
|
|
3155
3158
|
(
|
|
@@ -3179,7 +3182,8 @@ class ParticleEmitter extends EngineObject
|
|
|
3179
3182
|
collideTiles,
|
|
3180
3183
|
additive,
|
|
3181
3184
|
randomColorLinear = 1,
|
|
3182
|
-
renderOrder = additive ? 1e9 : 0
|
|
3185
|
+
renderOrder = additive ? 1e9 : 0,
|
|
3186
|
+
localSpace
|
|
3183
3187
|
)
|
|
3184
3188
|
{
|
|
3185
3189
|
super(pos, new Vector2, tileIndex, tileSize, angle, undefined, renderOrder);
|
|
@@ -3233,6 +3237,8 @@ class ParticleEmitter extends EngineObject
|
|
|
3233
3237
|
this.collideTiles = collideTiles;
|
|
3234
3238
|
/** @property {Number} - Should particles use addtive blend */
|
|
3235
3239
|
this.additive = additive;
|
|
3240
|
+
/** @property {Boolean} - Should it be in local space of emitter */
|
|
3241
|
+
this.localSpace = localSpace;
|
|
3236
3242
|
/** @property {Number} - If set the partile is drawn as a trail, stretched in the drection of velocity */
|
|
3237
3243
|
this.trailScale = 0;
|
|
3238
3244
|
|
|
@@ -3268,30 +3274,38 @@ class ParticleEmitter extends EngineObject
|
|
|
3268
3274
|
emitParticle()
|
|
3269
3275
|
{
|
|
3270
3276
|
// spawn a particle
|
|
3271
|
-
|
|
3272
|
-
(new Vector2(rand(-.5,.5), rand(-.5,.5)))
|
|
3273
|
-
|
|
3274
|
-
|
|
3275
|
-
|
|
3277
|
+
let pos = this.emitSize.x != undefined ? // check if vec2 was used for size
|
|
3278
|
+
(new Vector2(rand(-.5,.5), rand(-.5,.5)))
|
|
3279
|
+
.multiply(this.emitSize).rotate(this.angle) // box emitter
|
|
3280
|
+
: randInCircle(this.emitSize * .5); // circle emitter
|
|
3281
|
+
let angle = rand(this.particleConeAngle, -this.particleConeAngle);
|
|
3282
|
+
if (!this.localSpace)
|
|
3283
|
+
{
|
|
3284
|
+
pos = this.pos.add(pos);
|
|
3285
|
+
angle += this.angle;
|
|
3286
|
+
}
|
|
3287
|
+
|
|
3288
|
+
const particle = new Particle(pos, this.tileIndex, this.tileSize, angle);
|
|
3276
3289
|
|
|
3277
3290
|
// randomness scales each paremeter by a percentage
|
|
3278
3291
|
const randomness = this.randomness;
|
|
3279
3292
|
const randomizeScale = (v)=> v + v*rand(randomness, -randomness);
|
|
3280
3293
|
|
|
3281
3294
|
// randomize particle settings
|
|
3282
|
-
const particleTime
|
|
3283
|
-
const sizeStart
|
|
3284
|
-
const sizeEnd
|
|
3285
|
-
const speed
|
|
3286
|
-
const angleSpeed
|
|
3287
|
-
const coneAngle
|
|
3288
|
-
const colorStart
|
|
3289
|
-
const colorEnd
|
|
3295
|
+
const particleTime = randomizeScale(this.particleTime);
|
|
3296
|
+
const sizeStart = randomizeScale(this.sizeStart);
|
|
3297
|
+
const sizeEnd = randomizeScale(this.sizeEnd);
|
|
3298
|
+
const speed = randomizeScale(this.speed);
|
|
3299
|
+
const angleSpeed = randomizeScale(this.angleSpeed) * randSign();
|
|
3300
|
+
const coneAngle = rand(this.emitConeAngle, -this.emitConeAngle);
|
|
3301
|
+
const colorStart = randColor(this.colorStartA, this.colorStartB, this.randomColorLinear);
|
|
3302
|
+
const colorEnd = randColor(this.colorEndA, this.colorEndB, this.randomColorLinear);
|
|
3303
|
+
const velocityAngle = this.localSpace ? coneAngle : this.angle + coneAngle;
|
|
3290
3304
|
|
|
3291
3305
|
// build particle settings
|
|
3292
3306
|
particle.colorStart = colorStart;
|
|
3293
3307
|
particle.colorEndDelta = colorEnd.subtract(colorStart);
|
|
3294
|
-
particle.velocity = (new Vector2).setAngle(
|
|
3308
|
+
particle.velocity = (new Vector2).setAngle(velocityAngle, speed);
|
|
3295
3309
|
particle.angleVelocity = angleSpeed;
|
|
3296
3310
|
particle.lifeTime = particleTime;
|
|
3297
3311
|
particle.sizeStart = sizeStart;
|
|
@@ -3307,6 +3321,7 @@ class ParticleEmitter extends EngineObject
|
|
|
3307
3321
|
particle.renderOrder = this.renderOrder;
|
|
3308
3322
|
particle.trailScale = this.trailScale;
|
|
3309
3323
|
particle.mirror = rand()<.5;
|
|
3324
|
+
particle.localSpaceEmitter = this.localSpace && this;
|
|
3310
3325
|
|
|
3311
3326
|
// setup callbacks for particles
|
|
3312
3327
|
particle.destroyCallback = this.particleDestroyCallback;
|
|
@@ -3353,20 +3368,31 @@ class Particle extends EngineObject
|
|
|
3353
3368
|
|
|
3354
3369
|
// draw the particle
|
|
3355
3370
|
this.additive && setBlendMode(1);
|
|
3371
|
+
|
|
3372
|
+
let pos = this.pos, angle = this.angle;
|
|
3373
|
+
if (this.localSpaceEmitter)
|
|
3374
|
+
{
|
|
3375
|
+
// in local space of emitter
|
|
3376
|
+
pos = this.localSpaceEmitter.pos.add(pos.rotate(-this.localSpaceEmitter.angle));
|
|
3377
|
+
angle += this.localSpaceEmitter.angle;
|
|
3378
|
+
}
|
|
3356
3379
|
if (this.trailScale)
|
|
3357
3380
|
{
|
|
3358
3381
|
// trail style particles
|
|
3359
|
-
|
|
3360
|
-
|
|
3382
|
+
let velocity = this.velocity;
|
|
3383
|
+
if (this.localSpaceEmitter)
|
|
3384
|
+
velocity = velocity.rotate(-this.localSpaceEmitter.angle);
|
|
3385
|
+
const speed = velocity.length();
|
|
3386
|
+
const direction = velocity.scale(1/speed);
|
|
3361
3387
|
const trailLength = speed * this.trailScale;
|
|
3362
3388
|
size.y = max(size.x, trailLength);
|
|
3363
|
-
|
|
3364
|
-
drawTile(
|
|
3389
|
+
angle = direction.angle();
|
|
3390
|
+
drawTile(pos.add(direction.multiply(vec2(0,-trailLength/2))), size, this.tileIndex, this.tileSize, color, angle, this.mirror);
|
|
3365
3391
|
}
|
|
3366
3392
|
else
|
|
3367
|
-
drawTile(
|
|
3393
|
+
drawTile(pos, size, this.tileIndex, this.tileSize, color, angle, this.mirror);
|
|
3368
3394
|
this.additive && setBlendMode();
|
|
3369
|
-
debugParticles && debugRect(
|
|
3395
|
+
debugParticles && debugRect(pos, size, '#f005', 0, angle);
|
|
3370
3396
|
|
|
3371
3397
|
if (p == 1)
|
|
3372
3398
|
{
|
|
@@ -3396,11 +3422,6 @@ const medals = [];
|
|
|
3396
3422
|
* @memberof Medals */
|
|
3397
3423
|
let medalsPreventUnlock;
|
|
3398
3424
|
|
|
3399
|
-
/** This can used to enable Newgrounds functionality
|
|
3400
|
-
* @type {Newgrounds}
|
|
3401
|
-
* @memberof Medals */
|
|
3402
|
-
let newgrounds;
|
|
3403
|
-
|
|
3404
3425
|
// Engine internal variables not exposed to documentation
|
|
3405
3426
|
let medalsDisplayQueue = [], medalsSaveName, medalsDisplayTimeLast;
|
|
3406
3427
|
|
|
@@ -3415,7 +3436,7 @@ function medalsInit(saveName)
|
|
|
3415
3436
|
{
|
|
3416
3437
|
// check if medals are unlocked
|
|
3417
3438
|
medalsSaveName = saveName;
|
|
3418
|
-
debugMedals || medals.forEach(medal=> localStorage[medal.storageKey()]);
|
|
3439
|
+
debugMedals || medals.forEach(medal=> medal.unlocked = (localStorage[medal.storageKey()] | 0));
|
|
3419
3440
|
}
|
|
3420
3441
|
|
|
3421
3442
|
/**
|
|
@@ -3548,6 +3569,15 @@ function medalsRender()
|
|
|
3548
3569
|
|
|
3549
3570
|
///////////////////////////////////////////////////////////////////////////////
|
|
3550
3571
|
|
|
3572
|
+
// global Newgrounds object
|
|
3573
|
+
let newgrounds;
|
|
3574
|
+
|
|
3575
|
+
/** This can used to enable Newgrounds functionality
|
|
3576
|
+
* @param {Number} app_id - The newgrounds App ID
|
|
3577
|
+
* @param {String} [cipher] - The encryption Key (AES-128/Base64)
|
|
3578
|
+
* @memberof Medals */
|
|
3579
|
+
function newgroundsInit(app_id, cipher) { newgrounds = new Newgrounds(app_id, cipher); }
|
|
3580
|
+
|
|
3551
3581
|
/**
|
|
3552
3582
|
* Newgrounds API wrapper object
|
|
3553
3583
|
* @example
|
|
@@ -3708,15 +3738,13 @@ let glContext;
|
|
|
3708
3738
|
let glTileTexture;
|
|
3709
3739
|
|
|
3710
3740
|
// WebGL internal variables not exposed to documentation
|
|
3711
|
-
let glActiveTexture, glShader, glPositionData, glColorData, glBatchCount, glBatchAdditive, glAdditive;
|
|
3741
|
+
let glActiveTexture, glShader, glArrayBuffer, glVertexData, glPositionData, glColorData, glBatchCount, glBatchAdditive, glAdditive;
|
|
3712
3742
|
|
|
3713
3743
|
///////////////////////////////////////////////////////////////////////////////
|
|
3714
3744
|
|
|
3715
3745
|
// Init WebGL, called automatically by the engine
|
|
3716
3746
|
function glInit()
|
|
3717
3747
|
{
|
|
3718
|
-
if (!glEnable) return;
|
|
3719
|
-
|
|
3720
3748
|
// create the canvas and tile texture
|
|
3721
3749
|
glCanvas = document.createElement('canvas');
|
|
3722
3750
|
glContext = glCanvas.getContext('webgl', {antialias: false});
|
|
@@ -3749,24 +3777,11 @@ function glInit()
|
|
|
3749
3777
|
);
|
|
3750
3778
|
|
|
3751
3779
|
// init buffers
|
|
3752
|
-
|
|
3753
|
-
|
|
3780
|
+
glVertexData = new ArrayBuffer(gl_MAX_BATCH * gl_VERTICES_PER_QUAD * gl_VERTEX_BYTE_STRIDE);
|
|
3781
|
+
glArrayBuffer = glContext.createBuffer();
|
|
3754
3782
|
glPositionData = new Float32Array(glVertexData);
|
|
3755
3783
|
glColorData = new Uint32Array(glVertexData);
|
|
3756
|
-
|
|
3757
|
-
// setup the vertex data array
|
|
3758
|
-
let offset = glBatchCount = 0;
|
|
3759
|
-
const initVertexAttribArray = (name, type, typeSize, size, normalize=0)=>
|
|
3760
|
-
{
|
|
3761
|
-
const location = glContext.getAttribLocation(glShader, name);
|
|
3762
|
-
glContext.enableVertexAttribArray(location);
|
|
3763
|
-
glContext.vertexAttribPointer(location, size, type, normalize, gl_VERTEX_BYTE_STRIDE, offset);
|
|
3764
|
-
offset += size*typeSize;
|
|
3765
|
-
}
|
|
3766
|
-
initVertexAttribArray('p', gl_FLOAT, 4, 2); // position
|
|
3767
|
-
initVertexAttribArray('t', gl_FLOAT, 4, 2); // texture coords
|
|
3768
|
-
initVertexAttribArray('c', gl_UNSIGNED_BYTE, 1, 4, 1); // color
|
|
3769
|
-
initVertexAttribArray('a', gl_UNSIGNED_BYTE, 1, 4, 1); // additiveColor
|
|
3784
|
+
glBatchCount = 0;
|
|
3770
3785
|
}
|
|
3771
3786
|
|
|
3772
3787
|
/** Set the WebGl blend mode, normally you should call setBlendMode instead
|
|
@@ -3774,8 +3789,6 @@ function glInit()
|
|
|
3774
3789
|
* @memberof WebGL */
|
|
3775
3790
|
function glSetBlendMode(additive)
|
|
3776
3791
|
{
|
|
3777
|
-
if (!glEnable) return;
|
|
3778
|
-
|
|
3779
3792
|
// setup blending
|
|
3780
3793
|
glAdditive = additive;
|
|
3781
3794
|
}
|
|
@@ -3786,8 +3799,6 @@ function glSetBlendMode(additive)
|
|
|
3786
3799
|
* @memberof WebGL */
|
|
3787
3800
|
function glSetTexture(texture=glTileTexture)
|
|
3788
3801
|
{
|
|
3789
|
-
if (!glEnable) return;
|
|
3790
|
-
|
|
3791
3802
|
// must flush cache with the old texture to set a new one
|
|
3792
3803
|
if (texture != glActiveTexture)
|
|
3793
3804
|
glFlush();
|
|
@@ -3802,8 +3813,6 @@ function glSetTexture(texture=glTileTexture)
|
|
|
3802
3813
|
* @memberof WebGL */
|
|
3803
3814
|
function glCompileShader(source, type)
|
|
3804
3815
|
{
|
|
3805
|
-
if (!glEnable) return;
|
|
3806
|
-
|
|
3807
3816
|
// build the shader
|
|
3808
3817
|
const shader = glContext.createShader(type);
|
|
3809
3818
|
glContext.shaderSource(shader, source);
|
|
@@ -3822,8 +3831,6 @@ function glCompileShader(source, type)
|
|
|
3822
3831
|
* @memberof WebGL */
|
|
3823
3832
|
function glCreateProgram(vsSource, fsSource)
|
|
3824
3833
|
{
|
|
3825
|
-
if (!glEnable) return;
|
|
3826
|
-
|
|
3827
3834
|
// build the program
|
|
3828
3835
|
const program = glContext.createProgram();
|
|
3829
3836
|
glContext.attachShader(program, glCompileShader(vsSource, gl_VERTEX_SHADER));
|
|
@@ -3836,35 +3843,16 @@ function glCreateProgram(vsSource, fsSource)
|
|
|
3836
3843
|
return program;
|
|
3837
3844
|
}
|
|
3838
3845
|
|
|
3839
|
-
/** Create WebGL buffer
|
|
3840
|
-
* @param bufferType
|
|
3841
|
-
* @param size
|
|
3842
|
-
* @param usage
|
|
3843
|
-
* @return {WebGLBuffer}
|
|
3844
|
-
* @memberof WebGL */
|
|
3845
|
-
function glCreateBuffer(bufferType, size, usage)
|
|
3846
|
-
{
|
|
3847
|
-
if (!glEnable) return;
|
|
3848
|
-
|
|
3849
|
-
// build the buffer
|
|
3850
|
-
const buffer = glContext.createBuffer();
|
|
3851
|
-
glContext.bindBuffer(bufferType, buffer);
|
|
3852
|
-
glContext.bufferData(bufferType, size, usage);
|
|
3853
|
-
return buffer;
|
|
3854
|
-
}
|
|
3855
|
-
|
|
3856
3846
|
/** Create WebGL texture from an image and set the texture settings
|
|
3857
3847
|
* @param {Image} image
|
|
3858
3848
|
* @return {WebGLTexture}
|
|
3859
3849
|
* @memberof WebGL */
|
|
3860
3850
|
function glCreateTexture(image)
|
|
3861
3851
|
{
|
|
3862
|
-
if (!glEnable || !image || !image.width) return;
|
|
3863
|
-
|
|
3864
3852
|
// build the texture
|
|
3865
3853
|
const texture = glContext.createTexture();
|
|
3866
3854
|
glContext.bindTexture(gl_TEXTURE_2D, texture);
|
|
3867
|
-
glContext.texImage2D(gl_TEXTURE_2D, 0, gl_RGBA, gl_RGBA, gl_UNSIGNED_BYTE, image);
|
|
3855
|
+
image && image.width && glContext.texImage2D(gl_TEXTURE_2D, 0, gl_RGBA, gl_RGBA, gl_UNSIGNED_BYTE, image);
|
|
3868
3856
|
|
|
3869
3857
|
// use point filtering for pixelated rendering
|
|
3870
3858
|
glContext.texParameteri(gl_TEXTURE_2D, gl_TEXTURE_MIN_FILTER, cavasPixelated ? gl_NEAREST : gl_LINEAR);
|
|
@@ -3877,16 +3865,31 @@ function glCreateTexture(image)
|
|
|
3877
3865
|
// called automatically by engine before render
|
|
3878
3866
|
function glPreRender(width, height, cameraX, cameraY, cameraScale)
|
|
3879
3867
|
{
|
|
3880
|
-
if (!glEnable) return;
|
|
3881
|
-
|
|
3882
3868
|
// clear and set to same size as main canvas
|
|
3883
3869
|
glContext.viewport(0, 0, glCanvas.width = width, glCanvas.height = height);
|
|
3884
3870
|
glContext.clear(gl_COLOR_BUFFER_BIT);
|
|
3885
3871
|
|
|
3886
3872
|
// set up the shader
|
|
3887
|
-
glContext.bindTexture(gl_TEXTURE_2D, glActiveTexture = glTileTexture);
|
|
3888
3873
|
glContext.useProgram(glShader);
|
|
3874
|
+
glContext.activeTexture(gl_TEXTURE0);
|
|
3875
|
+
glContext.bindTexture(gl_TEXTURE_2D, glActiveTexture = glTileTexture);
|
|
3876
|
+
glContext.bindBuffer(gl_ARRAY_BUFFER, glArrayBuffer);
|
|
3877
|
+
glContext.bufferData(gl_ARRAY_BUFFER, glVertexData.byteLength, gl_DYNAMIC_DRAW);
|
|
3889
3878
|
glSetBlendMode();
|
|
3879
|
+
|
|
3880
|
+
// set vertex attributes
|
|
3881
|
+
let offset = 0;
|
|
3882
|
+
const initVertexAttribArray = (name, type, typeSize, size, normalize=0)=>
|
|
3883
|
+
{
|
|
3884
|
+
const location = glContext.getAttribLocation(glShader, name);
|
|
3885
|
+
glContext.enableVertexAttribArray(location);
|
|
3886
|
+
glContext.vertexAttribPointer(location, size, type, normalize, gl_VERTEX_BYTE_STRIDE, offset);
|
|
3887
|
+
offset += size*typeSize;
|
|
3888
|
+
}
|
|
3889
|
+
initVertexAttribArray('p', gl_FLOAT, 4, 2); // position
|
|
3890
|
+
initVertexAttribArray('t', gl_FLOAT, 4, 2); // texture coords
|
|
3891
|
+
initVertexAttribArray('c', gl_UNSIGNED_BYTE, 1, 4, 1); // color
|
|
3892
|
+
initVertexAttribArray('a', gl_UNSIGNED_BYTE, 1, 4, 1); // additiveColor
|
|
3890
3893
|
|
|
3891
3894
|
// build the transform matrix
|
|
3892
3895
|
const sx = 2 * cameraScale / width;
|
|
@@ -3905,7 +3908,7 @@ function glPreRender(width, height, cameraX, cameraY, cameraScale)
|
|
|
3905
3908
|
* @memberof WebGL */
|
|
3906
3909
|
function glFlush()
|
|
3907
3910
|
{
|
|
3908
|
-
if (!
|
|
3911
|
+
if (!glBatchCount) return;
|
|
3909
3912
|
|
|
3910
3913
|
const destBlend = glBatchAdditive ? gl_ONE : gl_ONE_MINUS_SRC_ALPHA;
|
|
3911
3914
|
glContext.blendFuncSeparate(gl_SRC_ALPHA, destBlend, gl_ONE, destBlend);
|
|
@@ -3925,7 +3928,7 @@ function glFlush()
|
|
|
3925
3928
|
* @memberof WebGL */
|
|
3926
3929
|
function glCopyToContext(context, forceDraw)
|
|
3927
3930
|
{
|
|
3928
|
-
if (!
|
|
3931
|
+
if (!glBatchCount && !forceDraw) return;
|
|
3929
3932
|
|
|
3930
3933
|
glFlush();
|
|
3931
3934
|
|
|
@@ -3949,8 +3952,6 @@ function glCopyToContext(context, forceDraw)
|
|
|
3949
3952
|
* @memberof WebGL */
|
|
3950
3953
|
function glDraw(x, y, sizeX, sizeY, angle, uv0X, uv0Y, uv1X, uv1Y, rgba=0xffffffff, rgbaAdditive=0)
|
|
3951
3954
|
{
|
|
3952
|
-
if (!glEnable) return;
|
|
3953
|
-
|
|
3954
3955
|
// flush if there is no room for more verts or if different blend mode
|
|
3955
3956
|
if (glBatchCount == gl_MAX_BATCH || glBatchAdditive != glAdditive)
|
|
3956
3957
|
glFlush();
|
|
@@ -3999,6 +4000,90 @@ function glDraw(x, y, sizeX, sizeY, angle, uv0X, uv0Y, uv1X, uv1Y, rgba=0xffffff
|
|
|
3999
4000
|
glColorData[offset++] = rgba; glColorData[offset++] = rgbaAdditive;
|
|
4000
4001
|
}
|
|
4001
4002
|
|
|
4003
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
4004
|
+
// post processing - can be enabled to pass other canvases through a final shader
|
|
4005
|
+
|
|
4006
|
+
let glPostShader, glPostArrayBuffer, glPostTexture;
|
|
4007
|
+
|
|
4008
|
+
/** Set up a post processing shader
|
|
4009
|
+
* @param {String} shaderCode
|
|
4010
|
+
* @memberof WebGL */
|
|
4011
|
+
function glInitPostProcess(shaderCode)
|
|
4012
|
+
{
|
|
4013
|
+
ASSERT(!glPostShader); // can only have 1 post effects shader
|
|
4014
|
+
|
|
4015
|
+
if (!shaderCode) // default shader
|
|
4016
|
+
shaderCode = 'void mainImage(out vec4 c,vec2 p){c=texture2D(iChannel0,p/iResolution.xy);}';
|
|
4017
|
+
|
|
4018
|
+
// create the shader
|
|
4019
|
+
glPostShader = glCreateProgram(
|
|
4020
|
+
'precision highp float;'+ // use highp for better accuracy
|
|
4021
|
+
'attribute vec2 p;'+ // position
|
|
4022
|
+
'void main(){'+ // shader entry point
|
|
4023
|
+
'gl_Position=vec4(p,1,1);'+ // set position
|
|
4024
|
+
'}' // end of shader
|
|
4025
|
+
,
|
|
4026
|
+
'precision highp float;'+ // use highp for better accuracy
|
|
4027
|
+
'uniform sampler2D iChannel0;'+ // input texture
|
|
4028
|
+
'uniform vec3 iResolution;'+ // size of output texture
|
|
4029
|
+
'uniform float iTime;'+ // time passed
|
|
4030
|
+
'\n' + shaderCode + '\n'+ // insert custom shader code
|
|
4031
|
+
'void main(){'+ // shader entry point
|
|
4032
|
+
'mainImage(gl_FragColor,gl_FragCoord.xy);'+ // call post process function
|
|
4033
|
+
'gl_FragColor.a=1.;'+ // always use full alpha
|
|
4034
|
+
'}' // end of shader
|
|
4035
|
+
);
|
|
4036
|
+
|
|
4037
|
+
// create buffer and texture
|
|
4038
|
+
glPostArrayBuffer = glContext.createBuffer();
|
|
4039
|
+
glPostTexture = glCreateTexture();
|
|
4040
|
+
|
|
4041
|
+
// hide the original 2d canvas
|
|
4042
|
+
mainCanvas.style.visibility = 'hidden';
|
|
4043
|
+
}
|
|
4044
|
+
|
|
4045
|
+
// Render the post processing shader, called automatically by the engine
|
|
4046
|
+
function glRenderPostProcess()
|
|
4047
|
+
{
|
|
4048
|
+
if (!glPostShader)
|
|
4049
|
+
return;
|
|
4050
|
+
|
|
4051
|
+
// prepare to render post process shader
|
|
4052
|
+
const width = mainCanvas.width, height = mainCanvas.height;
|
|
4053
|
+
if (glEnable)
|
|
4054
|
+
{
|
|
4055
|
+
glFlush(); // clear out the buffer
|
|
4056
|
+
mainContext.drawImage(glCanvas, 0, 0); // copy to the main canvas
|
|
4057
|
+
}
|
|
4058
|
+
else
|
|
4059
|
+
glContext.viewport(0, 0, glCanvas.width = width, glCanvas.height = height); // set viewport
|
|
4060
|
+
|
|
4061
|
+
// setup shader program to draw one triangle
|
|
4062
|
+
glContext.useProgram(glPostShader);
|
|
4063
|
+
glContext.disable(gl_BLEND);
|
|
4064
|
+
glContext.bindBuffer(gl_ARRAY_BUFFER, glPostArrayBuffer);
|
|
4065
|
+
glContext.bufferData(gl_ARRAY_BUFFER, new Float32Array([-3,1,1,-3,1,1]), gl_STATIC_DRAW);
|
|
4066
|
+
glContext.pixelStorei(gl_UNPACK_FLIP_Y_WEBGL, true);
|
|
4067
|
+
|
|
4068
|
+
// set textures, pass in the 2d canvas and gl canvas in separate texture channels
|
|
4069
|
+
glContext.activeTexture(gl_TEXTURE0);
|
|
4070
|
+
glContext.bindTexture(gl_TEXTURE_2D, glPostTexture);
|
|
4071
|
+
glContext.texImage2D(gl_TEXTURE_2D, 0, gl_RGBA, gl_RGBA, gl_UNSIGNED_BYTE, mainCanvas);
|
|
4072
|
+
|
|
4073
|
+
// set vertex position attribute
|
|
4074
|
+
const vertexByteStride = 8;
|
|
4075
|
+
const pLocation = glContext.getAttribLocation(glPostShader, 'p');
|
|
4076
|
+
glContext.enableVertexAttribArray(pLocation);
|
|
4077
|
+
glContext.vertexAttribPointer(pLocation, 2, gl_FLOAT, 0, vertexByteStride, 0);
|
|
4078
|
+
|
|
4079
|
+
// set uniforms and draw
|
|
4080
|
+
const uniformLocation = (name)=>glContext.getUniformLocation(glPostShader, name);
|
|
4081
|
+
glContext.uniform1i(uniformLocation('iChannel0'), 0);
|
|
4082
|
+
glContext.uniform1f(uniformLocation('iTime'), time);
|
|
4083
|
+
glContext.uniform3f(uniformLocation('iResolution'), width, height, 1);
|
|
4084
|
+
glContext.drawArrays(gl_TRIANGLES, 0, 3);
|
|
4085
|
+
}
|
|
4086
|
+
|
|
4002
4087
|
///////////////////////////////////////////////////////////////////////////////
|
|
4003
4088
|
// store gl constants as integers so their name doesn't use space in minifed
|
|
4004
4089
|
const
|
|
@@ -4009,6 +4094,7 @@ gl_ONE_MINUS_SRC_ALPHA = 771,
|
|
|
4009
4094
|
gl_BLEND = 3042,
|
|
4010
4095
|
gl_TEXTURE_2D = 3553,
|
|
4011
4096
|
gl_UNSIGNED_BYTE = 5121,
|
|
4097
|
+
gl_BYTE = 5120,
|
|
4012
4098
|
gl_FLOAT = 5126,
|
|
4013
4099
|
gl_RGBA = 6408,
|
|
4014
4100
|
gl_NEAREST = 9728,
|
|
@@ -4019,12 +4105,16 @@ gl_TEXTURE_WRAP_S = 10242,
|
|
|
4019
4105
|
gl_TEXTURE_WRAP_T = 10243,
|
|
4020
4106
|
gl_COLOR_BUFFER_BIT = 16384,
|
|
4021
4107
|
gl_CLAMP_TO_EDGE = 33071,
|
|
4108
|
+
gl_TEXTURE0 = 33984,
|
|
4109
|
+
gl_TEXTURE1 = 33985,
|
|
4022
4110
|
gl_ARRAY_BUFFER = 34962,
|
|
4111
|
+
gl_STATIC_DRAW = 35044,
|
|
4023
4112
|
gl_DYNAMIC_DRAW = 35048,
|
|
4024
4113
|
gl_FRAGMENT_SHADER = 35632,
|
|
4025
4114
|
gl_VERTEX_SHADER = 35633,
|
|
4026
4115
|
gl_COMPILE_STATUS = 35713,
|
|
4027
4116
|
gl_LINK_STATUS = 35714,
|
|
4117
|
+
gl_UNPACK_FLIP_Y_WEBGL = 37440,
|
|
4028
4118
|
|
|
4029
4119
|
// constants for batch rendering
|
|
4030
4120
|
gl_VERTICES_PER_QUAD = 6,
|