littlejsengine 1.16.2 → 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 +200 -166
- package/dist/littlejs.esm.js +1231 -1086
- package/dist/littlejs.esm.min.js +1 -1
- package/dist/littlejs.js +888 -735
- package/dist/littlejs.min.js +1 -1
- package/dist/littlejs.release.js +884 -731
- package/examples/box2d/gameObjects.js +1 -1
- 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/module/tiles.png +0 -0
- package/examples/platformer/gameEffects.js +23 -22
- package/examples/platformer/gameLevel.js +24 -25
- package/examples/shorts/base.html +1 -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 +2 -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 +15 -15
- package/reference.md +1 -1
- package/src/engine.js +174 -174
- package/src/engineAudio.js +4 -6
- package/src/engineDebug.js +4 -4
- package/src/engineDraw.js +179 -122
- package/src/engineExport.js +326 -334
- package/src/engineFont.png +0 -0
- package/src/engineInput.js +14 -20
- package/src/engineMath.js +15 -104
- package/src/engineObject.js +26 -25
- package/src/engineParticles.js +2 -2
- package/src/engineTileLayer.js +196 -170
- package/src/engineUtilities.js +100 -4
- package/src/engineWebGL.js +123 -72
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,45 +158,62 @@ 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) return;
|
|
210
|
+
if (!force && !glPolyMode) return;
|
|
172
211
|
|
|
173
212
|
// setup instanced mode
|
|
174
213
|
glFlush();
|
|
175
214
|
glPolyMode = false;
|
|
176
215
|
glContext.useProgram(glShader);
|
|
177
|
-
|
|
178
|
-
// set vertex attributes
|
|
179
|
-
let offset = 0;
|
|
180
|
-
const initVertexAttribArray = (name, type, typeSize, size)=>
|
|
181
|
-
{
|
|
182
|
-
const location = glContext.getAttribLocation(glShader, name);
|
|
183
|
-
const stride = typeSize && gl_INSTANCE_BYTE_STRIDE; // only if not geometry
|
|
184
|
-
const divisor = typeSize && 1; // only if not geometry
|
|
185
|
-
const normalize = typeSize === 1; // only if color
|
|
186
|
-
glContext.enableVertexAttribArray(location);
|
|
187
|
-
glContext.vertexAttribPointer(location, size, type, normalize, stride, offset);
|
|
188
|
-
glContext.vertexAttribDivisor(location, divisor);
|
|
189
|
-
offset += size*typeSize;
|
|
190
|
-
}
|
|
191
|
-
glContext.bindBuffer(glContext.ARRAY_BUFFER, glGeometryBuffer);
|
|
192
|
-
initVertexAttribArray('g', glContext.FLOAT, 0, 2); // geometry
|
|
193
|
-
glContext.bindBuffer(glContext.ARRAY_BUFFER, glArrayBuffer);
|
|
194
|
-
glContext.bufferData(glContext.ARRAY_BUFFER, gl_ARRAY_BUFFER_SIZE, glContext.DYNAMIC_DRAW);
|
|
195
|
-
initVertexAttribArray('p', glContext.FLOAT, 4, 4); // position & size
|
|
196
|
-
initVertexAttribArray('u', glContext.FLOAT, 4, 4); // texture coords
|
|
197
|
-
initVertexAttribArray('c', glContext.UNSIGNED_BYTE, 1, 4); // color
|
|
198
|
-
initVertexAttribArray('a', glContext.UNSIGNED_BYTE, 1, 4); // additiveColor
|
|
199
|
-
initVertexAttribArray('r', glContext.FLOAT, 4, 1); // rotation
|
|
216
|
+
glContext.bindVertexArray(glInstancedVAO);
|
|
200
217
|
}
|
|
201
218
|
|
|
202
219
|
function glSetPolyMode()
|
|
@@ -207,36 +224,30 @@ function glSetPolyMode()
|
|
|
207
224
|
glFlush();
|
|
208
225
|
glPolyMode = true;
|
|
209
226
|
glContext.useProgram(glPolyShader);
|
|
210
|
-
|
|
211
|
-
// set vertex attributes
|
|
212
|
-
let offset = 0;
|
|
213
|
-
const initVertexAttribArray = (name, type, typeSize, size)=>
|
|
214
|
-
{
|
|
215
|
-
const location = glContext.getAttribLocation(glPolyShader, name);
|
|
216
|
-
const normalize = typeSize === 1; // only normalize if color
|
|
217
|
-
const stride = gl_POLY_VERTEX_BYTE_STRIDE;
|
|
218
|
-
glContext.enableVertexAttribArray(location);
|
|
219
|
-
glContext.vertexAttribPointer(location, size, type, normalize, stride, offset);
|
|
220
|
-
glContext.vertexAttribDivisor(location, 0);
|
|
221
|
-
offset += size*typeSize;
|
|
222
|
-
}
|
|
223
|
-
glContext.bindBuffer(glContext.ARRAY_BUFFER, glArrayBuffer);
|
|
224
|
-
glContext.bufferData(glContext.ARRAY_BUFFER, gl_ARRAY_BUFFER_SIZE, glContext.DYNAMIC_DRAW);
|
|
225
|
-
initVertexAttribArray('p', glContext.FLOAT, 4, 2); // position
|
|
226
|
-
initVertexAttribArray('c', glContext.UNSIGNED_BYTE, 1, 4); // color
|
|
227
|
+
glContext.bindVertexArray(glPolyVAO);
|
|
227
228
|
}
|
|
228
229
|
|
|
229
230
|
// Setup WebGL render each frame, called automatically by engine
|
|
230
231
|
// Also used by tile layer rendering when redrawing tiles
|
|
231
|
-
function glPreRender()
|
|
232
|
+
function glPreRender(clear=true)
|
|
232
233
|
{
|
|
233
234
|
if (!glEnable || !glContext) return;
|
|
234
235
|
|
|
235
|
-
|
|
236
|
-
|
|
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();
|
|
237
246
|
|
|
238
247
|
// build the transform matrix
|
|
239
248
|
const s = vec2(2*cameraScale).divide(mainCanvasSize);
|
|
249
|
+
if (glRenderTarget)
|
|
250
|
+
s.y = -s.y; // invert y when using render target
|
|
240
251
|
const rotatedCam = cameraPos.rotate(-cameraAngle);
|
|
241
252
|
const p = vec2(-1).subtract(rotatedCam.multiply(s));
|
|
242
253
|
const ca = cos(cameraAngle);
|
|
@@ -265,12 +276,14 @@ function glPreRender()
|
|
|
265
276
|
glContext.bindTexture(glContext.TEXTURE_2D, glActiveTexture);
|
|
266
277
|
}
|
|
267
278
|
|
|
279
|
+
// rebind the array buffer
|
|
280
|
+
glContext.bindBuffer(glContext.ARRAY_BUFFER, glArrayBuffer);
|
|
281
|
+
|
|
268
282
|
// start with additive blending off
|
|
269
283
|
glAdditive = glBatchAdditive = false;
|
|
270
284
|
|
|
271
|
-
// force it to set instanced mode
|
|
272
|
-
|
|
273
|
-
glSetInstancedMode();
|
|
285
|
+
// force it to set instanced mode
|
|
286
|
+
glSetInstancedMode(true);
|
|
274
287
|
}
|
|
275
288
|
|
|
276
289
|
/** Clear the canvas and setup the viewport
|
|
@@ -279,13 +292,9 @@ function glClearCanvas()
|
|
|
279
292
|
{
|
|
280
293
|
if (!glContext) return;
|
|
281
294
|
|
|
282
|
-
// clear
|
|
283
|
-
glCanvas.width = mainCanvasSize.x;
|
|
284
|
-
glCanvas.height = mainCanvasSize.y;
|
|
285
|
-
glContext.viewport(0, 0, glCanvas.width, glCanvas.height);
|
|
295
|
+
// clear using the canvasClearColor
|
|
286
296
|
const color = canvasClearColor;
|
|
287
|
-
|
|
288
|
-
glContext.clearColor(color.r, color.g, color.b, color.a);
|
|
297
|
+
glContext.clearColor(color.r, color.g, color.b, color.a);
|
|
289
298
|
glContext.clear(glContext.COLOR_BUFFER_BIT);
|
|
290
299
|
}
|
|
291
300
|
|
|
@@ -362,7 +371,7 @@ function glCreateTexture(image)
|
|
|
362
371
|
// build the texture
|
|
363
372
|
const texture = glContext.createTexture();
|
|
364
373
|
let mipMap = false;
|
|
365
|
-
if (image
|
|
374
|
+
if (image?.width)
|
|
366
375
|
{
|
|
367
376
|
glSetTextureData(texture, image);
|
|
368
377
|
glContext.bindTexture(glContext.TEXTURE_2D, texture);
|
|
@@ -383,7 +392,9 @@ function glCreateTexture(image)
|
|
|
383
392
|
glContext.texParameteri(glContext.TEXTURE_2D, glContext.TEXTURE_MIN_FILTER, minFilter);
|
|
384
393
|
if (mipMap)
|
|
385
394
|
glContext.generateMipmap(glContext.TEXTURE_2D);
|
|
386
|
-
|
|
395
|
+
|
|
396
|
+
// rebind active texture
|
|
397
|
+
glContext.bindTexture(glContext.TEXTURE_2D, glActiveTexture);
|
|
387
398
|
return texture;
|
|
388
399
|
}
|
|
389
400
|
|
|
@@ -406,10 +417,12 @@ function glSetTextureData(texture, image)
|
|
|
406
417
|
if (!glContext) return;
|
|
407
418
|
|
|
408
419
|
// build the texture
|
|
409
|
-
ASSERT(
|
|
420
|
+
ASSERT(image?.width > 0, 'Invalid image data.');
|
|
410
421
|
glContext.bindTexture(glContext.TEXTURE_2D, texture);
|
|
411
422
|
glContext.texImage2D(glContext.TEXTURE_2D, 0, glContext.RGBA, glContext.RGBA, glContext.UNSIGNED_BYTE, image);
|
|
412
|
-
|
|
423
|
+
|
|
424
|
+
// rebind active texture
|
|
425
|
+
glContext.bindTexture(glContext.TEXTURE_2D, glActiveTexture);
|
|
413
426
|
}
|
|
414
427
|
|
|
415
428
|
/** Tells WebGL to create or update the glTexture and start tracking it
|
|
@@ -628,6 +641,48 @@ function glDrawColoredPoints(points, pointColors)
|
|
|
628
641
|
glBatchCount += vertCount;
|
|
629
642
|
}
|
|
630
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
|
+
|
|
631
686
|
// WebGL internal function to convert polygon to outline triangle strip
|
|
632
687
|
function glMakeOutline(points, width, wrap=true)
|
|
633
688
|
{
|
|
@@ -761,23 +816,20 @@ function glPolyStrip(points)
|
|
|
761
816
|
const a = points[i0], b = points[i1], c = points[i2];
|
|
762
817
|
|
|
763
818
|
// check if convex
|
|
764
|
-
if (cross(a, b, c) < e)
|
|
765
|
-
continue;
|
|
819
|
+
if (cross(a, b, c) < e) continue;
|
|
766
820
|
|
|
767
821
|
// check if any other point is inside
|
|
768
822
|
let hasInside = false;
|
|
769
823
|
for (let j = 0; j < indices.length; j++)
|
|
770
824
|
{
|
|
771
825
|
const k = indices[j];
|
|
772
|
-
if (k === i0 || k === i1 || k === i2)
|
|
773
|
-
|
|
826
|
+
if (k === i0 || k === i1 || k === i2) continue;
|
|
827
|
+
|
|
774
828
|
const p = points[k];
|
|
775
829
|
hasInside = pointInTriangle(p, a, b, c);
|
|
776
|
-
if (hasInside)
|
|
777
|
-
break;
|
|
830
|
+
if (hasInside) break;
|
|
778
831
|
}
|
|
779
|
-
if (hasInside)
|
|
780
|
-
continue;
|
|
832
|
+
if (hasInside) continue;
|
|
781
833
|
|
|
782
834
|
// found valid ear
|
|
783
835
|
triangles.push([i0, i1, i2]);
|
|
@@ -802,8 +854,7 @@ function glPolyStrip(points)
|
|
|
802
854
|
worstIndex = i;
|
|
803
855
|
}
|
|
804
856
|
}
|
|
805
|
-
if (worstIndex < 0)
|
|
806
|
-
break;
|
|
857
|
+
if (worstIndex < 0) break;
|
|
807
858
|
|
|
808
859
|
const i0 = indices[(worstIndex + indices.length - 1) % indices.length];
|
|
809
860
|
const i1 = indices[worstIndex];
|