littlejsengine 1.21.0 → 1.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/littlejs.d.ts +1258 -141
- package/dist/littlejs.esm.js +5023 -429
- package/dist/littlejs.esm.min.js +22 -9
- package/dist/littlejs.js +4977 -430
- package/dist/littlejs.min.js +21 -8
- package/dist/littlejs.release.js +2759 -313
- package/package.json +3 -2
- package/plugins/gltf.js +7 -1
- package/plugins/lightSystem.js +50 -5
- package/plugins/math3d.js +42 -20
- package/plugins/parallax.js +174 -0
- package/plugins/particleEffects.js +760 -0
- package/plugins/pluginExport.js +40 -0
- package/plugins/postProcess.js +206 -28
- package/plugins/render3d.js +495 -188
- package/plugins/render3dEditor.js +1754 -80
- package/plugins/render3dExtras.js +294 -21
- package/plugins/render3dLevel.js +463 -6
- package/plugins/sceneSystem.js +3 -2
- package/src/engine.js +1 -1
- package/src/engineAudio.js +25 -8
- package/src/engineBuild.mjs +2 -0
- package/src/engineDraw.js +59 -4
- package/src/engineEditor.js +475 -37
- package/src/engineExport.js +7 -0
- package/src/engineInput.js +48 -6
- package/src/engineParticles.js +80 -11
- package/src/engineRelease.js +13 -2
- package/src/engineSettings.js +14 -0
- package/src/engineWebGL.js +27 -10
package/plugins/pluginExport.js
CHANGED
|
@@ -29,6 +29,15 @@ export
|
|
|
29
29
|
PostProcessPlugin,
|
|
30
30
|
postProcessBloom,
|
|
31
31
|
postProcessBloomShader,
|
|
32
|
+
postProcessEffects,
|
|
33
|
+
postProcessGlow,
|
|
34
|
+
postProcessScanlines,
|
|
35
|
+
postProcessNoise,
|
|
36
|
+
postProcessVignette,
|
|
37
|
+
postProcessCurve,
|
|
38
|
+
postProcessChromatic,
|
|
39
|
+
postProcessOutline,
|
|
40
|
+
postProcessTV,
|
|
32
41
|
|
|
33
42
|
// Light System
|
|
34
43
|
lightSystem,
|
|
@@ -107,6 +116,10 @@ export
|
|
|
107
116
|
setScene,
|
|
108
117
|
getScene,
|
|
109
118
|
|
|
119
|
+
// Parallax
|
|
120
|
+
ParallaxLayer,
|
|
121
|
+
parallaxMountains,
|
|
122
|
+
|
|
110
123
|
// Path Finding
|
|
111
124
|
PathFinder,
|
|
112
125
|
PathFinderNode,
|
|
@@ -166,6 +179,7 @@ export
|
|
|
166
179
|
FirstPersonCamera3D,
|
|
167
180
|
ParticleEmitter3D,
|
|
168
181
|
Trail3D,
|
|
182
|
+
LensFlare3D,
|
|
169
183
|
engineObjectsCollect3D,
|
|
170
184
|
engineObjectsCallback3D,
|
|
171
185
|
engineObjectsRaycast3D,
|
|
@@ -186,6 +200,11 @@ export
|
|
|
186
200
|
level3DAddType,
|
|
187
201
|
level3DAddMesh,
|
|
188
202
|
level3DLoad,
|
|
203
|
+
level3DAddPrefab,
|
|
204
|
+
level3DLoadPrefab,
|
|
205
|
+
level3DSpawn,
|
|
206
|
+
Prefab3D,
|
|
207
|
+
level3DVoxelSetup,
|
|
189
208
|
|
|
190
209
|
// Three.js
|
|
191
210
|
threeJS,
|
|
@@ -203,4 +222,25 @@ export
|
|
|
203
222
|
loadAtlas,
|
|
204
223
|
parseAtlas,
|
|
205
224
|
spritesReady,
|
|
225
|
+
|
|
226
|
+
// Particle Effects
|
|
227
|
+
particleEffectGroups,
|
|
228
|
+
particleEffectSettings,
|
|
229
|
+
particleEffectBehaviors,
|
|
230
|
+
particleEffectShapes,
|
|
231
|
+
particleEffectSanitize,
|
|
232
|
+
particleEffectRecolor,
|
|
233
|
+
particleEffectsAdd,
|
|
234
|
+
particleEffectsGet,
|
|
235
|
+
particleEffectsParse,
|
|
236
|
+
particleEffectsText,
|
|
237
|
+
particleEffectsLoad,
|
|
238
|
+
particleEffectShapeTile,
|
|
239
|
+
particleEffect,
|
|
240
|
+
particleEffect3D,
|
|
241
|
+
particleEffectsBuiltIn,
|
|
242
|
+
particleEffectApply,
|
|
243
|
+
particleEffectApply3D,
|
|
244
|
+
particleEffectFromEmitter,
|
|
245
|
+
particleEffectsAddBehavior,
|
|
206
246
|
}
|
package/plugins/postProcess.js
CHANGED
|
@@ -46,8 +46,8 @@ class PostProcessPlugin
|
|
|
46
46
|
ASSERT(!(includeMainCanvas && feedbackTexture), 'Post process cannot both include main canvas and use feedback texture');
|
|
47
47
|
postProcess = this;
|
|
48
48
|
|
|
49
|
-
|
|
50
|
-
|
|
49
|
+
/** @property {string} - The shadertoy style mainImage code it shades with, see setShaderCode */
|
|
50
|
+
this.shaderCode = shaderCode || postProcessEffects(); // no code passes the frame through
|
|
51
51
|
|
|
52
52
|
/** @property {WebGLProgram|undefined} - Shader for post processing
|
|
53
53
|
* @type {WebGLProgram|undefined} */
|
|
@@ -93,7 +93,7 @@ class PostProcessPlugin
|
|
|
93
93
|
'gl_Position=vec4(p+p-1.,1,1);'+ // set position
|
|
94
94
|
'}' // end of shader
|
|
95
95
|
,
|
|
96
|
-
postProcessFragmentSource(shaderCode)
|
|
96
|
+
postProcessFragmentSource(postProcess.shaderCode)
|
|
97
97
|
);
|
|
98
98
|
|
|
99
99
|
// setup VAO for post processing
|
|
@@ -106,6 +106,10 @@ class PostProcessPlugin
|
|
|
106
106
|
const pLocation = glContext.getAttribLocation(postProcess.shader, 'p');
|
|
107
107
|
glContext.enableVertexAttribArray(pLocation);
|
|
108
108
|
glContext.vertexAttribPointer(pLocation, 2, glContext.FLOAT, false, vertexByteStride, 0);
|
|
109
|
+
|
|
110
|
+
// the engine's own vertex array and buffer back, its next batch is written into the buffer bound
|
|
111
|
+
glContext.bindVertexArray(glPolyMode ? glPolyVAO : glInstancedVAO);
|
|
112
|
+
glContext.bindBuffer(glContext.ARRAY_BUFFER, glArrayBuffer);
|
|
109
113
|
}
|
|
110
114
|
function postProcessContextLost()
|
|
111
115
|
{
|
|
@@ -123,16 +127,17 @@ class PostProcessPlugin
|
|
|
123
127
|
{
|
|
124
128
|
if (headlessMode || !glEnable) return;
|
|
125
129
|
|
|
126
|
-
//
|
|
130
|
+
// clear out the buffer, before anything here binds its own
|
|
131
|
+
glFlush();
|
|
132
|
+
|
|
133
|
+
// made now if WebGL was off when the plugin was made, when a lost context came back, or when
|
|
134
|
+
// setShaderCode gave it new code
|
|
127
135
|
if (!postProcess.shader)
|
|
128
136
|
{
|
|
129
137
|
if (glContext.isContextLost()) return;
|
|
130
138
|
initPostProcess();
|
|
131
139
|
}
|
|
132
140
|
|
|
133
|
-
// clear out the buffer
|
|
134
|
-
glFlush();
|
|
135
|
-
|
|
136
141
|
// ensure we render to the default framebuffer (in case any earlier
|
|
137
142
|
// caller this frame left a render target bound)
|
|
138
143
|
glContext.bindFramebuffer(glContext.FRAMEBUFFER, null);
|
|
@@ -201,7 +206,9 @@ class PostProcessPlugin
|
|
|
201
206
|
|
|
202
207
|
if (feedbackTexture)
|
|
203
208
|
{
|
|
204
|
-
// keep this frame's output for the next one,
|
|
209
|
+
// keep this frame's output for the next one, in the feedback texture still bound to the second
|
|
210
|
+
// unit, then hand the first texture unit back to the engine
|
|
211
|
+
glContext.activeTexture(glContext.TEXTURE1);
|
|
205
212
|
glContext.texImage2D(glContext.TEXTURE_2D, 0, glContext.RGBA, glContext.RGBA, glContext.UNSIGNED_BYTE, glCanvas);
|
|
206
213
|
glContext.activeTexture(glContext.TEXTURE0);
|
|
207
214
|
}
|
|
@@ -223,6 +230,23 @@ class PostProcessPlugin
|
|
|
223
230
|
glSetInstancedMode(true);
|
|
224
231
|
}
|
|
225
232
|
}
|
|
233
|
+
|
|
234
|
+
/** Shade with new code from the next frame on, to switch effects while the game runs; the shader is made again
|
|
235
|
+
* @param {string} [shaderCode] - Shadertoy style mainImage code, postProcessEffects builds it; none passes the
|
|
236
|
+
* frame through */
|
|
237
|
+
setShaderCode(shaderCode)
|
|
238
|
+
{
|
|
239
|
+
ASSERT(!shaderCode || typeof shaderCode === 'string', 'shader code must be a string');
|
|
240
|
+
this.shaderCode = shaderCode || postProcessEffects();
|
|
241
|
+
if (!this.shader || headlessMode || !glContext) return;
|
|
242
|
+
|
|
243
|
+
// what the new shader replaces, made again by the next render
|
|
244
|
+
glContext.deleteProgram(this.shader);
|
|
245
|
+
glContext.deleteTexture(this.texture);
|
|
246
|
+
this.feedbackTexture && glContext.deleteTexture(this.feedbackTexture);
|
|
247
|
+
glContext.deleteVertexArray(this.vao);
|
|
248
|
+
this.shader = this.texture = this.feedbackTexture = this.vao = undefined;
|
|
249
|
+
}
|
|
226
250
|
}
|
|
227
251
|
|
|
228
252
|
///////////////////////////////////////////////////////////////////////////////
|
|
@@ -263,9 +287,66 @@ function postProcessFragmentSource(shaderCode)
|
|
|
263
287
|
*/
|
|
264
288
|
function postProcessBloomShader(threshold=.6, strength=1, size=6)
|
|
265
289
|
{
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
290
|
+
return postProcessEffects(postProcessGlow(threshold, strength, size));
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Set up post processing with a bloom effect, so bright colors and lights glow
|
|
295
|
+
* @param {number} [threshold] - Brightness where the glow starts, 0 is everything and 1 is only pure white
|
|
296
|
+
* @param {number} [strength] - How much glow to add
|
|
297
|
+
* @param {number} [size] - How far the glow spreads in pixels
|
|
298
|
+
* @param {boolean} [includeMainCanvas] - Glow the 2D canvas too, off by default so HUD text stays crisp
|
|
299
|
+
* (a HUD drawn with WebGL in gameRenderPost glows either way, draw it with useWebGL=false)
|
|
300
|
+
* @return {PostProcessPlugin}
|
|
301
|
+
* @memberof PostProcess
|
|
302
|
+
* @example
|
|
303
|
+
* postProcessBloom(); // in gameInit, after any Render3DPlugin
|
|
304
|
+
*/
|
|
305
|
+
function postProcessBloom(threshold=.6, strength=1, size=6, includeMainCanvas=false)
|
|
306
|
+
{ return new PostProcessPlugin(postProcessBloomShader(threshold, strength, size), includeMainCanvas); }
|
|
307
|
+
|
|
308
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
309
|
+
// Effects: pieces of shader code, each with its settings written in as numbers, that postProcessEffects joins in
|
|
310
|
+
// order into one shader; a piece works on c, the pixel's color, and uv, where it is on the screen from 0 to 1, with p
|
|
311
|
+
// its pixel; one that bends uv or samples the frame, the curve, chromatic and glow, goes before the ones that shade
|
|
312
|
+
|
|
313
|
+
// a number as GLSL writes it, a float with a point
|
|
314
|
+
const postProcessNumber = (n)=> (ASSERT(isNumber(n), 'effect settings must be numbers', n), n.toFixed(4));
|
|
315
|
+
|
|
316
|
+
/**
|
|
317
|
+
* Join effects into one post process shader, in the order given, for PostProcessPlugin or setShaderCode
|
|
318
|
+
* - Each effect is a piece of shader code on c, the pixel's color, and uv, where it is on the screen from 0 to 1;
|
|
319
|
+
* your own code is a piece too, a line of GLSL or many, dropped in where you put it
|
|
320
|
+
* - Put the ones that bend the picture or sample it first: postProcessCurve, postProcessChromatic, postProcessGlow
|
|
321
|
+
* @param {...string} effects - The pieces, from the effect functions or your own code
|
|
322
|
+
* @return {string} - Shadertoy style mainImage code
|
|
323
|
+
* @example
|
|
324
|
+
* new PostProcessPlugin(postProcessEffects(
|
|
325
|
+
* postProcessScanlines(.5), postProcessVignette(), 'c.rgb *= vec3(1, .9, .8);'));
|
|
326
|
+
* @memberof PostProcess
|
|
327
|
+
*/
|
|
328
|
+
function postProcessEffects(...effects)
|
|
329
|
+
{
|
|
330
|
+
ASSERT(effects.every((e)=> typeof e === 'string'), 'each effect is a piece of shader code, a string');
|
|
331
|
+
return 'void mainImage(out vec4 c, vec2 p)\n{\n' +
|
|
332
|
+
' vec2 uv = p / iResolution.xy;\n' +
|
|
333
|
+
' c = texture(iChannel0, uv);\n' +
|
|
334
|
+
effects.map((e)=> ' {\n' + e + '\n }\n').join('') + '}\n';
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* Bright parts glow, the bloom as an effect to join with others; postProcessBloom sets up bloom on its own
|
|
339
|
+
* @param {number} [threshold] - Brightness where the glow starts, 0 is everything and 1 is only pure white
|
|
340
|
+
* @param {number} [strength] - How much glow to add
|
|
341
|
+
* @param {number} [size] - How far the glow spreads in pixels, which also sets how many samples it takes
|
|
342
|
+
* @return {string}
|
|
343
|
+
* @memberof PostProcess
|
|
344
|
+
*/
|
|
345
|
+
function postProcessGlow(threshold=.6, strength=1, size=6)
|
|
346
|
+
{
|
|
347
|
+
ASSERT(isNumber(threshold) && isNumber(strength) && isNumber(size), 'glow settings must be numbers');
|
|
348
|
+
ASSERT(size > 0, 'glow size must be above zero');
|
|
349
|
+
ASSERT(size <= 32, 'a glow this wide takes a sample every few pixels of every ring, which is hundreds of samples a pixel', size);
|
|
269
350
|
|
|
270
351
|
// Taps on three rings over a disc of the given size, one every three pixels or so of each ring
|
|
271
352
|
// so there is no gap wide enough to show. The count follows the ring all the way out: hold it
|
|
@@ -287,27 +368,124 @@ function postProcessBloomShader(threshold=.6, strength=1, size=6)
|
|
|
287
368
|
glow += max(vec3(0), texture(iChannel0, uv + vec2(cos(a), sin(a)) * ${radius.toFixed(4)} / iResolution.xy).rgb - ${threshold.toFixed(4)});
|
|
288
369
|
}`;
|
|
289
370
|
}
|
|
290
|
-
return `
|
|
291
|
-
void mainImage(out vec4 color, vec2 pixel)
|
|
292
|
-
{
|
|
293
|
-
vec2 uv = pixel / iResolution.xy;
|
|
294
|
-
color = texture(iChannel0, uv);
|
|
371
|
+
return ` // glow
|
|
295
372
|
vec3 glow = vec3(0);${code}
|
|
296
|
-
|
|
297
|
-
}`;
|
|
373
|
+
c.rgb += glow * ${(strength / taps).toFixed(6)};`;
|
|
298
374
|
}
|
|
299
375
|
|
|
300
376
|
/**
|
|
301
|
-
*
|
|
302
|
-
* @param {number} [
|
|
303
|
-
* @param {number} [
|
|
304
|
-
* @
|
|
305
|
-
* @
|
|
306
|
-
|
|
307
|
-
|
|
377
|
+
* Scan lines across the screen, like an old TV
|
|
378
|
+
* @param {number} [strength] - How dark the lines are, and how bright between them
|
|
379
|
+
* @param {number} [spacing] - Pixels from one line to the next
|
|
380
|
+
* @return {string}
|
|
381
|
+
* @memberof PostProcess
|
|
382
|
+
*/
|
|
383
|
+
function postProcessScanlines(strength=.5, spacing=6)
|
|
384
|
+
{
|
|
385
|
+
return ` // scanlines
|
|
386
|
+
c.rgb *= 1. - ${postProcessNumber(strength)} * cos(p.y * 6.2832 / ${postProcessNumber(spacing)});`;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* Static noise over the picture, changing every frame
|
|
391
|
+
* @param {number} [strength] - How bright the static is
|
|
392
|
+
* @param {number} [size] - Size of a speck in pixels
|
|
393
|
+
* @return {string}
|
|
394
|
+
* @memberof PostProcess
|
|
395
|
+
*/
|
|
396
|
+
function postProcessNoise(strength=.1, size=2)
|
|
397
|
+
{
|
|
398
|
+
return ` // noise
|
|
399
|
+
vec2 q = fract((floor(p / ${postProcessNumber(size)}) + mod(iTime * 500., 1e3)) * .3197);
|
|
400
|
+
c.rgb += ${postProcessNumber(strength)} * fract(1. + sin(51. * q.x + 73. * q.y) * 13753.3);`;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
/**
|
|
404
|
+
* Darken toward the edges and corners
|
|
405
|
+
* @param {number} [strength] - How dark the corners get, 1 is black
|
|
406
|
+
* @param {number} [falloff] - How far in it reaches, low darkens most of the screen, high only the corners
|
|
407
|
+
* @return {string}
|
|
408
|
+
* @memberof PostProcess
|
|
409
|
+
*/
|
|
410
|
+
function postProcessVignette(strength=1, falloff=3)
|
|
411
|
+
{
|
|
412
|
+
return ` // vignette
|
|
413
|
+
vec2 d = uv * 2. - 1.;
|
|
414
|
+
c.rgb *= 1. - ${postProcessNumber(strength)} * min(1., pow(dot(d, d) / 2., ${postProcessNumber(falloff)}));`;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
/**
|
|
418
|
+
* Bend the picture like the bulged glass of an old TV, black past the corners; put it first
|
|
419
|
+
* @param {number} [strength] - How much it bends
|
|
420
|
+
* @return {string}
|
|
421
|
+
* @memberof PostProcess
|
|
422
|
+
*/
|
|
423
|
+
function postProcessCurve(strength=.1)
|
|
424
|
+
{
|
|
425
|
+
return ` // curve
|
|
426
|
+
vec2 d = uv * 2. - 1.;
|
|
427
|
+
d *= 1. + ${postProcessNumber(strength)} * dot(d, d);
|
|
428
|
+
uv = d * .5 + .5;
|
|
429
|
+
c = all(lessThan(abs(d), vec2(1))) ? texture(iChannel0, uv) : vec4(0, 0, 0, 1);`;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
/**
|
|
433
|
+
* Split red and blue apart toward the edges, like a cheap lens; put it before what shades the picture
|
|
434
|
+
* @param {number} [strength] - How far apart at the edge, as a part of the screen
|
|
435
|
+
* @return {string}
|
|
436
|
+
* @memberof PostProcess
|
|
437
|
+
*/
|
|
438
|
+
function postProcessChromatic(strength=.005)
|
|
439
|
+
{
|
|
440
|
+
return ` // chromatic
|
|
441
|
+
vec2 d = (uv - .5) * ${postProcessNumber(strength)} * 2.;
|
|
442
|
+
c.r = texture(iChannel0, uv + d).r;
|
|
443
|
+
c.b = texture(iChannel0, uv - d).b;`;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
/**
|
|
447
|
+
* Draw lines where the 3D depth jumps, around objects and along their creases; needs render3D.depthTexture on
|
|
448
|
+
* @param {Color} [color] - The lines' color, its alpha how strong they are
|
|
449
|
+
* @param {number} [thickness] - How wide the lines are in pixels
|
|
450
|
+
* @param {number} [threshold] - How big a jump makes a line, as a part of the distance, lower draws more
|
|
451
|
+
* @return {string}
|
|
308
452
|
* @memberof PostProcess
|
|
453
|
+
*/
|
|
454
|
+
function postProcessOutline(color=BLACK, thickness=1, threshold=.02)
|
|
455
|
+
{
|
|
456
|
+
ASSERT(isColor(color), 'outline color must be a Color');
|
|
457
|
+
const n = postProcessNumber;
|
|
458
|
+
return ` // outline
|
|
459
|
+
vec2 o = ${n(thickness)} / iResolution.xy;
|
|
460
|
+
float d = sceneDepth(uv);
|
|
461
|
+
float dx = abs(sceneDepth(uv + vec2(o.x, 0)) + sceneDepth(uv - vec2(o.x, 0)) - 2. * d);
|
|
462
|
+
float dy = abs(sceneDepth(uv + vec2(0, o.y)) + sceneDepth(uv - vec2(0, o.y)) - 2. * d);
|
|
463
|
+
vec4 line = vec4(${n(color.r)}, ${n(color.g)}, ${n(color.b)}, ${n(color.a)});
|
|
464
|
+
c.rgb = mix(c.rgb, line.rgb, line.a * step(${n(threshold)}, max(dx, dy) / d));`;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
/**
|
|
468
|
+
* The look of an old TV, as one effect to use alone or join with others: static noise, scan lines, a soft glow and
|
|
469
|
+
* a vignette, and a bulged screen when curve is set; any setting at 0 leaves that part out
|
|
470
|
+
* @param {Object} [settings]
|
|
471
|
+
* @param {number} [settings.noise] - Static noise strength
|
|
472
|
+
* @param {number} [settings.scanlines] - Scan line strength
|
|
473
|
+
* @param {number} [settings.scanlineSpacing] - Pixels from one scan line to the next
|
|
474
|
+
* @param {number} [settings.glow] - Soft glow strength
|
|
475
|
+
* @param {number} [settings.vignette] - Vignette strength
|
|
476
|
+
* @param {number} [settings.curve] - How much the screen bulges, 0 by default for flat
|
|
477
|
+
* @return {string}
|
|
309
478
|
* @example
|
|
310
|
-
*
|
|
479
|
+
* new PostProcessPlugin(postProcessEffects(postProcessTV({scanlines: .4, curve: .1})));
|
|
480
|
+
* @memberof PostProcess
|
|
311
481
|
*/
|
|
312
|
-
function
|
|
313
|
-
{
|
|
482
|
+
function postProcessTV({noise=.1, scanlines=.5, scanlineSpacing=6, glow=.4, vignette=1, curve=0}={})
|
|
483
|
+
{
|
|
484
|
+
const parts = [];
|
|
485
|
+
curve && parts.push(postProcessCurve(curve));
|
|
486
|
+
glow && parts.push(postProcessGlow(0, glow, 2));
|
|
487
|
+
scanlines && parts.push(postProcessScanlines(scanlines, scanlineSpacing));
|
|
488
|
+
noise && parts.push(postProcessNoise(noise, 1));
|
|
489
|
+
vignette && parts.push(postProcessVignette(vignette, 6));
|
|
490
|
+
return parts.map((part)=> ' {\n' + part + '\n }').join('\n');
|
|
491
|
+
}
|