littlejsengine 1.19.3 → 1.20.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 (50) hide show
  1. package/FAQ.md +841 -820
  2. package/README.md +29 -25
  3. package/dist/littlejs.d.ts +2455 -935
  4. package/dist/littlejs.esm.js +30344 -21110
  5. package/dist/littlejs.esm.min.js +4 -3
  6. package/dist/littlejs.js +30259 -21052
  7. package/dist/littlejs.min.js +2 -2
  8. package/dist/littlejs.release.js +26567 -20455
  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 +740 -0
  14. package/plugins/jsconfig.json +19 -0
  15. package/plugins/lightSystem.js +719 -332
  16. package/plugins/math3d.js +58 -17
  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 +15 -0
  21. package/plugins/postProcess.js +56 -13
  22. package/plugins/render3d.js +1643 -1577
  23. package/plugins/render3dDebug.js +109 -0
  24. package/plugins/render3dExtras.js +1754 -0
  25. package/plugins/render3dVoxels.js +502 -0
  26. package/plugins/textureSheet.js +496 -458
  27. package/plugins/threejs.js +183 -163
  28. package/plugins/tweakables.js +411 -0
  29. package/plugins/tweenSystem.js +263 -145
  30. package/plugins/uiSystem.js +2024 -1687
  31. package/plugins/zzfxm.js +159 -159
  32. package/src/engine.js +191 -75
  33. package/src/engineAudio.js +229 -125
  34. package/src/engineBuild.mjs +289 -256
  35. package/src/engineDebug.js +912 -742
  36. package/src/engineDraw.js +295 -193
  37. package/src/engineEditor.js +2431 -0
  38. package/src/engineExport.js +12 -0
  39. package/src/engineInput.js +1462 -1293
  40. package/src/engineMath.js +1274 -1252
  41. package/src/engineObject.js +194 -80
  42. package/src/engineParticles.js +583 -532
  43. package/src/engineRelease.js +67 -45
  44. package/src/engineSettings.js +77 -29
  45. package/src/engineTileLayer.js +995 -741
  46. package/src/engineUtilities.js +19 -13
  47. package/src/engineWebGL.js +239 -82
  48. package/src/jsconfig.json +17 -13
  49. package/plugins/box2d.wasm.js +0 -630
  50. package/plugins/box2d.wasm.wasm +0 -0
@@ -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
@@ -81,6 +96,7 @@ class PostProcessPlugin
81
96
  '#version 300 es\n' + // specify GLSL ES version
82
97
  'precision highp float;'+ // use highp for accuracy
83
98
  'uniform sampler2D iChannel0;'+ // input texture
99
+ 'uniform sampler2D iChannel1;'+ // the previous frame's output, when feedbackTexture is set
84
100
  'uniform vec3 iResolution;'+ // size of output texture
85
101
  'uniform float iTime;'+ // time
86
102
  'out vec4 c;'+ // out color
@@ -106,6 +122,7 @@ class PostProcessPlugin
106
122
  {
107
123
  postProcess.shader = undefined;
108
124
  postProcess.texture = undefined;
125
+ postProcess.feedbackTexture = undefined;
109
126
  LOG('PostProcessPlugin: WebGL context lost');
110
127
  }
111
128
  function postProcessContextRestored()
@@ -117,6 +134,13 @@ class PostProcessPlugin
117
134
  {
118
135
  if (headlessMode || !glEnable) return;
119
136
 
137
+ // made now if WebGL was off when the plugin was made, or when a lost context came back
138
+ if (!postProcess.shader)
139
+ {
140
+ if (glContext.isContextLost()) return;
141
+ initPostProcess();
142
+ }
143
+
120
144
  // clear out the buffer
121
145
  glFlush();
122
146
 
@@ -128,6 +152,9 @@ class PostProcessPlugin
128
152
  glContext.useProgram(postProcess.shader);
129
153
  glContext.bindVertexArray(postProcess.vao);
130
154
  glContext.pixelStorei(glContext.UNPACK_FLIP_Y_WEBGL, true);
155
+ // upload the canvas the way it shows, premultiplied, since the shader writes full alpha; unpremultiplied
156
+ // a see-through pixel would come out at its full brightness instead of faded over the background
157
+ glContext.pixelStorei(glContext.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);
131
158
  glContext.disable(glContext.BLEND);
132
159
 
133
160
  // setup texture
@@ -141,37 +168,52 @@ class PostProcessPlugin
141
168
  workCanvas.height = mainCanvas.height;
142
169
  glCopyToContext(workContext);
143
170
  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);
