littlejsengine 1.26.0 → 1.26.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/CHANGELOG.md +12 -0
- package/REFERENCE.md +9 -3
- package/dist/littlejs.d.ts +23 -3
- package/dist/littlejs.esm.js +46 -16
- package/dist/littlejs.esm.min.js +2 -2
- package/dist/littlejs.js +45 -16
- package/dist/littlejs.min.js +2 -2
- package/dist/littlejs.release.js +45 -16
- package/package.json +1 -1
- package/plugins/postProcess.js +5 -1
- package/plugins/render3d.js +14 -4
- package/src/engine.js +16 -5
- package/src/engineDraw.js +3 -0
- package/src/engineExport.js +1 -0
- package/src/engineInput.js +7 -6
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,18 @@ What changed in each release, newest first. Releases before 1.20.0 are on the
|
|
|
7
7
|
|
|
8
8
|
Nothing yet.
|
|
9
9
|
|
|
10
|
+
## 1.26.1 - 2026-10-08
|
|
11
|
+
|
|
12
|
+
### New Changes
|
|
13
|
+
- A 3D Shader may define `void mainNormal(inout vec3 n)`, given the world normal after the normal map, to bend it per pixel for waves, ripples or a flag; the lighting, shadows, specular, Fresnel, environment reflection and fog all use it
|
|
14
|
+
- `postProcess.enabled`: false skips the post process pass, so an effect turns off and on without taking the plugin apart
|
|
15
|
+
- `averageFPS` is public and kept in release builds, where it read 0 unless debug or the watermark was on; it starts at the first frame's rate rather than climbing from 0
|
|
16
|
+
- `camera.align2DZ`: the z of the plane an align2D camera lines up with the 2D view, 0 as before
|
|
17
|
+
- The right click menu is left on links, as it is on text fields
|
|
18
|
+
|
|
19
|
+
### Fixes
|
|
20
|
+
- A tap starts the audio with touch input off too
|
|
21
|
+
|
|
10
22
|
## 1.26.0 - 2026-10-07
|
|
11
23
|
|
|
12
24
|
### New Changes
|
package/REFERENCE.md
CHANGED
|
@@ -25,8 +25,9 @@ engineName // Name of the engine: 'LittleJS'
|
|
|
25
25
|
engineVersion // Version of the engine
|
|
26
26
|
frameRate // Fixed frame rate for updates (60)
|
|
27
27
|
frame // Current update frame
|
|
28
|
-
time // Game time since start in seconds (stops when paused)
|
|
28
|
+
time // Game time since start in seconds (stops when paused, falls behind the clock below 20 FPS)
|
|
29
29
|
timeReal // Real time since start in seconds (keeps running when paused; the debug speed keys scale it)
|
|
30
|
+
averageFPS // Frames drawn per second, smoothed
|
|
30
31
|
timeDelta // Seconds the update covers: 1/60, or the display frame's time with engineVariableStep
|
|
31
32
|
timeScale = 1 // Game speed, more or fewer fixed updates per second; with engineVariableStep it scales timeDelta
|
|
32
33
|
paused // Is the game paused? (set with setPaused)
|
|
@@ -325,7 +326,9 @@ toggleFullscreen()
|
|
|
325
326
|
// Shader Object - a custom fragment shader for objects and draws, 2D or 3D
|
|
326
327
|
new Shader(fragmentCode) // fragmentCode defines void mainImage(out vec4 c, vec2 uv) in the post processing
|
|
327
328
|
// style; it gives the surface color, then the object's color and additive color
|
|
328
|
-
// apply in 2D, and the lighting, shadows and fog in 3D
|
|
329
|
+
// apply in 2D, and the lighting, shadows and fog in 3D; in 3D it may also define
|
|
330
|
+
// void mainNormal(inout vec3 n), the world normal after the normal map, to bend
|
|
331
|
+
// it per pixel (waves, ripples) for the lighting, specular and reflection
|
|
329
332
|
obj.shader = shader // any EngineObject or EngineObject3D; draws that share a Shader share a batch
|
|
330
333
|
shader.dispose() // frees its programs and takes it off the engine's list, which keeps every Shader
|
|
331
334
|
// for a lost context; for one made each time a scene starts; drawn again it
|
|
@@ -1179,6 +1182,7 @@ postProcessBloom(threshold=.6, strength=1, size=6, includeMainCanvas=false) // s
|
|
|
1179
1182
|
// and past a size of 32 it would take hundreds, so that is as wide as it goes
|
|
1180
1183
|
postProcessBloomShader(threshold, strength, size) // its shader code, to pass to PostProcessPlugin or build on
|
|
1181
1184
|
postProcess.setShaderCode(shaderCode) // shade with new code from the next frame, to switch effects while running
|
|
1185
|
+
postProcess.enabled = true // false skips the pass, the frame showing as drawn, to turn an effect off and back on
|
|
1182
1186
|
|
|
1183
1187
|
// Built in effects: each is a piece of shader code with its settings written in, working on c, the pixel's color,
|
|
1184
1188
|
// and uv, where it is on the screen from 0 to 1; postProcessEffects joins pieces in order into one shader, and your
|
|
@@ -1333,6 +1337,7 @@ render3D.camera.follow(target, offset, percent=1) // chase camera: ease toward t
|
|
|
1333
1337
|
// is how far it moves each call, so call it every frame, from
|
|
1334
1338
|
// gameUpdatePost once the target has moved
|
|
1335
1339
|
render3D.camera.align2D = true // lock to the 2D camera so the z=0 plane matches world space, false by default
|
|
1340
|
+
render3D.camera.align2DZ = 0 // the z of the plane align2D lines up, the camera its distance in front
|
|
1336
1341
|
render3D.camera.getForward() .getRight() .getUp() // the camera's axes as it is right now; render3D.cameraRight
|
|
1337
1342
|
// .cameraUp .cameraForward are this frame's, read only
|
|
1338
1343
|
render3D.viewMatrix .projectionMatrix .viewProjection .shadowMatrix // this frame's, rebuilt by updateMatrices()
|
|
@@ -1408,7 +1413,8 @@ render3D.shadowLight = flashlight // a spotlight, a Light3D with a coneAngle
|
|
|
1408
1413
|
render3D.shadowRange = 40 // world size the map covers around shadowCenter, smaller is sharper
|
|
1409
1414
|
// it is a square facing the light, so ~1.5x an area's width covers it
|
|
1410
1415
|
render3D.shadowCenter = undefined // Vector3 center of the shadowed area, read each frame; undefined follows the camera
|
|
1411
|
-
render3D.shadowBias = .003 // raise if lit surfaces get speckled with their own shadow, lower if shadows float away
|
|
1416
|
+
render3D.shadowBias = .003 // raise if lit surfaces get speckled with their own shadow, lower if shadows float away;
|
|
1417
|
+
// a share of the map's depth (2 * shadowRange for the sun), so the gap grows with the range
|
|
1412
1418
|
// from their casters
|
|
1413
1419
|
render3D.shadowSoftness = 1 // how far to blur the shadow edge, in shadow map pixels
|
|
1414
1420
|
|
package/dist/littlejs.d.ts
CHANGED
|
@@ -606,6 +606,8 @@ declare module "littlejsengine" {
|
|
|
606
606
|
* @memberof Engine */
|
|
607
607
|
export let frame: number;
|
|
608
608
|
/** Current engine time since start in seconds
|
|
609
|
+
* - Below 20 FPS it falls behind the clock, since a frame catches up at most 50 ms of updates, so a timer in
|
|
610
|
+
* real seconds, one that must keep up on a slow device, goes by timeReal
|
|
609
611
|
* @type {number}
|
|
610
612
|
* @memberof Engine */
|
|
611
613
|
export let time: number;
|
|
@@ -613,6 +615,10 @@ declare module "littlejsengine" {
|
|
|
613
615
|
* @type {number}
|
|
614
616
|
* @memberof Engine */
|
|
615
617
|
export let timeReal: number;
|
|
618
|
+
/** Frames drawn per second, smoothed over the last few seconds, in release builds too
|
|
619
|
+
* @type {number}
|
|
620
|
+
* @memberof Engine */
|
|
621
|
+
export let averageFPS: number;
|
|
616
622
|
/** Is the game paused? Causes time and objects to not be updated
|
|
617
623
|
* @type {boolean}
|
|
618
624
|
* @default false
|
|
@@ -647,7 +653,9 @@ declare module "littlejsengine" {
|
|
|
647
653
|
* @param {GameCallback} [gameRender] - Called before objects are rendered, use for drawing backgrounds/world elements
|
|
648
654
|
* @param {GameCallback} [gameRenderPost] - Called after objects are rendered, use for drawing UI/overlays
|
|
649
655
|
* @param {Array<string>|string} [imageSources=[]] - List of image file paths to preload (e.g., ['player.png', 'tiles.png']), or one path
|
|
650
|
-
* @param {HTMLElement} [rootElement] - Root DOM element to attach canvas to, defaults to document.body
|
|
656
|
+
* @param {HTMLElement} [rootElement] - Root DOM element to attach canvas to, defaults to document.body; it is
|
|
657
|
+
* styled for a game (no scroll bars or selection, touch-action none),
|
|
658
|
+
* where its own inline style does not say otherwise
|
|
651
659
|
* It keeps its own inline styles and the canvas centers inside it, but the canvas is still sized from the window,
|
|
652
660
|
* so set canvasFixedSize or canvasMaxSize to fit a smaller element
|
|
653
661
|
* @example
|
|
@@ -2890,6 +2898,9 @@ declare module "littlejsengine" {
|
|
|
2890
2898
|
* across the sprite or the mesh's own uv
|
|
2891
2899
|
* - Names in 3D only: worldPos, worldNormal, cameraPos, sunDirection, sunColor, ambientColor, ambientGroundColor,
|
|
2892
2900
|
* lightCount, lights[i], lightColors[i] and shadow()
|
|
2901
|
+
* - In 3D the snippet may also define void mainNormal(inout vec3 n), given the normal facing the camera after the
|
|
2902
|
+
* normal map, in world space, to bend it per pixel for waves or ripples; the lighting, specular, reflection and
|
|
2903
|
+
* fog then all use it, as they use a normal map
|
|
2893
2904
|
* - In 3D the shadow map is drawn without the Shader, cut only by the texture's alpha, so a snippet that removes
|
|
2894
2905
|
* parts of a surface still shadows with the whole of it
|
|
2895
2906
|
* @example
|
|
@@ -5350,6 +5361,9 @@ declare module "littlejsengine" {
|
|
|
5350
5361
|
constructor(shaderCode?: string, includeMainCanvas?: boolean, feedbackTexture?: boolean);
|
|
5351
5362
|
/** @property {string} - The shadertoy style mainImage code it shades with, see setShaderCode */
|
|
5352
5363
|
shaderCode: string;
|
|
5364
|
+
/** @property {boolean} - Is the pass on? Off, the frame shows as the engine drew it, the shader is kept,
|
|
5365
|
+
* and the feedback texture holds the last frame drawn with it on */
|
|
5366
|
+
enabled: boolean;
|
|
5353
5367
|
/** @property {Object<string, number|Array<number>>} - The game's own values for the shader, a uniform each
|
|
5354
5368
|
* by its name, a number a float and a list of 2 to 4 numbers a vector, set every frame as they are; an
|
|
5355
5369
|
* effect setting can be one of these names, so it changes every frame without making the shader again, all
|
|
@@ -8788,7 +8802,8 @@ declare module "littlejsengine" {
|
|
|
8788
8802
|
* - EngineObject3D is an EngineObject with a 3D position, rotation and mesh
|
|
8789
8803
|
* - The 3D scene draws under the 2D sprites, so HUD and text land on top
|
|
8790
8804
|
* - Lighting is the sun plus ambient, with optional extra lights, fog and shadows
|
|
8791
|
-
* - Any object or draw can bring its own Shader, a mainImage snippet the lighting then applies to
|
|
8805
|
+
* - Any object or draw can bring its own Shader, a mainImage snippet the lighting then applies to, and a
|
|
8806
|
+
* mainNormal in it bends the normal the lighting uses
|
|
8792
8807
|
* - Meshes and the basic builders are in render3dMesh.js, EngineObject3D, instancing and lights in
|
|
8793
8808
|
* render3dObject.js, both right after this one; the other builders, terrain, particles, camera controls and the
|
|
8794
8809
|
* OBJ loader are in the Render3D Extras plugin, which goes after those
|
|
@@ -8873,7 +8888,9 @@ declare module "littlejsengine" {
|
|
|
8873
8888
|
/** @property {Vector3|undefined} - Center of the shadowed area, read each frame, undefined follows the camera
|
|
8874
8889
|
* @type {Vector3|undefined} */
|
|
8875
8890
|
shadowCenter: Vector3 | undefined;
|
|
8876
|
-
/** @property {number} - Stops surfaces shadowing themselves, raise for speckles, lower if shadows drift off
|
|
8891
|
+
/** @property {number} - Stops surfaces shadowing themselves, raise for speckles, lower if shadows drift off;
|
|
8892
|
+
* a share of the shadow map's depth, twice shadowRange for the sun and a spotlight's radius, so the gap behind
|
|
8893
|
+
* a caster grows with the range as the map's texels do, and the speckles they make stay away */
|
|
8877
8894
|
shadowBias: number;
|
|
8878
8895
|
/** @property {number} - How much to blur the shadow edges */
|
|
8879
8896
|
shadowSoftness: number;
|
|
@@ -9417,6 +9434,9 @@ declare module "littlejsengine" {
|
|
|
9417
9434
|
/** @property {boolean} - Line the 3D camera up with the 2D camera, so 3D things at z=0 sit on the 2D sprites;
|
|
9418
9435
|
* it lines up with the 2D view of the main canvas, whatever canvas size a screenToRay is given */
|
|
9419
9436
|
align2D: boolean;
|
|
9437
|
+
/** @property {number} - The z of the plane align2D lines up with the 2D view, the camera sitting its
|
|
9438
|
+
* distance in front of it */
|
|
9439
|
+
align2DZ: number;
|
|
9420
9440
|
/** Returns the camera's world transform
|
|
9421
9441
|
* @return {Matrix4} */
|
|
9422
9442
|
getMatrix(): Matrix4;
|
package/dist/littlejs.esm.js
CHANGED
|
@@ -35,7 +35,7 @@ const engineName = 'LittleJS';
|
|
|
35
35
|
* @type {string}
|
|
36
36
|
* @default
|
|
37
37
|
* @memberof Engine */
|
|
38
|
-
const engineVersion = '1.26.
|
|
38
|
+
const engineVersion = '1.26.1';
|
|
39
39
|
|
|
40
40
|
/** Frames per second to update
|
|
41
41
|
* @type {number}
|
|
@@ -69,6 +69,8 @@ let engineObjectsCollideStaticLast = [];
|
|
|
69
69
|
let frame = 0;
|
|
70
70
|
|
|
71
71
|
/** Current engine time since start in seconds
|
|
72
|
+
* - Below 20 FPS it falls behind the clock, since a frame catches up at most 50 ms of updates, so a timer in
|
|
73
|
+
* real seconds, one that must keep up on a slow device, goes by timeReal
|
|
72
74
|
* @type {number}
|
|
73
75
|
* @memberof Engine */
|
|
74
76
|
let time = 0;
|
|
@@ -94,8 +96,13 @@ function getPaused() { return paused; }
|
|
|
94
96
|
* @memberof Engine */
|
|
95
97
|
function setPaused(isPaused=true) { paused = isPaused; }
|
|
96
98
|
|
|
99
|
+
/** Frames drawn per second, smoothed over the last few seconds, in release builds too
|
|
100
|
+
* @type {number}
|
|
101
|
+
* @memberof Engine */
|
|
102
|
+
let averageFPS = 0;
|
|
103
|
+
|
|
97
104
|
// Engine internal variables
|
|
98
|
-
let frameTimeLastMS = 0, frameTimeBufferMS = 0
|
|
105
|
+
let frameTimeLastMS = 0, frameTimeBufferMS = 0;
|
|
99
106
|
|
|
100
107
|
// delta smoothing, after Time Delta Smoothing by Frank Force (2013): a frame is on screen for whole display frames,
|
|
101
108
|
// so each delta is rounded to them and the rest is carried to the next, keeping the total real time; the frame
|
|
@@ -436,7 +443,9 @@ function engineLoadingScreenDraw(elapsed)
|
|
|
436
443
|
* @param {GameCallback} [gameRender] - Called before objects are rendered, use for drawing backgrounds/world elements
|
|
437
444
|
* @param {GameCallback} [gameRenderPost] - Called after objects are rendered, use for drawing UI/overlays
|
|
438
445
|
* @param {Array<string>|string} [imageSources=[]] - List of image file paths to preload (e.g., ['player.png', 'tiles.png']), or one path
|
|
439
|
-
* @param {HTMLElement} [rootElement] - Root DOM element to attach canvas to, defaults to document.body
|
|
446
|
+
* @param {HTMLElement} [rootElement] - Root DOM element to attach canvas to, defaults to document.body; it is
|
|
447
|
+
* styled for a game (no scroll bars or selection, touch-action none),
|
|
448
|
+
* where its own inline style does not say otherwise
|
|
440
449
|
* It keeps its own inline styles and the canvas centers inside it, but the canvas is still sized from the window,
|
|
441
450
|
* so set canvasFixedSize or canvasMaxSize to fit a smaller element
|
|
442
451
|
* @example
|
|
@@ -499,8 +508,10 @@ async function engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, game
|
|
|
499
508
|
// by ~page-load-time when RAF starts handing real timestamps
|
|
500
509
|
if (!frameTimeLastMS) frameTimeDeltaMS = 0;
|
|
501
510
|
frameTimeLastMS = frameTimeMS;
|
|
502
|
-
|
|
503
|
-
|
|
511
|
+
// the first frame's rate seeds the average, so it does not start out climbing from 0; a gap of over a
|
|
512
|
+
// second, a hidden tab coming back, is not a frame
|
|
513
|
+
if (frameTimeDeltaMS && frameTimeDeltaMS < 1e3)
|
|
514
|
+
averageFPS = averageFPS ? lerp(averageFPS, 1e3/frameTimeDeltaMS, .05) : 1e3/frameTimeDeltaMS;
|
|
504
515
|
// the time the frame will be on screen, in whole display frames; engineStep's steps are exact already
|
|
505
516
|
if (!manualStepAtStart)
|
|
506
517
|
frameTimeDeltaMS = engineSmoothDelta(frameTimeDeltaMS);
|
|
@@ -5748,6 +5759,9 @@ class SpriteAnimator
|
|
|
5748
5759
|
* across the sprite or the mesh's own uv
|
|
5749
5760
|
* - Names in 3D only: worldPos, worldNormal, cameraPos, sunDirection, sunColor, ambientColor, ambientGroundColor,
|
|
5750
5761
|
* lightCount, lights[i], lightColors[i] and shadow()
|
|
5762
|
+
* - In 3D the snippet may also define void mainNormal(inout vec3 n), given the normal facing the camera after the
|
|
5763
|
+
* normal map, in world space, to bend it per pixel for waves or ripples; the lighting, specular, reflection and
|
|
5764
|
+
* fog then all use it, as they use a normal map
|
|
5751
5765
|
* - In 3D the shadow map is drawn without the Shader, cut only by the texture's alpha, so a snippet that removes
|
|
5752
5766
|
* parts of a surface still shadows with the whole of it
|
|
5753
5767
|
* @example
|
|
@@ -7899,8 +7913,9 @@ function inputInit()
|
|
|
7899
7913
|
}
|
|
7900
7914
|
function onContextMenu(e)
|
|
7901
7915
|
{
|
|
7902
|
-
// prevent right click menu, but a text field keeps its copy and paste menu
|
|
7903
|
-
|
|
7916
|
+
// prevent right click menu, but a text field keeps its copy and paste menu and a link its open in new tab
|
|
7917
|
+
const target = /** @type {HTMLElement} */ (e.target);
|
|
7918
|
+
if (inputPreventDefault && !isTextInput(target) && !target?.closest?.('a[href]'))
|
|
7904
7919
|
e.preventDefault();
|
|
7905
7920
|
}
|
|
7906
7921
|
function onBlur()
|
|
@@ -7921,6 +7936,10 @@ function inputInit()
|
|
|
7921
7936
|
// handle all touch events the same way
|
|
7922
7937
|
function handleTouch(e)
|
|
7923
7938
|
{
|
|
7939
|
+
// fix stalled audio requiring user interaction, with touch input off too since the page's sound needs it
|
|
7940
|
+
if (soundEnable && !headlessMode && audioContext && !audioIsRunning())
|
|
7941
|
+
audioResume();
|
|
7942
|
+
|
|
7924
7943
|
if (!touchInputEnable)
|
|
7925
7944
|
{
|
|
7926
7945
|
// turned off mid touch, the finger that drove the mouse lets go of it
|
|
@@ -7931,10 +7950,6 @@ function inputInit()
|
|
|
7931
7950
|
}
|
|
7932
7951
|
inputLastTouchTime = performance.now();
|
|
7933
7952
|
|
|
7934
|
-
// fix stalled audio requiring user interaction
|
|
7935
|
-
if (soundEnable && !headlessMode && audioContext && !audioIsRunning())
|
|
7936
|
-
audioResume();
|
|
7937
|
-
|
|
7938
7953
|
// when the touch gamepad is enabled it owns touch input: suppress the
|
|
7939
7954
|
// touch->mouse passthrough entirely unless touchGamepadPassthrough is set
|
|
7940
7955
|
// (its own zones drive gameplay via pointer events)
|
|
@@ -14193,6 +14208,10 @@ class PostProcessPlugin
|
|
|
14193
14208
|
/** @property {string} - The shadertoy style mainImage code it shades with, see setShaderCode */
|
|
14194
14209
|
this.shaderCode = shaderCode || postProcessEffects(); // no code passes the frame through
|
|
14195
14210
|
|
|
14211
|
+
/** @property {boolean} - Is the pass on? Off, the frame shows as the engine drew it, the shader is kept,
|
|
14212
|
+
* and the feedback texture holds the last frame drawn with it on */
|
|
14213
|
+
this.enabled = true;
|
|
14214
|
+
|
|
14196
14215
|
/** @property {Object<string, number|Array<number>>} - The game's own values for the shader, a uniform each
|
|
14197
14216
|
* by its name, a number a float and a list of 2 to 4 numbers a vector, set every frame as they are; an
|
|
14198
14217
|
* effect setting can be one of these names, so it changes every frame without making the shader again, all
|
|
@@ -14278,7 +14297,7 @@ class PostProcessPlugin
|
|
|
14278
14297
|
}
|
|
14279
14298
|
function postProcessRender()
|
|
14280
14299
|
{
|
|
14281
|
-
if (headlessMode || !glEnable) return;
|
|
14300
|
+
if (headlessMode || !glEnable || !postProcess.enabled) return;
|
|
14282
14301
|
|
|
14283
14302
|
// clear out the buffer, before anything here binds its own
|
|
14284
14303
|
glFlush();
|
|
@@ -24708,7 +24727,8 @@ function raycastBox(ray, pos, size, rotation)
|
|
|
24708
24727
|
* - EngineObject3D is an EngineObject with a 3D position, rotation and mesh
|
|
24709
24728
|
* - The 3D scene draws under the 2D sprites, so HUD and text land on top
|
|
24710
24729
|
* - Lighting is the sun plus ambient, with optional extra lights, fog and shadows
|
|
24711
|
-
* - Any object or draw can bring its own Shader, a mainImage snippet the lighting then applies to
|
|
24730
|
+
* - Any object or draw can bring its own Shader, a mainImage snippet the lighting then applies to, and a
|
|
24731
|
+
* mainNormal in it bends the normal the lighting uses
|
|
24712
24732
|
* - Meshes and the basic builders are in render3dMesh.js, EngineObject3D, instancing and lights in
|
|
24713
24733
|
* render3dObject.js, both right after this one; the other builders, terrain, particles, camera controls and the
|
|
24714
24734
|
* OBJ loader are in the Render3D Extras plugin, which goes after those
|
|
@@ -25286,7 +25306,9 @@ class Render3DPlugin
|
|
|
25286
25306
|
/** @property {Vector3|undefined} - Center of the shadowed area, read each frame, undefined follows the camera
|
|
25287
25307
|
* @type {Vector3|undefined} */
|
|
25288
25308
|
this.shadowCenter = undefined;
|
|
25289
|
-
/** @property {number} - Stops surfaces shadowing themselves, raise for speckles, lower if shadows drift off
|
|
25309
|
+
/** @property {number} - Stops surfaces shadowing themselves, raise for speckles, lower if shadows drift off;
|
|
25310
|
+
* a share of the shadow map's depth, twice shadowRange for the sun and a spotlight's radius, so the gap behind
|
|
25311
|
+
* a caster grows with the range as the map's texels do, and the speckles they make stay away */
|
|
25290
25312
|
this.shadowBias = .003;
|
|
25291
25313
|
/** @property {number} - How much to blur the shadow edges */
|
|
25292
25314
|
this.shadowSoftness = 1;
|
|
@@ -26320,6 +26342,9 @@ class Camera3D
|
|
|
26320
26342
|
/** @property {boolean} - Line the 3D camera up with the 2D camera, so 3D things at z=0 sit on the 2D sprites;
|
|
26321
26343
|
* it lines up with the 2D view of the main canvas, whatever canvas size a screenToRay is given */
|
|
26322
26344
|
this.align2D = false;
|
|
26345
|
+
/** @property {number} - The z of the plane align2D lines up with the 2D view, the camera sitting its
|
|
26346
|
+
* distance in front of it */
|
|
26347
|
+
this.align2DZ = 0;
|
|
26323
26348
|
}
|
|
26324
26349
|
|
|
26325
26350
|
/** Returns the camera's world transform
|
|
@@ -26390,7 +26415,7 @@ class Camera3D
|
|
|
26390
26415
|
ASSERT(!canvasHeight || distance < this.far,
|
|
26391
26416
|
'align2D needs this camera distance to match the 2D view, raise camera.far past it', distance);
|
|
26392
26417
|
this.orthographic &&= halfHeight * 2; // an orthographic camera stays orthographic and shows the same height
|
|
26393
|
-
this.pos = vec3(cameraPos.x, cameraPos.y, distance);
|
|
26418
|
+
this.pos = vec3(cameraPos.x, cameraPos.y, this.align2DZ + distance);
|
|
26394
26419
|
this.rotation = vec3(0, 0, -cameraAngle); // 2D angles turn the other way
|
|
26395
26420
|
}
|
|
26396
26421
|
}
|
|
@@ -26442,7 +26467,8 @@ const RENDER3D_SNIPPET_NAMES =
|
|
|
26442
26467
|
'#define lights extraLights\n' +
|
|
26443
26468
|
'#define lightColors extraLightColors\n';
|
|
26444
26469
|
|
|
26445
|
-
// the fragment shader; given a Shader's snippet, its mainImage replaces the texture sample and all else is the same
|
|
26470
|
+
// the fragment shader; given a Shader's snippet, its mainImage replaces the texture sample and all else is the same,
|
|
26471
|
+
// and a mainNormal in it bends the normal after the normal map, before all the lighting reads it
|
|
26446
26472
|
// uniforms: lightDir (xyz the way the sunlight travels, w = emissive, 1 or more skips the lighting),
|
|
26447
26473
|
// lightColor (the sun's rgb, a = specular), ambientFog (rgb, a = fogEnd), fogColor (rgb, a = fogStart),
|
|
26448
26474
|
// cameraPos, tex, shadowMap, shadowParams (x = shadows on, y = bias, z = blur step in texture space,
|
|
@@ -26451,6 +26477,7 @@ const RENDER3D_SNIPPET_NAMES =
|
|
|
26451
26477
|
// emissive map is on), skyTop, skyHorizon, skyBottom (what a reflection shows), normalTex, emissiveTex
|
|
26452
26478
|
function render3DFragmentSource(fragmentCode)
|
|
26453
26479
|
{
|
|
26480
|
+
const hasNormal = /\bmainNormal\s*\(/.test(fragmentCode || '');
|
|
26454
26481
|
return '#version 300 es\n' +
|
|
26455
26482
|
'precision highp float;' +
|
|
26456
26483
|
'uniform vec4 lightDir,lightColor,ambientFog,ambientGround,fogColor,shadowParams;' +
|
|
@@ -26498,6 +26525,7 @@ function render3DFragmentSource(fragmentCode)
|
|
|
26498
26525
|
'return normalize((u*m.x-v*m.y)*inversesqrt(k)+n*m.z);}' +
|
|
26499
26526
|
// a snippet's mainImage is declared here and written after main, so a define in it can not reach main
|
|
26500
26527
|
(fragmentCode ? 'void mainImage(out vec4,vec2);' : '') +
|
|
26528
|
+
(hasNormal ? 'void mainNormal(inout vec3);' : '') +
|
|
26501
26529
|
'void main(){' +
|
|
26502
26530
|
(fragmentCode ? 'vec4 t;mainImage(t,T);' : 'vec4 t=texture(tex,T);') +
|
|
26503
26531
|
'if(premultipliedTexture&&t.a>0.)t.rgb/=t.a;' + // back to straight color, what the lighting and blend expect
|
|
@@ -26507,6 +26535,7 @@ function render3DFragmentSource(fragmentCode)
|
|
|
26507
26535
|
'vec3 n=dot(N,N)>0.?normalize(N):vec3(0,1,0);' +
|
|
26508
26536
|
'if(!gl_FrontFacing)n=-n;' + // only a double sided mesh shows a back face, light it on the side that is seen
|
|
26509
26537
|
'if(materialParams.x!=0.)n=normalMapNormal(n);' +
|
|
26538
|
+
(hasNormal ? 'mainNormal(n);n=normalize(n);' : '') +
|
|
26510
26539
|
'float nl=dot(n,-lightDir.xyz);' +
|
|
26511
26540
|
// the shadow is the sun's, or one spotlight's: shadowParams.x is 1 for the sun, 2 and up for that Light3D
|
|
26512
26541
|
'float sh=shadow(),s=shadowParams.x<1.5?sh:1.;' +
|
|
@@ -43439,6 +43468,7 @@ export
|
|
|
43439
43468
|
frame,
|
|
43440
43469
|
time,
|
|
43441
43470
|
timeReal,
|
|
43471
|
+
averageFPS,
|
|
43442
43472
|
paused,
|
|
43443
43473
|
getPaused,
|
|
43444
43474
|
setPaused,
|