littlejsengine 1.19.3 → 1.21.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.
Files changed (54) hide show
  1. package/FAQ.md +841 -820
  2. package/README.md +29 -25
  3. package/dist/littlejs.d.ts +2857 -955
  4. package/dist/littlejs.esm.js +33428 -20995
  5. package/dist/littlejs.esm.min.js +4 -3
  6. package/dist/littlejs.js +33386 -20996
  7. package/dist/littlejs.min.js +2 -2
  8. package/dist/littlejs.release.js +27841 -20422
  9. package/package.json +10 -5
  10. package/plugins/audioEffects.js +28 -24
  11. package/plugins/box2d.js +2516 -2073
  12. package/plugins/drawUtilities.js +206 -31
  13. package/plugins/gltf.js +786 -0
  14. package/plugins/jsconfig.json +19 -0
  15. package/plugins/lightSystem.js +719 -332
  16. package/plugins/math3d.js +148 -27
  17. package/plugins/medalSystem.js +326 -280
  18. package/plugins/newgrounds.js +400 -199
  19. package/plugins/pathFinder.js +208 -175
  20. package/plugins/pluginExport.js +25 -0
  21. package/plugins/postProcess.js +96 -24
  22. package/plugins/render3d.js +2067 -1632
  23. package/plugins/render3dDebug.js +110 -0
  24. package/plugins/render3dEditor.js +1812 -0
  25. package/plugins/render3dExtras.js +1948 -0
  26. package/plugins/render3dLevel.js +189 -0
  27. package/plugins/render3dVoxels.js +514 -0
  28. package/plugins/sceneSystem.js +58 -0
  29. package/plugins/textureSheet.js +496 -458
  30. package/plugins/threejs.js +183 -163
  31. package/plugins/tweakables.js +411 -0
  32. package/plugins/tweenSystem.js +265 -145
  33. package/plugins/uiSystem.js +2024 -1687
  34. package/plugins/zzfxm.js +159 -159
  35. package/src/engine.js +378 -97
  36. package/src/engineAudio.js +231 -127
  37. package/src/engineBuild.mjs +292 -256
  38. package/src/engineDebug.js +967 -743
  39. package/src/engineDraw.js +391 -198
  40. package/src/engineEditor.js +2452 -0
  41. package/src/engineExport.js +18 -0
  42. package/src/engineInput.js +1466 -1293
  43. package/src/engineLogo.js +19 -0
  44. package/src/engineMath.js +1274 -1252
  45. package/src/engineObject.js +197 -82
  46. package/src/engineParticles.js +583 -532
  47. package/src/engineRelease.js +79 -45
  48. package/src/engineSettings.js +115 -29
  49. package/src/engineTileLayer.js +995 -741
  50. package/src/engineUtilities.js +19 -13
  51. package/src/engineWebGL.js +239 -82
  52. package/src/jsconfig.json +17 -13
  53. package/plugins/box2d.wasm.js +0 -630
  54. package/plugins/box2d.wasm.wasm +0 -0
@@ -92,6 +92,7 @@ export
92
92
  drawNineSliceScreen,
93
93
  drawThreeSlice,
94
94
  drawThreeSliceScreen,
95
+ TileSlice,
95
96
  drawCrescent,
96
97
  getCrescentPoints,
97
98
 
@@ -102,10 +103,20 @@ export
102
103
  tweenUpdate,
103
104
  Ease,
104
105
 
106
+ // Scene System
107
+ setScene,
108
+ getScene,
109
+
105
110
  // Path Finding
106
111
  PathFinder,
107
112
  PathFinderNode,
108
113
 
114
+ // Tweakables
115
+ tweak,
116
+ tweakDivider,
117
+ tweakButton,
118
+ tweakEngineDefaults,
119
+
109
120
  // Math3D
110
121
  vec3,
111
122
  isVector3,
@@ -132,6 +143,7 @@ export
132
143
  Camera3D,
133
144
  EngineObject3D,
134
145
  Mesh,
146
+ InstancedMesh3D,
135
147
  buildLathe,
136
148
  buildCylinder,
137
149
  buildSphere,
@@ -143,9 +155,11 @@ export
143
155
  buildRibbon,
144
156
  buildLoft,
145
157
  buildSky,
158
+ normalMapFromHeight,
146
159
  buildExtrude,
147
160
  buildText3D,
148
161
  HeightMap,
162
+ VoxelMap,
149
163
  Light3D,
150
164
  DirectionalLight3D,
151
165
  CameraControl3D,
@@ -157,11 +171,22 @@ export
157
171
  engineObjectsRaycast3D,
158
172
  parseOBJ,
159
173
  loadOBJ,
