littlejsengine 1.22.0 → 1.23.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/COPYRIGHT.txt +65 -38
- package/EDITOR.md +359 -0
- package/README.md +12 -7
- package/REFERENCE.md +2314 -0
- package/dist/littlejs.d.ts +640 -100
- package/dist/littlejs.esm.js +3596 -1444
- package/dist/littlejs.esm.min.js +3 -3
- package/dist/littlejs.js +3583 -1444
- package/dist/littlejs.min.js +2 -2
- package/dist/littlejs.release.js +2106 -1355
- package/package.json +4 -3
- package/plugins/gltf.js +29 -13
- package/plugins/lightSystem.js +8 -6
- package/plugins/parallax.js +174 -0
- package/plugins/particleEffects.js +37 -22
- package/plugins/pluginExport.js +8 -0
- package/plugins/postProcess.js +5 -2
- package/plugins/render3d.js +59 -21
- package/plugins/render3dEditor.js +1058 -118
- package/plugins/render3dExtras.js +82 -21
- package/plugins/render3dLevel.js +328 -8
- package/plugins/textureSheet.js +1 -0
- package/plugins/tweenSystem.js +39 -34
- package/plugins/uiSystem.js +7 -3
- package/plugins/zzfxm.js +161 -159
- package/src/engine.js +1 -1
- package/src/engineAudio.js +17 -3
- package/src/engineBuild.mjs +18 -2
- package/src/engineDraw.js +26 -10
- package/src/engineEditor.js +515 -52
- package/src/engineExport.js +5 -0
- package/src/engineInput.js +48 -6
- package/src/engineObject.js +675 -675
- package/src/engineRelease.js +17 -2
- package/src/engineSettings.js +14 -0
- package/src/engineTileLayer.js +2 -1
- package/src/engineUtilities.js +291 -291
- package/src/engineWebGL.js +12 -3
package/plugins/render3d.js
CHANGED
|
@@ -302,17 +302,19 @@ function render3DInstance(mesh, matrix, tileInfo, color)
|
|
|
302
302
|
// make room for one more instance of a mesh under a texture and the current draw state, flushing a batch that
|
|
303
303
|
// differs first, and return where its 24 floats go in mesh.instanceData: the matrix, the tint and the uv rect
|
|
304
304
|
// drawMesh passes whether its matrix mirrors, and its batch then culls by the mesh and winds by that at the flush,
|
|
305
|
-
// so it never sets the draw state for them, which would move the state's version at every draw
|
|
306
|
-
|
|
305
|
+
// so it never sets the draw state for them, which would move the state's version at every draw; drawBillboard
|
|
306
|
+
// passes that its batch is unlit, for the same reason
|
|
307
|
+
function render3DInstanceSlot(mesh, textureInfo, mirrored, unlit=false)
|
|
307
308
|
{
|
|
308
309
|
const r = render3D;
|
|
309
310
|
if (mesh.instanceCount && (mesh.instanceTextureInfo !== textureInfo || mesh.instanceMirrored !== mirrored
|
|
310
|
-
|| render3DStateChanged(mesh.instanceState)))
|
|
311
|
+
|| mesh.instanceUnlit !== unlit || render3DStateChanged(mesh.instanceState)))
|
|
311
312
|
render3DFlushInstances(mesh);
|
|
312
313
|
if (!mesh.instanceCount)
|
|
313
314
|
{
|
|
314
315
|
mesh.instanceTextureInfo = textureInfo;
|
|
315
316
|
mesh.instanceMirrored = mirrored;
|
|
317
|
+
mesh.instanceUnlit = unlit;
|
|
316
318
|
mesh.instanceState = render3DCaptureBatchState();
|
|
317
319
|
r.instanceMeshes.push(mesh);
|
|
318
320
|
}
|
|
@@ -346,6 +348,8 @@ function render3DFlushInstances(only)
|
|
|
346
348
|
const state = mesh.instanceState;
|
|
347
349
|
if (mesh.instanceMirrored !== undefined) // a drawMesh batch: culled by its mesh, wound by its matrices
|
|
348
350
|
state.cullBackFaces = !mesh.doubleSided, state.mirrored = mesh.instanceMirrored;
|
|
351
|
+
if (mesh.instanceUnlit) // a batch of sprites
|
|
352
|
+
state.lighting = false;
|
|
349
353
|
render3DDrawInstanced(mesh, buffer, count, mesh.instanceTextureInfo, state);
|
|
350
354
|
}
|
|
351
355
|
if (!only)
|
|
@@ -433,12 +437,17 @@ function render3DShadowCaster()
|
|
|
433
437
|
light.intensity > 0 && light.color.a > 0 ? light : undefined;
|
|
434
438
|
}
|
|
435
439
|
|
|
440
|
+
// the widest cone a shadow map can look down, to each side; the light that casts the shadows lights no wider, or
|
|
441
|
+
// what is past the map's edge would be lit with nothing to shade it
|
|
442
|
+
const RENDER3D_SHADOW_CONE_MAX = 1.35;
|
|
443
|
+
|
|
436
444
|
// a light's cone as the four numbers the shader gets: the way it shines, scaled so that its dot with the way to
|
|
437
445
|
// a point, less the fourth number, is 0 at the edge of the cone and 1 where its fade starts; a light with no cone
|
|
438
446
|
// gets numbers that make it 1 every way
|
|
439
447
|
function render3DLightCone(light)
|
|
440
448
|
{
|
|
441
|
-
const
|
|
449
|
+
const widest = light === render3DShadowCaster() ? RENDER3D_SHADOW_CONE_MAX : PI;
|
|
450
|
+
const angle = light.directional ? 0 : min(light.coneAngle, widest);
|
|
442
451
|
if (!(angle > 0)) return [0, 0, 0, -1];
|
|
443
452
|
const outer = cos(angle), inner = cos(angle * (1 - clamp(light.coneSoftness)));
|
|
444
453
|
const k = 1 / max(inner - outer, 1e-4), forward = light.getForward3D();
|
|
@@ -697,6 +706,7 @@ class Render3DPlugin
|
|
|
697
706
|
/** @type {TextureInfo|undefined} */
|
|
698
707
|
this.streamTileInfo = undefined;
|
|
699
708
|
this.streamState = undefined; // captured state the pending batch was drawn under
|
|
709
|
+
this.streamUnlit = false; // the pending batch is drawn unlit whatever that state says, billboards are
|
|
700
710
|
/** @type {Mesh|undefined} */
|
|
701
711
|
this.capture = undefined; // the mesh a bake is filling
|
|
702
712
|
/** @type {Array<{distance: number, state: Object, draw: function(): void}>|undefined} */
|
|
@@ -1087,6 +1097,8 @@ class Render3DPlugin
|
|
|
1087
1097
|
{
|
|
1088
1098
|
if (!this.streamCount || !render3DCanDraw()) return;
|
|
1089
1099
|
const gl = glContext;
|
|
1100
|
+
if (this.streamUnlit)
|
|
1101
|
+
this.streamState.lighting = false; // its own copy of the state
|
|
1090
1102
|
render3DSetDrawUniforms(RENDER3D_IDENTITY, this.streamTileInfo, WHITE, RENDER3D_FULL_UV_RECT, this.streamState);
|
|
1091
1103
|
render3DBindVertexBuffer(this.streamBuffer);
|
|
1092
1104
|
gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.streamFloats, 0, this.streamCount * RENDER3D_VERTEX_FLOATS);
|
|
@@ -1225,8 +1237,9 @@ class Render3DPlugin
|
|
|
1225
1237
|
// a spotlight's map looks down its cone with perspective, from just in front of it out to its radius
|
|
1226
1238
|
const pos = caster.getWorldPos3D(), forward = caster.getForward3D();
|
|
1227
1239
|
const up = abs(forward.y) > .99 ? vec3(0, 0, 1) : vec3(0, 1, 0);
|
|
1228
|
-
|
|
1229
|
-
const
|
|
1240
|
+
// the near plane stays in front of the far one however small the light
|
|
1241
|
+
const far = caster.radius, near = min(max(far / 500, .02), far / 2);
|
|
1242
|
+
const fov = min(caster.coneAngle, RENDER3D_SHADOW_CONE_MAX) * 2 + .1;
|
|
1230
1243
|
this.shadowMatrix = Matrix4.perspective(fov, 1, near, far).multiply(
|
|
1231
1244
|
Matrix4.lookAt(pos, pos.add(forward), up).invert());
|
|
1232
1245
|
this.shadowPlanes = render3DFrustumPlanes(this.shadowMatrix);
|
|
@@ -1320,13 +1333,34 @@ class Render3DPlugin
|
|
|
1320
1333
|
return this.queueTransparent(p, ()=> this.drawBillboard(p, s, tileInfo, c, angle, upright));
|
|
1321
1334
|
}
|
|
1322
1335
|
|
|
1323
|
-
//
|
|
1324
|
-
//
|
|
1325
|
-
const
|
|
1326
|
-
this.
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1336
|
+
// unlit on screen, in the shadow map the object's flag decides; the batch is told, the draw state is not
|
|
1337
|
+
// set, which would move its version at every sprite
|
|
1338
|
+
const unlit = !this.shadowPass;
|
|
1339
|
+
if (!this.blend && this.depthTest && this.instancing)
|
|
1340
|
+
{
|
|
1341
|
+
// an opaque sprite is one more instance of the shared quad, as a mesh's uses are: every sprite of a
|
|
1342
|
+
// sheet is one instanced draw at the end of the stage, with nothing written per corner; the shader
|
|
1343
|
+
// drops its see through texels, so it needs no sorting
|
|
1344
|
+
if (!render3DCanDraw() || this.shadowPass && !this.lighting) return; // unlit things cast no shadow
|
|
1345
|
+
if (this.frustumCulling && !render3DSphereVisible(pos.x, pos.y, pos.z, hypot(size.x, size.y) / 2))
|
|
1346
|
+
return;
|
|
1347
|
+
const quad = this.billboardMesh, cb = this.cameraBack, uv = render3DGetTileUVs(tileInfo);
|
|
1348
|
+
render3DMeshUpload(quad);
|
|
1349
|
+
// the quad's half axes, doubled for its unit square
|
|
1350
|
+
const a = render3DBillboardAxes(size, angle, upright);
|
|
1351
|
+
const k = render3DInstanceSlot(quad, render3DTextureOf(tileInfo), false, unlit), data = quad.instanceData;
|
|
1352
|
+
data[k] = a[0] * 2; data[k+1] = a[1] * 2; data[k+2] = a[2] * 2; data[k+3] = 0;
|
|
1353
|
+
data[k+4] = a[3] * 2; data[k+5] = a[4] * 2; data[k+6] = a[5] * 2; data[k+7] = 0;
|
|
1354
|
+
data[k+8] = cb.x; data[k+9] = cb.y; data[k+10] = cb.z; data[k+11] = 0;
|
|
1355
|
+
data[k+12] = pos.x; data[k+13] = pos.y; data[k+14] = pos.z; data[k+15] = 1;
|
|
1356
|
+
data[k+16] = color.r; data[k+17] = color.g; data[k+18] = color.b; data[k+19] = color.a;
|
|
1357
|
+
data[k+20] = uv.x; data[k+21] = uv.y; data[k+22] = uv.w; data[k+23] = uv.h;
|
|
1358
|
+
return;
|
|
1359
|
+
}
|
|
1360
|
+
|
|
1361
|
+
// one that blends is drawn in its sorted place: the quad's six stream vertices written straight in with no
|
|
1362
|
+
// vectors made, for sprites that blend, and for particles when instancing is off
|
|
1363
|
+
const uvRect = render3DBeginStrip(6, tileInfo, unlit);
|
|
1330
1364
|
if (!uvRect) return;
|
|
1331
1365
|
const a = render3DBillboardAxes(size, angle, upright);
|
|
1332
1366
|
const rx = a[0], ry = a[1], rz = a[2], ux = a[3], uy = a[4], uz = a[5];
|
|
@@ -2438,8 +2472,9 @@ function render3DRenderDepth()
|
|
|
2438
2472
|
// which way they face, so keeping the count even keeps every strip facing out.
|
|
2439
2473
|
|
|
2440
2474
|
// make room in the stream for a strip of count vertices under the current state and texture, flushing a batch that
|
|
2441
|
-
// differs first; returns the uv rect to map the vertices with, or undefined when nothing can be drawn
|
|
2442
|
-
|
|
2475
|
+
// differs first; returns the uv rect to map the vertices with, or undefined when nothing can be drawn; unlit draws
|
|
2476
|
+
// the batch unlit whatever the state says, so a billboard does not set the state and set it back at every draw
|
|
2477
|
+
function render3DBeginStrip(count, tileInfo, unlit=false)
|
|
2443
2478
|
{
|
|
2444
2479
|
const r = render3D;
|
|
2445
2480
|
if (!render3DCanDraw()) return;
|
|
@@ -2447,12 +2482,13 @@ function render3DBeginStrip(count, tileInfo)
|
|
|
2447
2482
|
ASSERT(count <= RENDER3D_MAX_STREAM_VERTS, 'strip is too large for the stream, bake it into a mesh');
|
|
2448
2483
|
if (count > RENDER3D_MAX_STREAM_VERTS) return;
|
|
2449
2484
|
const textureInfo = render3DTextureOf(tileInfo);
|
|
2450
|
-
if (r.streamCount && (textureInfo !== r.streamTileInfo ||
|
|
2451
|
-
|| r.streamCount + count > RENDER3D_MAX_STREAM_VERTS))
|
|
2485
|
+
if (r.streamCount && (textureInfo !== r.streamTileInfo || r.streamUnlit !== unlit
|
|
2486
|
+
|| render3DStateChanged(r.streamState) || r.streamCount + count > RENDER3D_MAX_STREAM_VERTS))
|
|
2452
2487
|
r.flush();
|
|
2453
2488
|
render3DFlushBeforeOverlay();
|
|
2454
2489
|
if (!r.streamCount)
|
|
2455
2490
|
r.streamState = render3DCaptureBatchState();
|
|
2491
|
+
r.streamUnlit = unlit;
|
|
2456
2492
|
r.streamTileInfo = textureInfo;
|
|
2457
2493
|
return render3DGetTileUVs(tileInfo);
|
|
2458
2494
|
}
|
|
@@ -4660,7 +4696,7 @@ class InstancedMesh3D extends EngineObject3D
|
|
|
4660
4696
|
* - intensity multiplies the color, above 1 for a light brighter than white
|
|
4661
4697
|
* - radius is a world distance, so scale3D does not change it
|
|
4662
4698
|
* - An alpha, an intensity or a radius of 0 switches it off, and a light that is off takes none of those slots
|
|
4663
|
-
* - Draws nothing
|
|
4699
|
+
* - Draws nothing but its glow, when it has one; add a small emissive mesh if the lamp itself should be seen
|
|
4664
4700
|
* @extends EngineObject3D
|
|
4665
4701
|
* @memberof Render3D
|
|
4666
4702
|
* @example
|
|
@@ -4709,8 +4745,10 @@ class Light3D extends EngineObject3D
|
|
|
4709
4745
|
const r = render3D, c = this.color, pos = render3DObjectMatrix(this).getTranslation();
|
|
4710
4746
|
const toCamera = r.camera.pos.subtract(pos), distance = toCamera.length();
|
|
4711
4747
|
const at = distance ? pos.add(toCamera.scale(min(this.glow, distance) / 2 / distance)) : pos;
|
|
4712
|
-
const color = rgb(c.r, c.g, c.b, c.a * min(this.intensity, 1));
|
|
4713
|
-
|
|
4748
|
+
const color = rgb(c.r, c.g, c.b, c.a * min(this.intensity, 1)), texture = engineGlowTexture(this.glowFalloff);
|
|
4749
|
+
// a browser that can not make the glow's texture draws no glow, not a plain square
|
|
4750
|
+
if (texture || !glContext)
|
|
4751
|
+
r.drawBillboard(at, vec2(this.glow), texture, color);
|
|
4714
4752
|
}
|
|
4715
4753
|
}
|
|
4716
4754
|
|
|
@@ -4720,7 +4758,7 @@ class Light3D extends EngineObject3D
|
|
|
4720
4758
|
* - It shines from its position toward the origin, like a three.js DirectionalLight: only the direction to it
|
|
4721
4759
|
* counts, so moving it or its parent swings the light around; parent it to a sun in the sky and it follows
|
|
4722
4760
|
* - It cannot sit on the origin, since that leaves no direction
|
|
4723
|
-
* -
|
|
4761
|
+
* - It casts no shadow: the sun, render3D.sunDirection, does, or a spotlight set as render3D.shadowLight
|
|
4724
4762
|
* @extends Light3D
|
|
4725
4763
|
* @memberof Render3D
|
|
4726
4764
|
* @example
|