171
+ // clear the main canvas with clearRect, resizing it would also
172
+ // reset the context state (smoothing, line caps) for anything
173
+ // drawn after this and reallocate the canvas every frame
174
+ mainContext.save();
175
+ mainContext.setTransform(1, 0, 0, 1, 0, 0);
176
+ mainContext.clearRect(0, 0, mainCanvas.width, mainCanvas.height);
177
+ mainContext.restore();
150
178
 
151
179
  // copy work canvas to texture
152
180
  glContext.texImage2D(glContext.TEXTURE_2D, 0, glContext.RGBA, glContext.RGBA, glContext.UNSIGNED_BYTE, workCanvas);
153
181
  }
154
- else if (!feedbackTexture)
182
+ else
155
183
  {
156
184
  // copy glCanvas to texture
157
185
  glContext.texImage2D(glContext.TEXTURE_2D, 0, glContext.RGBA, glContext.RGBA, glContext.UNSIGNED_BYTE, glCanvas);
158
186
  }
159
187
 
188
+ // the previous frame's output, on the second texture unit
189
+ if (feedbackTexture)
190
+ {
191
+ glContext.activeTexture(glContext.TEXTURE1);
192
+ glContext.bindTexture(glContext.TEXTURE_2D, postProcess.feedbackTexture);
193
+ }
194
+
160
195
  // set uniforms and draw
161
- const uniformLocation = (name)=>glContext.getUniformLocation(postProcess.shader, name);
196
+ const uniformLocation = (name)=>glUniformLocation(postProcess.shader, name);
162
197
  glContext.uniform1i(uniformLocation('iChannel0'), 0);
198
+ glContext.uniform1i(uniformLocation('iChannel1'), 1);
163
199
  glContext.uniform1f(uniformLocation('iTime'), time);
164
200
  glContext.uniform3f(uniformLocation('iResolution'), mainCanvas.width, mainCanvas.height, 1);
165
201
  glContext.drawArrays(glContext.TRIANGLE_STRIP, 0, 4);
166
202
 
167
203
  if (feedbackTexture)
168
204
  {
169
- // pass glCanvas back to overlay texture
205
+ // keep this frame's output for the next one, then hand the first texture unit back to the engine
170
206
  glContext.texImage2D(glContext.TEXTURE_2D, 0, glContext.RGBA, glContext.RGBA, glContext.UNSIGNED_BYTE, glCanvas);
207
+ glContext.activeTexture(glContext.TEXTURE0);
171
208
  }
172
209
 
173
- // restore default so subsequent dynamic texture uploads aren't flipped
210
+ // restore defaults so subsequent dynamic texture uploads aren't flipped or premultiplied
174
211
  glContext.pixelStorei(glContext.UNPACK_FLIP_Y_WEBGL, false);
212
+ glContext.pixelStorei(glContext.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
213
+
214
+ // bind back the texture the 2D batch thinks is bound, a plugin drawing after this one uses it
215
+ if (glActiveTexture)
216
+ glContext.bindTexture(glContext.TEXTURE_2D, glActiveTexture);
175
217
 
176
218
  // force it to set instanced mode
177
219
  glSetInstancedMode(true);
@@ -232,6 +274,7 @@ function postProcessBloomShader(threshold=.6, strength=1, size=6)
232
274
  * @param {number} [strength] - How much glow to add
233
275
  * @param {number} [size] - How far the glow spreads in pixels
234
276
  * @param {boolean} [includeMainCanvas] - Glow the 2D canvas too, off by default so HUD text stays crisp
277
+ * (a HUD drawn with WebGL in gameRenderPost glows either way, draw it with useWebGL=false)
235
278
  * @return {PostProcessPlugin}
236
279
  * @memberof PostProcess
237
280
  * @example