174
+ GLTFModel,
175
+ GLTFPart,
176
+ GLTFObject,
177
+ GLTFAnimation,
178
+ parseGLTF,
179
+ loadGLTF,
160
180
  debugBox3D,
161
181
  debugSphere3D,
162
182
  debugLine3D,
163
183
  debugPoint3D,
164
184
 
185
+ // 3D Level
186
+ level3DAddType,
187
+ level3DAddMesh,
188
+ level3DLoad,
189
+
165
190
  // Three.js
166
191
  threeJS,
167
192
  ThreeJSPlugin,
@@ -24,20 +24,24 @@ let postProcess;
24
24
  * Post Process Plugin - Applies a full screen shader to the rendered output
25
25
  * - Create it after any plugin that draws, since plugins render in the order they are made
26
26
  * and this one shades what is on the canvas when its turn comes
27
+ * - It runs after gameRenderPost, so a HUD drawn there with WebGL is shaded (and bloomed) too;
28
+ * draw the HUD with useWebGL=false (the main canvas) or from a plugin created after this one
27
29
  * @memberof PostProcess
28
30
  */
29
31
  class PostProcessPlugin
30
32
  {
31
33
  /** Create global post processing shader
32
- * @param {string} shaderCode
34
+ * @param {string} [shaderCode] - Shadertoy style mainImage code, a pass-through when left out
33
35
  * @param {boolean} [includeMainCanvas] - combine mainCanvas onto glCanvas
34
- * @param {boolean} [feedbackTexture] - use glCanvas from previous frame as the texture
36
+ * @param {boolean} [feedbackTexture] - also pass the shader's own output from the previous frame as iChannel1,
37
+ * for trails and echoes; iChannel0 is still the frame just drawn
35
38
  * @example
36
39
  * // create the post process plugin object
37
40
  * new PostProcessPlugin(shaderCode);
38
41
  */
39
42
  constructor(shaderCode, includeMainCanvas=false, feedbackTexture=false)
40
43
  {
44
+ ASSERT(engineInitialized || headlessMode, 'create the plugin after engineInit, e.g. in gameInit');
41
45
  ASSERT(!postProcess, 'Post process already initialized');
42
46
  ASSERT(!(includeMainCanvas && feedbackTexture), 'Post process cannot both include main canvas and use feedback texture');
43
47
  postProcess = this;
@@ -51,6 +55,9 @@ class PostProcessPlugin
51
55
  /** @property {WebGLTexture|undefined} - Texture for post processing
52
56
  * @type {WebGLTexture|undefined} */
53
57
  this.texture = undefined;
58
+ /** @property {WebGLTexture|undefined} - The previous frame's output, iChannel1, when feedbackTexture is set
59
+ * @type {WebGLTexture|undefined} */
60
+ this.feedbackTexture = undefined;
54
61
  /** @property {WebGLVertexArrayObject|undefined} - Vertex array object
55
62
  * @type {WebGLVertexArrayObject|undefined} */
56
63
  this.vao = undefined;
@@ -68,7 +75,15 @@ class PostProcessPlugin
68
75
  return;
69
76
  }
70
77
 
71
- // create resources
78
+ // create resources, the feedback starting black, as if the frame before the first were empty
79
+ if (feedbackTexture)
80
+ {
81
+ postProcess.feedbackTexture = glCreateTexture();
82
+ glContext.bindTexture(glContext.TEXTURE_2D, postProcess.feedbackTexture);
83
+ glContext.texImage2D(glContext.TEXTURE_2D, 0, glContext.RGBA, 1, 1, 0, glContext.RGBA,
84
+ glContext.UNSIGNED_BYTE, new Uint8Array([0, 0, 0, 255]));
85
+ glContext.bindTexture(glContext.TEXTURE_2D, glActiveTexture);
86
+ }
72
87
  postProcess.texture = glCreateTexture();
73
88
  postProcess.shader = glCreateProgram(
74
89
  '#version 300 es\n' + // specify GLSL ES version
@@ -78,17 +93,7 @@ class PostProcessPlugin
78
93
  'gl_Position=vec4(p+p-1.,1,1);'+ // set position
79
94
  '}' // end of shader
80
95
  ,
81
- '#version 300 es\n' + // specify GLSL ES version
82
- 'precision highp float;'+ // use highp for accuracy
83
- 'uniform sampler2D iChannel0;'+ // input texture
84
- 'uniform vec3 iResolution;'+ // size of output texture
85
- 'uniform float iTime;'+ // time
86
- 'out vec4 c;'+ // out color
87
- '\n' + shaderCode + '\n'+ // insert custom shader code
88
- 'void main(){'+ // shader entry point
89
- 'mainImage(c,gl_FragCoord.xy);'+ // call post process function
90
- 'c.a=1.;'+ // always use full alpha
91
- '}' // end of shader
96
+ postProcessFragmentSource(shaderCode)
92
97
  );
93
98
 
94
99
  // setup VAO for post processing
@@ -106,6 +111,7 @@ class PostProcessPlugin
106
111
  {
107
112
  postProcess.shader = undefined;
108
113
  postProcess.texture = undefined;
114
+ postProcess.feedbackTexture = undefined;
109
115
  LOG('PostProcessPlugin: WebGL context lost');
110
116
  }
111
117
  function postProcessContextRestored()
@@ -117,6 +123,13 @@ class PostProcessPlugin
117
123
  {
118
124
  if (headlessMode || !glEnable) return;
119
125
 
126
+ // made now if WebGL was off when the plugin was made, or when a lost context came back
127
+ if (!postProcess.shader)
128
+ {
129
+ if (glContext.isContextLost()) return;
130
+ initPostProcess();
131
+ }
132
+
120
133
  // clear out the buffer
121
134
  glFlush();
122
135
 
@@ -128,6 +141,9 @@ class PostProcessPlugin
128
141
  glContext.useProgram(postProcess.shader);
129
142
  glContext.bindVertexArray(postProcess.vao);
130
143
  glContext.pixelStorei(glContext.UNPACK_FLIP_Y_WEBGL, true);
144
+ // upload the canvas the way it shows, premultiplied, since the shader writes full alpha; unpremultiplied
145
+ // a see-through pixel would come out at its full brightness instead of faded over the background
146
+ glContext.pixelStorei(glContext.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);
131
147
  glContext.disable(glContext.BLEND);
132
148
 
133
149
  // setup texture
@@ -141,37 +157,67 @@ class PostProcessPlugin
141
157
  workCanvas.height = mainCanvas.height;
142
158
  glCopyToContext(workContext);
143
159
  workContext.drawImage(mainCanvas, 0, 0);
144
- mainCanvas.width |= 0; // setting size clears the main canvas
145
-
146
- // that also reset the transform, restore it so anything drawn
147
- // later this frame is still in css pixels
148
- const dpr = getCanvasPixelRatio();
149
- mainContext.setTransform(dpr, 0, 0, dpr, 0, 0);
160
+ // clear the main canvas with clearRect, resizing it would also
161
+ // reset the context state (smoothing, line caps) for anything
162
+ // drawn after this and reallocate the canvas every frame
163
+ mainContext.save();
164
+ mainContext.setTransform(1, 0, 0, 1, 0, 0);
165
+ mainContext.clearRect(0, 0, mainCanvas.width, mainCanvas.height);
166
+ mainContext.restore();
150
167
 
151
168
  // copy work canvas to texture
152
169
  glContext.texImage2D(glContext.TEXTURE_2D, 0, glContext.RGBA, glContext.RGBA, glContext.UNSIGNED_BYTE, workCanvas);
153
170
  }
154
- else if (!feedbackTexture)
171
+ else
155
172
  {
156
173
  // copy glCanvas to texture
157
174
  glContext.texImage2D(glContext.TEXTURE_2D, 0, glContext.RGBA, glContext.RGBA, glContext.UNSIGNED_BYTE, glCanvas);
158
175
  }
159
176
 
177
+ // the previous frame's output, on the second texture unit
178
+ if (feedbackTexture)
179
+ {
180
+ glContext.activeTexture(glContext.TEXTURE1);
181
+ glContext.bindTexture(glContext.TEXTURE_2D, postProcess.feedbackTexture);
182
+ }
183
+
184
+ // the 3D depth, when render3D draws it, on the third texture unit, with what sceneDepth needs to read it
185
+ const depth = typeof render3D != 'undefined' && render3D?.depthTexture ? render3D : undefined;
186
+ glContext.activeTexture(glContext.TEXTURE2);
187
+ glContext.bindTexture(glContext.TEXTURE_2D, depth?.cameraDepthTexture || null);
188
+ glContext.activeTexture(glContext.TEXTURE0);
189
+ const camera = depth?.camera;
190
+ camera && glContext.uniform3f(glUniformLocation(postProcess.shader, 'iDepthRange'), camera.near,
191
+ camera.far == Infinity ? 0 : camera.far, camera.orthographic ? 1 : 0);
192
+
160
193
  // set uniforms and draw
161
- const uniformLocation = (name)=>glContext.getUniformLocation(postProcess.shader, name);
194
+ const uniformLocation = (name)=>glUniformLocation(postProcess.shader, name);
162
195
  glContext.uniform1i(uniformLocation('iChannel0'), 0);
196
+ glContext.uniform1i(uniformLocation('iChannel1'), 1);
197
+ glContext.uniform1i(uniformLocation('iChannel2'), 2);
163
198
  glContext.uniform1f(uniformLocation('iTime'), time);
164
199
  glContext.uniform3f(uniformLocation('iResolution'), mainCanvas.width, mainCanvas.height, 1);
165
200
  glContext.drawArrays(glContext.TRIANGLE_STRIP, 0, 4);
166
201
 
167
202
  if (feedbackTexture)
168
203
  {
169
- // pass glCanvas back to overlay texture
204
+ // keep this frame's output for the next one, then hand the first texture unit back to the engine
170
205
  glContext.texImage2D(glContext.TEXTURE_2D, 0, glContext.RGBA, glContext.RGBA, glContext.UNSIGNED_BYTE, glCanvas);
206
+ glContext.activeTexture(glContext.TEXTURE0);
171
207
  }
172
208
 
173
- // restore default so subsequent dynamic texture uploads aren't flipped
209
+ // the depth leaves the third unit for whatever draws next
210
+ glContext.activeTexture(glContext.TEXTURE2);
211
+ glContext.bindTexture(glContext.TEXTURE_2D, null);
212
+ glContext.activeTexture(glContext.TEXTURE0);
213
+
214
+ // restore defaults so subsequent dynamic texture uploads aren't flipped or premultiplied
174
215
  glContext.pixelStorei(glContext.UNPACK_FLIP_Y_WEBGL, false);
216
+ glContext.pixelStorei(glContext.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
217
+
218
+ // bind back the texture the 2D batch thinks is bound, a plugin drawing after this one uses it
219
+ if (glActiveTexture)
220
+ glContext.bindTexture(glContext.TEXTURE_2D, glActiveTexture);
175
221
 
176
222
  // force it to set instanced mode
177
223
  glSetInstancedMode(true);
@@ -181,6 +227,31 @@ class PostProcessPlugin
181
227
 
182
228
  ///////////////////////////////////////////////////////////////////////////////
183
229
 
230
+ // the fragment shader of the post process pass around its mainImage snippet: the frame on iChannel0, the last output
231
+ // on iChannel1 with a feedback texture, and the 3D depth on iChannel2 when render3D.depthTexture is on, read with
232
+ // sceneDepth(uv), the distance from the camera along its view in world units, uv 0 to 1 across the screen
233
+ function postProcessFragmentSource(shaderCode)
234
+ {
235
+ return '#version 300 es\n' + // specify GLSL ES version
236
+ 'precision highp float;'+ // use highp for accuracy
237
+ 'uniform sampler2D iChannel0;'+ // input texture
238
+ 'uniform sampler2D iChannel1;'+ // the previous frame's output, when feedbackTexture is set
239
+ 'uniform sampler2D iChannel2;'+ // the 3D depth, when render3D.depthTexture is on
240
+ 'uniform vec3 iResolution;'+ // size of output texture
241
+ 'uniform float iTime;'+ // time
242
+ 'uniform vec3 iDepthRange;'+ // the camera's near, its far or 0 for none, and 1 when orthographic
243
+ 'out vec4 c;'+ // out color
244
+ // the depth texture's value back to a distance, as the camera's projection put it there
245
+ 'float sceneDepth(vec2 uv){'+
246
+ 'float d=texture(iChannel2,uv).r*2.-1.,n=iDepthRange.x,f=iDepthRange.y;'+
247
+ 'return iDepthRange.z>0.?(d*(f-n)+f+n)/2.:f>0.?2.*n*f/(f+n-d*(f-n)):2.*n/(1.-d);}'+
248
+ '\n' + shaderCode + '\n'+ // insert custom shader code
249
+ 'void main(){'+ // shader entry point
250
+ 'mainImage(c,gl_FragCoord.xy);'+ // call post process function
251
+ 'c.a=1.;'+ // always use full alpha
252
+ '}'; // end of shader
253
+ }
254
+
184
255
  /**
185
256
  * Shader code for a bloom effect, the bright parts of the image blurred back over it
186
257
  * - Pass it to PostProcessPlugin, or edit the string to build an effect on top of it
@@ -232,6 +303,7 @@ function postProcessBloomShader(threshold=.6, strength=1, size=6)
232
303
  * @param {number} [strength] - How much glow to add
233
304
  * @param {number} [size] - How far the glow spreads in pixels
234
305
  * @param {boolean} [includeMainCanvas] - Glow the 2D canvas too, off by default so HUD text stays crisp
306
+ * (a HUD drawn with WebGL in gameRenderPost glows either way, draw it with useWebGL=false)
235
307
  * @return {PostProcessPlugin}
236
308
  * @memberof PostProcess
237
309
  * @example