littlejsengine 1.16.1 → 1.17.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/littlejs.d.ts +287 -240
- package/dist/littlejs.esm.js +1419 -1259
- package/dist/littlejs.esm.min.js +1 -1
- package/dist/littlejs.js +1076 -910
- package/dist/littlejs.min.js +1 -1
- package/dist/littlejs.release.js +977 -815
- package/examples/box2d/gameObjects.js +6 -6
- package/examples/breakout/game.js +5 -6
- package/examples/electron/index.html +2 -2
- package/examples/electron/tiles.png +0 -0
- package/examples/htmlMenu/tiles.png +0 -0
- package/examples/index.html +1 -1
- package/examples/logo.png +0 -0
- package/examples/logo2.png +0 -0
- package/examples/module/tiles.png +0 -0
- package/examples/platformer/gameEffects.js +24 -23
- package/examples/platformer/gameLevel.js +24 -25
- package/examples/shorts/base.html +2 -1
- package/examples/shorts/clock.js +3 -3
- package/examples/shorts/fontImage.js +4 -3
- package/examples/shorts/parallax.js +1 -1
- package/examples/shorts/sequencer.js +1 -1
- package/examples/shorts/shapes.js +1 -1
- package/examples/shorts/texture.js +10 -6
- package/examples/shorts/tiles.png +0 -0
- package/examples/shorts/tiltedView.js +2 -0
- package/examples/starter/index.html +3 -2
- package/examples/starter/tiles.png +0 -0
- package/examples/typescript/tiles.png +0 -0
- package/examples/uiSystem/game.js +1 -1
- package/examples/uiSystem/tiles.png +0 -0
- package/package.json +1 -1
- package/plugins/postProcess.js +47 -28
- package/plugins/uiSystem.js +16 -16
- package/reference.md +6 -6
- package/src/engine.js +186 -198
- package/src/engineAudio.js +6 -10
- package/src/engineBuild.js +1 -0
- package/src/engineDebug.js +100 -98
- package/src/engineDraw.js +185 -148
- package/src/engineExport.js +327 -333
- package/src/engineFont.png +0 -0
- package/src/engineInput.js +17 -26
- package/src/engineMath.js +1112 -0
- package/src/engineMedals.js +4 -4
- package/src/engineObject.js +27 -27
- package/src/engineParticles.js +2 -2
- package/src/engineRelease.js +1 -3
- package/src/engineSettings.js +2 -2
- package/src/engineTileLayer.js +200 -176
- package/src/engineUtilities.js +48 -1097
- package/src/engineWebGL.js +127 -79
package/src/engineWebGL.js
CHANGED
|
@@ -29,7 +29,7 @@ let glContext;
|
|
|
29
29
|
let glAntialias = true;
|
|
30
30
|
|
|
31
31
|
// WebGL internal variables not exposed to documentation
|
|
32
|
-
let glShader, glPolyShader, glPolyMode, glAdditive, glBatchAdditive, glActiveTexture, glArrayBuffer, glGeometryBuffer, glPositionData, glColorData, glBatchCount, glTextureInfos, glCanBeEnabled = true;
|
|
32
|
+
let glShader, glPolyShader, glPolyMode, glAdditive, glBatchAdditive, glActiveTexture, glArrayBuffer, glGeometryBuffer, glPositionData, glColorData, glBatchCount, glTextureInfos, glInstancedVAO, glPolyVAO, glFramebuffer, glRenderTarget, glCanBeEnabled = true;
|
|
33
33
|
|
|
34
34
|
// WebGL internal constants
|
|
35
35
|
const gl_ARRAY_BUFFER_SIZE = 5e5;
|
|
@@ -105,7 +105,7 @@ function glInit(rootElement)
|
|
|
105
105
|
// setup instanced rendering shader program
|
|
106
106
|
glShader = glCreateProgram(
|
|
107
107
|
'#version 300 es\n' + // specify GLSL ES version
|
|
108
|
-
'precision highp float;'+ // use highp for
|
|
108
|
+
'precision highp float;'+ // use highp for accuracy
|
|
109
109
|
'uniform mat4 m;'+ // transform matrix
|
|
110
110
|
'in vec2 g;'+ // in: geometry
|
|
111
111
|
'in vec4 p,u,c,a;'+ // in: position/size, uvs, color, additiveColor
|
|
@@ -120,7 +120,7 @@ function glInit(rootElement)
|
|
|
120
120
|
'}' // end of shader
|
|
121
121
|
,
|
|
122
122
|
'#version 300 es\n' + // specify GLSL ES version
|
|
123
|
-
'precision highp float;'+ // use highp for
|
|
123
|
+
'precision highp float;'+ // use highp for accuracy
|
|
124
124
|
'uniform sampler2D s;'+ // texture
|
|
125
125
|
'in vec2 v;'+ // in: uv
|
|
126
126
|
'in vec4 d,e;'+ // in: color, additiveColor
|
|
@@ -158,87 +158,96 @@ function glInit(rootElement)
|
|
|
158
158
|
glColorData = new Uint32Array(glInstanceData);
|
|
159
159
|
glArrayBuffer = glContext.createBuffer();
|
|
160
160
|
glGeometryBuffer = glContext.createBuffer();
|
|
161
|
+
glFramebuffer = glContext.createFramebuffer();
|
|
162
|
+
glBatchCount = 0;
|
|
161
163
|
|
|
162
164
|
// create the geometry buffer, triangle strip square
|
|
163
|
-
const geometry = new Float32Array([
|
|
165
|
+
const geometry = new Float32Array([0,0,1,0,0,1,1,1]);
|
|
164
166
|
glContext.bindBuffer(glContext.ARRAY_BUFFER, glGeometryBuffer);
|
|
165
167
|
glContext.bufferData(glContext.ARRAY_BUFFER, geometry, glContext.STATIC_DRAW);
|
|
168
|
+
|
|
169
|
+
let offset, shader, stride;
|
|
170
|
+
const initVertexAttrib = (name, type, typeSize, size, divisor=0)=>
|
|
171
|
+
{
|
|
172
|
+
const location = glContext.getAttribLocation(shader, name);
|
|
173
|
+
const normalize = typeSize === 1;
|
|
174
|
+
const fixedStride = typeSize && stride;
|
|
175
|
+
glContext.enableVertexAttribArray(location);
|
|
176
|
+
glContext.vertexAttribPointer(location, size, type, normalize, fixedStride, offset);
|
|
177
|
+
glContext.vertexAttribDivisor(location, divisor);
|
|
178
|
+
offset += size*typeSize;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// setup VAO for instanced rendering
|
|
182
|
+
glInstancedVAO = glContext.createVertexArray();
|
|
183
|
+
glContext.bindVertexArray(glInstancedVAO);
|
|
184
|
+
|
|
185
|
+
// configure instanced vertex attributes
|
|
186
|
+
offset = 0, shader = glShader, stride = gl_INSTANCE_BYTE_STRIDE;
|
|
187
|
+
glContext.bindBuffer(glContext.ARRAY_BUFFER, glGeometryBuffer);
|
|
188
|
+
initVertexAttrib('g', glContext.FLOAT, 0, 2); // geometry
|
|
189
|
+
glContext.bindBuffer(glContext.ARRAY_BUFFER, glArrayBuffer);
|
|
190
|
+
glContext.bufferData(glContext.ARRAY_BUFFER, gl_ARRAY_BUFFER_SIZE, glContext.DYNAMIC_DRAW);
|
|
191
|
+
initVertexAttrib('p', glContext.FLOAT, 4, 4, 1); // position & size
|
|
192
|
+
initVertexAttrib('u', glContext.FLOAT, 4, 4, 1); // texture coords
|
|
193
|
+
initVertexAttrib('c', glContext.UNSIGNED_BYTE, 1, 4, 1); // color
|
|
194
|
+
initVertexAttrib('a', glContext.UNSIGNED_BYTE, 1, 4, 1); // additiveColor
|
|
195
|
+
initVertexAttrib('r', glContext.FLOAT, 4, 1, 1); // rotation
|
|
196
|
+
|
|
197
|
+
// setup VAO for poly rendering
|
|
198
|
+
glPolyVAO = glContext.createVertexArray();
|
|
199
|
+
glContext.bindVertexArray(glPolyVAO);
|
|
200
|
+
|
|
201
|
+
// configure poly vertex attributes
|
|
202
|
+
offset = 0, shader = glPolyShader, stride = gl_POLY_VERTEX_BYTE_STRIDE;
|
|
203
|
+
initVertexAttrib('p', glContext.FLOAT, 4, 2); // position
|
|
204
|
+
initVertexAttrib('c', glContext.UNSIGNED_BYTE, 1, 4); // color
|
|
166
205
|
}
|
|
167
206
|
}
|
|
168
207
|
|
|
169
|
-
function glSetInstancedMode()
|
|
208
|
+
function glSetInstancedMode(force=false)
|
|
170
209
|
{
|
|
171
|
-
if (!glPolyMode)
|
|
172
|
-
return;
|
|
210
|
+
if (!force && !glPolyMode) return;
|
|
173
211
|
|
|
174
212
|
// setup instanced mode
|
|
175
213
|
glFlush();
|
|
176
214
|
glPolyMode = false;
|
|
177
215
|
glContext.useProgram(glShader);
|
|
178
|
-
|
|
179
|
-
// set vertex attributes
|
|
180
|
-
let offset = 0;
|
|
181
|
-
const initVertexAttribArray = (name, type, typeSize, size)=>
|
|
182
|
-
{
|
|
183
|
-
const location = glContext.getAttribLocation(glShader, name);
|
|
184
|
-
const stride = typeSize && gl_INSTANCE_BYTE_STRIDE; // only if not geometry
|
|
185
|
-
const divisor = typeSize && 1; // only if not geometry
|
|
186
|
-
const normalize = typeSize === 1; // only if color
|
|
187
|
-
glContext.enableVertexAttribArray(location);
|
|
188
|
-
glContext.vertexAttribPointer(location, size, type, normalize, stride, offset);
|
|
189
|
-
glContext.vertexAttribDivisor(location, divisor);
|
|
190
|
-
offset += size*typeSize;
|
|
191
|
-
}
|
|
192
|
-
glContext.bindBuffer(glContext.ARRAY_BUFFER, glGeometryBuffer);
|
|
193
|
-
initVertexAttribArray('g', glContext.FLOAT, 0, 2); // geometry
|
|
194
|
-
glContext.bindBuffer(glContext.ARRAY_BUFFER, glArrayBuffer);
|
|
195
|
-
glContext.bufferData(glContext.ARRAY_BUFFER, gl_ARRAY_BUFFER_SIZE, glContext.DYNAMIC_DRAW);
|
|
196
|
-
initVertexAttribArray('p', glContext.FLOAT, 4, 4); // position & size
|
|
197
|
-
initVertexAttribArray('u', glContext.FLOAT, 4, 4); // texture coords
|
|
198
|
-
initVertexAttribArray('c', glContext.UNSIGNED_BYTE, 1, 4); // color
|
|
199
|
-
initVertexAttribArray('a', glContext.UNSIGNED_BYTE, 1, 4); // additiveColor
|
|
200
|
-
initVertexAttribArray('r', glContext.FLOAT, 4, 1); // rotation
|
|
216
|
+
glContext.bindVertexArray(glInstancedVAO);
|
|
201
217
|
}
|
|
202
218
|
|
|
203
219
|
function glSetPolyMode()
|
|
204
220
|
{
|
|
205
|
-
if (glPolyMode)
|
|
206
|
-
return;
|
|
221
|
+
if (glPolyMode) return;
|
|
207
222
|
|
|
208
223
|
// setup poly mode
|
|
209
224
|
glFlush();
|
|
210
225
|
glPolyMode = true;
|
|
211
226
|
glContext.useProgram(glPolyShader);
|
|
212
|
-
|
|
213
|
-
// set vertex attributes
|
|
214
|
-
let offset = 0;
|
|
215
|
-
const initVertexAttribArray = (name, type, typeSize, size)=>
|
|
216
|
-
{
|
|
217
|
-
const location = glContext.getAttribLocation(glPolyShader, name);
|
|
218
|
-
const normalize = typeSize === 1; // only normalize if color
|
|
219
|
-
const stride = gl_POLY_VERTEX_BYTE_STRIDE;
|
|
220
|
-
glContext.enableVertexAttribArray(location);
|
|
221
|
-
glContext.vertexAttribPointer(location, size, type, normalize, stride, offset);
|
|
222
|
-
glContext.vertexAttribDivisor(location, 0);
|
|
223
|
-
offset += size*typeSize;
|
|
224
|
-
}
|
|
225
|
-
glContext.bindBuffer(glContext.ARRAY_BUFFER, glArrayBuffer);
|
|
226
|
-
glContext.bufferData(glContext.ARRAY_BUFFER, gl_ARRAY_BUFFER_SIZE, glContext.DYNAMIC_DRAW);
|
|
227
|
-
initVertexAttribArray('p', glContext.FLOAT, 4, 2); // position
|
|
228
|
-
initVertexAttribArray('c', glContext.UNSIGNED_BYTE, 1, 4); // color
|
|
227
|
+
glContext.bindVertexArray(glPolyVAO);
|
|
229
228
|
}
|
|
230
229
|
|
|
231
230
|
// Setup WebGL render each frame, called automatically by engine
|
|
232
231
|
// Also used by tile layer rendering when redrawing tiles
|
|
233
|
-
function glPreRender()
|
|
232
|
+
function glPreRender(clear=true)
|
|
234
233
|
{
|
|
235
234
|
if (!glEnable || !glContext) return;
|
|
236
235
|
|
|
237
|
-
|
|
238
|
-
|
|
236
|
+
ASSERT(!glBatchCount, 'glPreRender called with unflushed batch.');
|
|
237
|
+
|
|
238
|
+
if (!glRenderTarget)
|
|
239
|
+
{
|
|
240
|
+
// set to same size as main canvas
|
|
241
|
+
glCanvas.width = mainCanvasSize.x;
|
|
242
|
+
glCanvas.height = mainCanvasSize.y;
|
|
243
|
+
}
|
|
244
|
+
glContext.viewport(0, 0, mainCanvasSize.x, mainCanvasSize.y);
|
|
245
|
+
clear && glClearCanvas();
|
|
239
246
|
|
|
240
247
|
// build the transform matrix
|
|
241
248
|
const s = vec2(2*cameraScale).divide(mainCanvasSize);
|
|
249
|
+
if (glRenderTarget)
|
|
250
|
+
s.y = -s.y; // invert y when using render target
|
|
242
251
|
const rotatedCam = cameraPos.rotate(-cameraAngle);
|
|
243
252
|
const p = vec2(-1).subtract(rotatedCam.multiply(s));
|
|
244
253
|
const ca = cos(cameraAngle);
|
|
@@ -267,12 +276,14 @@ function glPreRender()
|
|
|
267
276
|
glContext.bindTexture(glContext.TEXTURE_2D, glActiveTexture);
|
|
268
277
|
}
|
|
269
278
|
|
|
279
|
+
// rebind the array buffer
|
|
280
|
+
glContext.bindBuffer(glContext.ARRAY_BUFFER, glArrayBuffer);
|
|
281
|
+
|
|
270
282
|
// start with additive blending off
|
|
271
283
|
glAdditive = glBatchAdditive = false;
|
|
272
284
|
|
|
273
|
-
// force it to set instanced mode
|
|
274
|
-
|
|
275
|
-
glSetInstancedMode();
|
|
285
|
+
// force it to set instanced mode
|
|
286
|
+
glSetInstancedMode(true);
|
|
276
287
|
}
|
|
277
288
|
|
|
278
289
|
/** Clear the canvas and setup the viewport
|
|
@@ -281,13 +292,9 @@ function glClearCanvas()
|
|
|
281
292
|
{
|
|
282
293
|
if (!glContext) return;
|
|
283
294
|
|
|
284
|
-
// clear
|
|
285
|
-
glCanvas.width = drawCanvas.width;
|
|
286
|
-
glCanvas.height = drawCanvas.height;
|
|
287
|
-
glContext.viewport(0, 0, glCanvas.width, glCanvas.height);
|
|
295
|
+
// clear using the canvasClearColor
|
|
288
296
|
const color = canvasClearColor;
|
|
289
|
-
|
|
290
|
-
glContext.clearColor(color.r, color.g, color.b, color.a);
|
|
297
|
+
glContext.clearColor(color.r, color.g, color.b, color.a);
|
|
291
298
|
glContext.clear(glContext.COLOR_BUFFER_BIT);
|
|
292
299
|
}
|
|
293
300
|
|
|
@@ -299,8 +306,7 @@ function glClearCanvas()
|
|
|
299
306
|
function glSetTexture(texture, wrap=false)
|
|
300
307
|
{
|
|
301
308
|
// must flush cache with the old texture to set a new one
|
|
302
|
-
if (!glContext || texture === glActiveTexture)
|
|
303
|
-
return;
|
|
309
|
+
if (!glContext || texture === glActiveTexture) return;
|
|
304
310
|
|
|
305
311
|
glFlush();
|
|
306
312
|
glActiveTexture = texture;
|
|
@@ -365,7 +371,7 @@ function glCreateTexture(image)
|
|
|
365
371
|
// build the texture
|
|
366
372
|
const texture = glContext.createTexture();
|
|
367
373
|
let mipMap = false;
|
|
368
|
-
if (image
|
|
374
|
+
if (image?.width)
|
|
369
375
|
{
|
|
370
376
|
glSetTextureData(texture, image);
|
|
371
377
|
glContext.bindTexture(glContext.TEXTURE_2D, texture);
|
|
@@ -386,7 +392,9 @@ function glCreateTexture(image)
|
|
|
386
392
|
glContext.texParameteri(glContext.TEXTURE_2D, glContext.TEXTURE_MIN_FILTER, minFilter);
|
|
387
393
|
if (mipMap)
|
|
388
394
|
glContext.generateMipmap(glContext.TEXTURE_2D);
|
|
389
|
-
|
|
395
|
+
|
|
396
|
+
// rebind active texture
|
|
397
|
+
glContext.bindTexture(glContext.TEXTURE_2D, glActiveTexture);
|
|
390
398
|
return texture;
|
|
391
399
|
}
|
|
392
400
|
|
|
@@ -396,6 +404,7 @@ function glCreateTexture(image)
|
|
|
396
404
|
function glDeleteTexture(texture)
|
|
397
405
|
{
|
|
398
406
|
if (!glContext) return;
|
|
407
|
+
|
|
399
408
|
glContext.deleteTexture(texture);
|
|
400
409
|
}
|
|
401
410
|
|
|
@@ -408,10 +417,12 @@ function glSetTextureData(texture, image)
|
|
|
408
417
|
if (!glContext) return;
|
|
409
418
|
|
|
410
419
|
// build the texture
|
|
411
|
-
ASSERT(
|
|
420
|
+
ASSERT(image?.width > 0, 'Invalid image data.');
|
|
412
421
|
glContext.bindTexture(glContext.TEXTURE_2D, texture);
|
|
413
422
|
glContext.texImage2D(glContext.TEXTURE_2D, 0, glContext.RGBA, glContext.RGBA, glContext.UNSIGNED_BYTE, image);
|
|
414
|
-
|
|
423
|
+
|
|
424
|
+
// rebind active texture
|
|
425
|
+
glContext.bindTexture(glContext.TEXTURE_2D, glActiveTexture);
|
|
415
426
|
}
|
|
416
427
|
|
|
417
428
|
/** Tells WebGL to create or update the glTexture and start tracking it
|
|
@@ -480,8 +491,7 @@ function glFlush()
|
|
|
480
491
|
* @memberof WebGL */
|
|
481
492
|
function glCopyToContext(context)
|
|
482
493
|
{
|
|
483
|
-
if (!glEnable || !glContext)
|
|
484
|
-
return;
|
|
494
|
+
if (!glEnable || !glContext) return;
|
|
485
495
|
|
|
486
496
|
glFlush();
|
|
487
497
|
context.drawImage(glCanvas, 0, 0);
|
|
@@ -631,6 +641,48 @@ function glDrawColoredPoints(points, pointColors)
|
|
|
631
641
|
glBatchCount += vertCount;
|
|
632
642
|
}
|
|
633
643
|
|
|
644
|
+
/** Set the WebGL render target to the given texture or back to the canvas
|
|
645
|
+
* @param {WebGLTexture} [texture] - a texture or undefined to use normal glCanvas
|
|
646
|
+
* @param {boolean} [clear] - should the render target be cleared
|
|
647
|
+
* @memberof WebGL */
|
|
648
|
+
function glSetRenderTarget(texture, clear=false)
|
|
649
|
+
{
|
|
650
|
+
if (texture)
|
|
651
|
+
{
|
|
652
|
+
glRenderTarget = texture;
|
|
653
|
+
glContext.bindFramebuffer(glContext.FRAMEBUFFER, glFramebuffer);
|
|
654
|
+
glContext.framebufferTexture2D(glContext.FRAMEBUFFER,
|
|
655
|
+
glContext.COLOR_ATTACHMENT0, glContext.TEXTURE_2D, texture, 0);
|
|
656
|
+
glPreRender(clear);
|
|
657
|
+
}
|
|
658
|
+
else
|
|
659
|
+
{
|
|
660
|
+
glFlush();
|
|
661
|
+
glRenderTarget = undefined;
|
|
662
|
+
glContext.bindFramebuffer(glContext.FRAMEBUFFER, null);
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
/** Clear out a rectangle area of the WebGL canvas or render target
|
|
667
|
+
* @param {number} x
|
|
668
|
+
* @param {number} y
|
|
669
|
+
* @param {number} width
|
|
670
|
+
* @param {number} height
|
|
671
|
+
* @memberof WebGL */
|
|
672
|
+
function glClearRect(x, y, width, height)
|
|
673
|
+
{
|
|
674
|
+
if (!glEnable) return;
|
|
675
|
+
|
|
676
|
+
// Enable scissor test to clear only the specified area
|
|
677
|
+
glContext.enable(glContext.SCISSOR_TEST);
|
|
678
|
+
glContext.scissor(x, y, width, height);
|
|
679
|
+
glContext.clearColor(0, 0, 0, 0);
|
|
680
|
+
glContext.clear(glContext.COLOR_BUFFER_BIT);
|
|
681
|
+
glContext.disable(glContext.SCISSOR_TEST);
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
685
|
+
|
|
634
686
|
// WebGL internal function to convert polygon to outline triangle strip
|
|
635
687
|
function glMakeOutline(points, width, wrap=true)
|
|
636
688
|
{
|
|
@@ -764,23 +816,20 @@ function glPolyStrip(points)
|
|
|
764
816
|
const a = points[i0], b = points[i1], c = points[i2];
|
|
765
817
|
|
|
766
818
|
// check if convex
|
|
767
|
-
if (cross(a, b, c) < e)
|
|
768
|
-
continue;
|
|
819
|
+
if (cross(a, b, c) < e) continue;
|
|
769
820
|
|
|
770
821
|
// check if any other point is inside
|
|
771
822
|
let hasInside = false;
|
|
772
823
|
for (let j = 0; j < indices.length; j++)
|
|
773
824
|
{
|
|
774
825
|
const k = indices[j];
|
|
775
|
-
if (k === i0 || k === i1 || k === i2)
|
|
776
|
-
|
|
826
|
+
if (k === i0 || k === i1 || k === i2) continue;
|
|
827
|
+
|
|
777
828
|
const p = points[k];
|
|
778
829
|
hasInside = pointInTriangle(p, a, b, c);
|
|
779
|
-
if (hasInside)
|
|
780
|
-
break;
|
|
830
|
+
if (hasInside) break;
|
|
781
831
|
}
|
|
782
|
-
if (hasInside)
|
|
783
|
-
continue;
|
|
832
|
+
if (hasInside) continue;
|
|
784
833
|
|
|
785
834
|
// found valid ear
|
|
786
835
|
triangles.push([i0, i1, i2]);
|
|
@@ -805,8 +854,7 @@ function glPolyStrip(points)
|
|
|
805
854
|
worstIndex = i;
|
|
806
855
|
}
|
|
807
856
|
}
|
|
808
|
-
if (worstIndex < 0)
|
|
809
|
-
break;
|
|
857
|
+
if (worstIndex < 0) break;
|
|
810
858
|
|
|
811
859
|
const i0 = indices[(worstIndex + indices.length - 1) % indices.length];
|
|
812
860
|
const i1 = indices[worstIndex];
|