p5 2.0.0 → 2.0.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.
Files changed (188) hide show
  1. package/{src → dist}/accessibility/color_namer.js +48 -3
  2. package/{src → dist}/accessibility/describe.js +2 -2
  3. package/{src → dist}/accessibility/gridOutput.js +2 -2
  4. package/dist/accessibility/index.js +60 -0
  5. package/{src → dist}/accessibility/outputs.js +2 -2
  6. package/{src → dist}/accessibility/textOutput.js +2 -2
  7. package/dist/app.js +120 -0
  8. package/{src → dist}/color/color_conversion.js +48 -10
  9. package/{src → dist}/color/color_spaces/hsb.js +3 -1
  10. package/dist/color/creating_reading.js +3 -0
  11. package/dist/color/index.js +13 -0
  12. package/dist/color/p5.Color.culori.js +1 -0
  13. package/dist/color/p5.Color.js +3 -0
  14. package/{src → dist}/color/setting.js +9 -6
  15. package/{src/core/constants.js → dist/constants-C-g_eAdC.js} +266 -130
  16. package/{src → dist}/core/States.js +3 -1
  17. package/dist/core/constants.js +1 -0
  18. package/{src → dist}/core/environment.js +7 -6
  19. package/{src → dist}/core/friendly_errors/browser_errors.js +1 -1
  20. package/{src → dist}/core/friendly_errors/fes_core.js +14 -44
  21. package/{src → dist}/core/friendly_errors/file_errors.js +6 -3
  22. package/dist/core/friendly_errors/index.js +23 -0
  23. package/dist/core/friendly_errors/param_validator.js +5455 -0
  24. package/{src → dist}/core/friendly_errors/sketch_reader.js +50 -4
  25. package/{src → dist}/core/friendly_errors/sketch_verifier.js +6 -6
  26. package/{src → dist}/core/friendly_errors/stacktrace.js +3 -5
  27. package/{src → dist}/core/friendly_errors/validate_params.js +50 -41
  28. package/{src → dist}/core/helpers.js +9 -6
  29. package/dist/core/init.js +105 -0
  30. package/dist/core/internationalization.js +302 -0
  31. package/dist/core/legacy.js +73 -0
  32. package/dist/core/main.js +44 -0
  33. package/dist/core/noop.js +3 -0
  34. package/dist/core/p5.Graphics.js +40 -0
  35. package/dist/core/p5.Renderer.js +11 -0
  36. package/dist/core/p5.Renderer2D.js +44 -0
  37. package/dist/core/reference.js +1 -0
  38. package/dist/core/rendering.js +40 -0
  39. package/{src → dist}/core/structure.js +3 -3
  40. package/{src → dist}/core/transform.js +2 -2
  41. package/{src/color/creating_reading.js → dist/creating_reading-D4AAKRbx.js} +841 -13
  42. package/{src → dist}/data/index.js +3 -1
  43. package/{src → dist}/data/local_storage.js +2 -8
  44. package/{src → dist}/dom/dom.js +11 -5
  45. package/dist/dom/index.js +18 -0
  46. package/{src → dist}/dom/p5.Element.js +14 -12
  47. package/{src → dist}/dom/p5.File.js +4 -4
  48. package/{src → dist}/dom/p5.MediaElement.js +10 -4
  49. package/{src → dist}/events/acceleration.js +2 -2
  50. package/{src → dist}/events/index.js +3 -1
  51. package/{src → dist}/events/keyboard.js +14 -11
  52. package/{src → dist}/events/pointer.js +16 -17
  53. package/dist/image/const.js +9 -0
  54. package/{src → dist}/image/filterRenderer2D.js +57 -37
  55. package/{src → dist}/image/filters.js +1 -3
  56. package/dist/image/image.js +40 -0
  57. package/dist/image/index.js +51 -0
  58. package/dist/image/loading_displaying.js +40 -0
  59. package/dist/image/p5.Image.js +11 -0
  60. package/{src → dist}/image/pixels.js +4 -3
  61. package/{src → dist}/io/csv.js +72 -70
  62. package/dist/io/files.js +40 -0
  63. package/dist/io/index.js +51 -0
  64. package/{src → dist}/io/p5.Table.js +6 -6
  65. package/{src → dist}/io/p5.TableRow.js +3 -4
  66. package/{src → dist}/io/p5.XML.js +2 -5
  67. package/{src → dist}/io/utilities.js +1 -1
  68. package/{src/core/p5.Renderer2D.js → dist/main-s72KWcUy.js} +735 -57
  69. package/{src → dist}/math/Matrices/Matrix.js +10 -8
  70. package/{src → dist}/math/Matrices/MatrixInterface.js +5 -3
  71. package/{src → dist}/math/Matrices/MatrixNumjs.js +12 -26
  72. package/{src → dist}/math/calculation.js +2 -2
  73. package/{src → dist}/math/index.js +6 -3
  74. package/{src → dist}/math/math.js +2 -2
  75. package/{src → dist}/math/noise.js +2 -2
  76. package/{src → dist}/math/p5.Matrix.js +7 -4
  77. package/{src → dist}/math/p5.Vector.js +6 -6
  78. package/{src → dist}/math/random.js +2 -2
  79. package/{src → dist}/math/trigonometry.js +16 -15
  80. package/{src/image/p5.Image.js → dist/p5.Renderer-CwAYZOC2.js} +390 -19
  81. package/dist/rendering--aAe5aq3.js +24925 -0
  82. package/{src → dist}/shape/2d_primitives.js +18 -17
  83. package/{src → dist}/shape/attributes.js +18 -17
  84. package/{src → dist}/shape/curves.js +2 -2
  85. package/{src → dist}/shape/custom_shapes.js +44 -64
  86. package/{src → dist}/shape/index.js +10 -2
  87. package/{src → dist}/shape/vertex.js +2 -3
  88. package/dist/type/index.js +25 -0
  89. package/{src → dist}/type/lib/Typr.js +76 -94
  90. package/{src → dist}/type/p5.Font.js +37 -61
  91. package/{src → dist}/type/textCore.js +34 -57
  92. package/{src → dist}/type/unicodeRanges.js +3 -1
  93. package/{src → dist}/utilities/conversion.js +2 -2
  94. package/{src → dist}/utilities/index.js +3 -1
  95. package/{src → dist}/utilities/time_date.js +6 -7
  96. package/{src → dist}/utilities/utility_functions.js +2 -2
  97. package/dist/webgl/3d_primitives.js +40 -0
  98. package/{src → dist}/webgl/GeometryBufferCache.js +3 -1
  99. package/{src → dist}/webgl/GeometryBuilder.js +12 -8
  100. package/{src → dist}/webgl/ShaderGenerator.js +79 -82
  101. package/{src → dist}/webgl/ShapeBuilder.js +26 -23
  102. package/dist/webgl/index.js +76 -0
  103. package/{src → dist}/webgl/interaction.js +7 -6
  104. package/dist/webgl/light.js +40 -0
  105. package/{src → dist}/webgl/loading.js +45 -12
  106. package/dist/webgl/material.js +40 -0
  107. package/dist/webgl/p5.Camera.js +40 -0
  108. package/{src → dist}/webgl/p5.DataArray.js +3 -5
  109. package/dist/webgl/p5.Framebuffer.js +40 -0
  110. package/{src → dist}/webgl/p5.Geometry.js +12 -15
  111. package/{src → dist}/webgl/p5.Quat.js +5 -4
  112. package/{src → dist}/webgl/p5.RenderBuffer.js +2 -3
  113. package/dist/webgl/p5.RendererGL.js +40 -0
  114. package/dist/webgl/p5.Shader.js +40 -0
  115. package/dist/webgl/p5.Texture.js +40 -0
  116. package/{src → dist}/webgl/text.js +51 -9
  117. package/lib/p5.esm.js +102 -48
  118. package/lib/p5.js +102 -48
  119. package/lib/p5.min.js +1 -1
  120. package/package.json +17 -16
  121. package/translations/dev.js +6 -6
  122. package/translations/index.js +1 -1
  123. package/src/README.md +0 -27
  124. package/src/accessibility/index.js +0 -13
  125. package/src/app.js +0 -61
  126. package/src/color/index.js +0 -9
  127. package/src/color/p5.Color.culori.js +0 -66
  128. package/src/color/p5.Color.js +0 -851
  129. package/src/core/README.md +0 -91
  130. package/src/core/friendly_errors/index.js +0 -13
  131. package/src/core/friendly_errors/param_validator.js +0 -561
  132. package/src/core/init.js +0 -58
  133. package/src/core/internationalization.js +0 -195
  134. package/src/core/legacy.js +0 -29
  135. package/src/core/main.js +0 -689
  136. package/src/core/noop.js +0 -1
  137. package/src/core/p5.Graphics.js +0 -696
  138. package/src/core/p5.Renderer.js +0 -408
  139. package/src/core/reference.js +0 -2060
  140. package/src/core/rendering.js +0 -697
  141. package/src/dom/index.js +0 -11
  142. package/src/image/const.js +0 -6
  143. package/src/image/image.js +0 -731
  144. package/src/image/index.js +0 -15
  145. package/src/image/loading_displaying.js +0 -1431
  146. package/src/io/files.js +0 -2210
  147. package/src/io/index.js +0 -11
  148. package/src/math/README.md +0 -40
  149. package/src/type/index.js +0 -9
  150. package/src/webgl/3d_primitives.js +0 -2741
  151. package/src/webgl/index.js +0 -37
  152. package/src/webgl/light.js +0 -1851
  153. package/src/webgl/material.js +0 -3854
  154. package/src/webgl/p5.Camera.js +0 -4010
  155. package/src/webgl/p5.Framebuffer.js +0 -1865
  156. package/src/webgl/p5.RendererGL.js +0 -2867
  157. package/src/webgl/p5.Shader.js +0 -1505
  158. package/src/webgl/p5.Texture.js +0 -541
  159. package/src/webgl/shaders/basic.frag +0 -6
  160. package/src/webgl/shaders/filters/base.frag +0 -22
  161. package/src/webgl/shaders/filters/base.vert +0 -19
  162. package/src/webgl/shaders/filters/blur.frag +0 -60
  163. package/src/webgl/shaders/filters/default.vert +0 -18
  164. package/src/webgl/shaders/filters/dilate.frag +0 -39
  165. package/src/webgl/shaders/filters/erode.frag +0 -39
  166. package/src/webgl/shaders/filters/gray.frag +0 -16
  167. package/src/webgl/shaders/filters/invert.frag +0 -15
  168. package/src/webgl/shaders/filters/opaque.frag +0 -12
  169. package/src/webgl/shaders/filters/posterize.frag +0 -29
  170. package/src/webgl/shaders/filters/threshold.frag +0 -23
  171. package/src/webgl/shaders/font.frag +0 -216
  172. package/src/webgl/shaders/font.vert +0 -44
  173. package/src/webgl/shaders/imageLight.vert +0 -33
  174. package/src/webgl/shaders/imageLightDiffused.frag +0 -82
  175. package/src/webgl/shaders/imageLightSpecular.frag +0 -134
  176. package/src/webgl/shaders/light.vert +0 -37
  177. package/src/webgl/shaders/light_texture.frag +0 -26
  178. package/src/webgl/shaders/lighting.glsl +0 -227
  179. package/src/webgl/shaders/line.frag +0 -74
  180. package/src/webgl/shaders/line.vert +0 -294
  181. package/src/webgl/shaders/normal.frag +0 -6
  182. package/src/webgl/shaders/normal.vert +0 -72
  183. package/src/webgl/shaders/phong.frag +0 -84
  184. package/src/webgl/shaders/phong.vert +0 -87
  185. package/src/webgl/shaders/point.frag +0 -29
  186. package/src/webgl/shaders/point.vert +0 -19
  187. package/src/webgl/shaders/sphereMapping.frag +0 -26
  188. package/src/webgl/shaders/webgl2Compatibility.glsl +0 -34
@@ -1,1865 +0,0 @@
1
- /**
2
- * @module Rendering
3
- * @requires constants
4
- */
5
-
6
- import * as constants from '../core/constants';
7
- import { RGB, RGBA } from '../color/creating_reading';
8
- import { checkWebGLCapabilities } from './p5.Texture';
9
- import { readPixelsWebGL, readPixelWebGL } from './p5.RendererGL';
10
- import { Camera } from './p5.Camera';
11
- import { Texture } from './p5.Texture';
12
- import { Image } from '../image/p5.Image';
13
-
14
- const constrain = (n, low, high) => Math.max(Math.min(n, high), low);
15
-
16
- class FramebufferCamera extends Camera {
17
- constructor(framebuffer) {
18
- super(framebuffer.renderer);
19
- this.fbo = framebuffer;
20
-
21
- // WebGL textures are upside-down compared to textures that come from
22
- // images and graphics. Framebuffer cameras need to invert their y
23
- // axes when being rendered to so that the texture comes out rightway up
24
- // when read in shaders or image().
25
- this.yScale = -1;
26
- }
27
-
28
- _computeCameraDefaultSettings() {
29
- super._computeCameraDefaultSettings();
30
- this.defaultAspectRatio = this.fbo.width / this.fbo.height;
31
- this.defaultCameraFOV =
32
- 2 * Math.atan(this.fbo.height / 2 / this.defaultEyeZ);
33
- }
34
- }
35
-
36
- class FramebufferTexture {
37
- constructor(framebuffer, property) {
38
- this.framebuffer = framebuffer;
39
- this.property = property;
40
- }
41
-
42
- get width() {
43
- return this.framebuffer.width * this.framebuffer.density;
44
- }
45
-
46
- get height() {
47
- return this.framebuffer.height * this.framebuffer.density;
48
- }
49
-
50
- rawTexture() {
51
- return this.framebuffer[this.property];
52
- }
53
- }
54
-
55
- class Framebuffer {
56
- constructor(renderer, settings = {}) {
57
- this.renderer = renderer;
58
- this.renderer.framebuffers.add(this);
59
-
60
- this._isClipApplied = false;
61
-
62
- this.pixels = [];
63
-
64
- this.format = settings.format || constants.UNSIGNED_BYTE;
65
- this.channels = settings.channels || (
66
- this.renderer._pInst._glAttributes.alpha
67
- ? RGBA
68
- : RGB
69
- );
70
- this.useDepth = settings.depth === undefined ? true : settings.depth;
71
- this.depthFormat = settings.depthFormat || constants.FLOAT;
72
- this.textureFiltering = settings.textureFiltering || constants.LINEAR;
73
- if (settings.antialias === undefined) {
74
- this.antialiasSamples = this.renderer._pInst._glAttributes.antialias
75
- ? 2
76
- : 0;
77
- } else if (typeof settings.antialias === 'number') {
78
- this.antialiasSamples = settings.antialias;
79
- } else {
80
- this.antialiasSamples = settings.antialias ? 2 : 0;
81
- }
82
- this.antialias = this.antialiasSamples > 0;
83
- if (this.antialias && this.renderer.webglVersion !== constants.WEBGL2) {
84
- console.warn('Antialiasing is unsupported in a WebGL 1 context');
85
- this.antialias = false;
86
- }
87
- this.density = settings.density || this.renderer._pixelDensity;
88
- const gl = this.renderer.GL;
89
- this.gl = gl;
90
- if (settings.width && settings.height) {
91
- const dimensions =
92
- this.renderer._adjustDimensions(settings.width, settings.height);
93
- this.width = dimensions.adjustedWidth;
94
- this.height = dimensions.adjustedHeight;
95
- this._autoSized = false;
96
- } else {
97
- if ((settings.width === undefined) !== (settings.height === undefined)) {
98
- console.warn(
99
- 'Please supply both width and height for a framebuffer to give it a ' +
100
- 'size. Only one was given, so the framebuffer will match the size ' +
101
- 'of its canvas.'
102
- );
103
- }
104
- this.width = this.renderer.width;
105
- this.height = this.renderer.height;
106
- this._autoSized = true;
107
- }
108
- this._checkIfFormatsAvailable();
109
-
110
- if (settings.stencil && !this.useDepth) {
111
- console.warn('A stencil buffer can only be used if also using depth. Since the framebuffer has no depth buffer, the stencil buffer will be ignored.');
112
- }
113
- this.useStencil = this.useDepth &&
114
- (settings.stencil === undefined ? true : settings.stencil);
115
-
116
- this.framebuffer = gl.createFramebuffer();
117
- if (!this.framebuffer) {
118
- throw new Error('Unable to create a framebuffer');
119
- }
120
- if (this.antialias) {
121
- this.aaFramebuffer = gl.createFramebuffer();
122
- if (!this.aaFramebuffer) {
123
- throw new Error('Unable to create a framebuffer for antialiasing');
124
- }
125
- }
126
-
127
- this._recreateTextures();
128
-
129
- const prevCam = this.renderer.states.curCamera;
130
- this.defaultCamera = this.createCamera();
131
- this.filterCamera = this.createCamera();
132
- this.renderer.states.setValue('curCamera', prevCam);
133
-
134
- this.draw(() => this.renderer.clear());
135
- }
136
-
137
- /**
138
- * Resizes the framebuffer to a given width and height.
139
- *
140
- * The parameters, `width` and `height`, set the dimensions of the
141
- * framebuffer. For example, calling `myBuffer.resize(300, 500)` resizes
142
- * the framebuffer to 300×500 pixels, then sets `myBuffer.width` to 300
143
- * and `myBuffer.height` 500.
144
- *
145
- * @param {Number} width width of the framebuffer.
146
- * @param {Number} height height of the framebuffer.
147
- *
148
- * @example
149
- * <div>
150
- * <code>
151
- * let myBuffer;
152
- *
153
- * function setup() {
154
- * createCanvas(100, 100, WEBGL);
155
- *
156
- * // Create a p5.Framebuffer object.
157
- * myBuffer = createFramebuffer();
158
- *
159
- * describe('A multicolor sphere on a white surface. The image grows larger or smaller when the user moves the mouse, revealing a gray background.');
160
- * }
161
- *
162
- * function draw() {
163
- * background(200);
164
- *
165
- * // Draw to the p5.Framebuffer object.
166
- * myBuffer.begin();
167
- * background(255);
168
- * normalMaterial();
169
- * sphere(20);
170
- * myBuffer.end();
171
- *
172
- * // Display the p5.Framebuffer object.
173
- * image(myBuffer, -50, -50);
174
- * }
175
- *
176
- * // Resize the p5.Framebuffer object when the
177
- * // user moves the mouse.
178
- * function mouseMoved() {
179
- * myBuffer.resize(mouseX, mouseY);
180
- * }
181
- * </code>
182
- * </div>
183
- */
184
- resize(width, height) {
185
- this._autoSized = false;
186
- const dimensions =
187
- this.renderer._adjustDimensions(width, height);
188
- width = dimensions.adjustedWidth;
189
- height = dimensions.adjustedHeight;
190
- this.width = width;
191
- this.height = height;
192
- this._handleResize();
193
- }
194
-
195
- /**
196
- * Sets the framebuffer's pixel density or returns its current density.
197
- *
198
- * Computer displays are grids of little lights called pixels. A display's
199
- * pixel density describes how many pixels it packs into an area. Displays
200
- * with smaller pixels have a higher pixel density and create sharper
201
- * images.
202
- *
203
- * The parameter, `density`, is optional. If a number is passed, as in
204
- * `myBuffer.pixelDensity(1)`, it sets the framebuffer's pixel density. By
205
- * default, the framebuffer's pixel density will match that of the canvas
206
- * where it was created. All canvases default to match the display's pixel
207
- * density.
208
- *
209
- * Calling `myBuffer.pixelDensity()` without an argument returns its current
210
- * pixel density.
211
- *
212
- * @param {Number} [density] pixel density to set.
213
- * @returns {Number} current pixel density.
214
- *
215
- * @example
216
- * <div>
217
- * <code>
218
- * let myBuffer;
219
- *
220
- * function setup() {
221
- * createCanvas(100, 100, WEBGL);
222
- *
223
- * // Create a p5.Framebuffer object.
224
- * myBuffer = createFramebuffer();
225
- *
226
- * describe("A white circle on a gray canvas. The circle's edge become fuzzy while the user presses and holds the mouse.");
227
- * }
228
- *
229
- * function draw() {
230
- * // Draw to the p5.Framebuffer object.
231
- * myBuffer.begin();
232
- * background(200);
233
- * circle(0, 0, 40);
234
- * myBuffer.end();
235
- *
236
- * // Display the p5.Framebuffer object.
237
- * image(myBuffer, -50, -50);
238
- * }
239
- *
240
- * // Decrease the pixel density when the user
241
- * // presses the mouse.
242
- * function mousePressed() {
243
- * myBuffer.pixelDensity(1);
244
- * }
245
- *
246
- * // Increase the pixel density when the user
247
- * // releases the mouse.
248
- * function mouseReleased() {
249
- * myBuffer.pixelDensity(2);
250
- * }
251
- * </code>
252
- * </div>
253
- *
254
- * <div>
255
- * <code>
256
- * let myBuffer;
257
- * let myFont;
258
- *
259
- * async function setup() {
260
- * // Load a font and create a p5.Font object.
261
- * myFont = await loadFont('assets/inconsolata.otf');
262
- *
263
- * createCanvas(100, 100, WEBGL);
264
- *
265
- * background(200);
266
- *
267
- * // Create a p5.Framebuffer object.
268
- * myBuffer = createFramebuffer();
269
- *
270
- * // Get the p5.Framebuffer object's pixel density.
271
- * let d = myBuffer.pixelDensity();
272
- *
273
- * // Style the text.
274
- * textAlign(CENTER, CENTER);
275
- * textFont(myFont);
276
- * textSize(16);
277
- * fill(0);
278
- *
279
- * // Display the pixel density.
280
- * text(`Density: ${d}`, 0, 0);
281
- *
282
- * describe(`The text "Density: ${d}" written in black on a gray background.`);
283
- * }
284
- * </code>
285
- * </div>
286
- */
287
- pixelDensity(density) {
288
- if (density) {
289
- this._autoSized = false;
290
- this.density = density;
291
- this._handleResize();
292
- } else {
293
- return this.density;
294
- }
295
- }
296
-
297
- /**
298
- * Toggles the framebuffer's autosizing mode or returns the current mode.
299
- *
300
- * By default, the framebuffer automatically resizes to match the canvas
301
- * that created it. Calling `myBuffer.autoSized(false)` disables this
302
- * behavior and calling `myBuffer.autoSized(true)` re-enables it.
303
- *
304
- * Calling `myBuffer.autoSized()` without an argument returns `true` if
305
- * the framebuffer automatically resizes and `false` if not.
306
- *
307
- * @param {Boolean} [autoSized] whether to automatically resize the framebuffer to match the canvas.
308
- * @returns {Boolean} current autosize setting.
309
- *
310
- * @example
311
- * <div>
312
- * <code>
313
- * // Double-click to toggle the autosizing mode.
314
- *
315
- * let myBuffer;
316
- *
317
- * function setup() {
318
- * createCanvas(100, 100, WEBGL);
319
- *
320
- * // Create a p5.Framebuffer object.
321
- * myBuffer = createFramebuffer();
322
- *
323
- * describe('A multicolor sphere on a gray background. The image resizes when the user moves the mouse.');
324
- * }
325
- *
326
- * function draw() {
327
- * background(50);
328
- *
329
- * // Draw to the p5.Framebuffer object.
330
- * myBuffer.begin();
331
- * background(200);
332
- * normalMaterial();
333
- * sphere(width / 4);
334
- * myBuffer.end();
335
- *
336
- * // Display the p5.Framebuffer object.
337
- * image(myBuffer, -width / 2, -height / 2);
338
- * }
339
- *
340
- * // Resize the canvas when the user moves the mouse.
341
- * function mouseMoved() {
342
- * let w = constrain(mouseX, 0, 100);
343
- * let h = constrain(mouseY, 0, 100);
344
- * resizeCanvas(w, h);
345
- * }
346
- *
347
- * // Toggle autoSizing when the user double-clicks.
348
- * // Note: opened an issue to fix(?) this.
349
- * function doubleClicked() {
350
- * let isAuto = myBuffer.autoSized();
351
- * myBuffer.autoSized(!isAuto);
352
- * }
353
- * </code>
354
- * </div>
355
- */
356
- autoSized(autoSized) {
357
- if (autoSized === undefined) {
358
- return this._autoSized;
359
- } else {
360
- this._autoSized = autoSized;
361
- this._handleResize();
362
- }
363
- }
364
-
365
- /**
366
- * Checks the capabilities of the current WebGL environment to see if the
367
- * settings supplied by the user are capable of being fulfilled. If they
368
- * are not, warnings will be logged and the settings will be changed to
369
- * something close that can be fulfilled.
370
- *
371
- * @private
372
- */
373
- _checkIfFormatsAvailable() {
374
- const gl = this.gl;
375
-
376
- if (
377
- this.useDepth &&
378
- this.renderer.webglVersion === constants.WEBGL &&
379
- !gl.getExtension('WEBGL_depth_texture')
380
- ) {
381
- console.warn(
382
- 'Unable to create depth textures in this environment. Falling back ' +
383
- 'to a framebuffer without depth.'
384
- );
385
- this.useDepth = false;
386
- }
387
-
388
- if (
389
- this.useDepth &&
390
- this.renderer.webglVersion === constants.WEBGL &&
391
- this.depthFormat === constants.FLOAT
392
- ) {
393
- console.warn(
394
- 'FLOAT depth format is unavailable in WebGL 1. ' +
395
- 'Defaulting to UNSIGNED_INT.'
396
- );
397
- this.depthFormat = constants.UNSIGNED_INT;
398
- }
399
-
400
- if (![
401
- constants.UNSIGNED_BYTE,
402
- constants.FLOAT,
403
- constants.HALF_FLOAT
404
- ].includes(this.format)) {
405
- console.warn(
406
- 'Unknown Framebuffer format. ' +
407
- 'Please use UNSIGNED_BYTE, FLOAT, or HALF_FLOAT. ' +
408
- 'Defaulting to UNSIGNED_BYTE.'
409
- );
410
- this.format = constants.UNSIGNED_BYTE;
411
- }
412
- if (this.useDepth && ![
413
- constants.UNSIGNED_INT,
414
- constants.FLOAT
415
- ].includes(this.depthFormat)) {
416
- console.warn(
417
- 'Unknown Framebuffer depth format. ' +
418
- 'Please use UNSIGNED_INT or FLOAT. Defaulting to FLOAT.'
419
- );
420
- this.depthFormat = constants.FLOAT;
421
- }
422
-
423
- const support = checkWebGLCapabilities(this.renderer);
424
- if (!support.float && this.format === constants.FLOAT) {
425
- console.warn(
426
- 'This environment does not support FLOAT textures. ' +
427
- 'Falling back to UNSIGNED_BYTE.'
428
- );
429
- this.format = constants.UNSIGNED_BYTE;
430
- }
431
- if (
432
- this.useDepth &&
433
- !support.float &&
434
- this.depthFormat === constants.FLOAT
435
- ) {
436
- console.warn(
437
- 'This environment does not support FLOAT depth textures. ' +
438
- 'Falling back to UNSIGNED_INT.'
439
- );
440
- this.depthFormat = constants.UNSIGNED_INT;
441
- }
442
- if (!support.halfFloat && this.format === constants.HALF_FLOAT) {
443
- console.warn(
444
- 'This environment does not support HALF_FLOAT textures. ' +
445
- 'Falling back to UNSIGNED_BYTE.'
446
- );
447
- this.format = constants.UNSIGNED_BYTE;
448
- }
449
-
450
- if (
451
- this.channels === RGB &&
452
- [constants.FLOAT, constants.HALF_FLOAT].includes(this.format)
453
- ) {
454
- console.warn(
455
- 'FLOAT and HALF_FLOAT formats do not work cross-platform with only ' +
456
- 'RGB channels. Falling back to RGBA.'
457
- );
458
- this.channels = RGBA;
459
- }
460
- }
461
-
462
- /**
463
- * Creates new textures and renderbuffers given the current size of the
464
- * framebuffer.
465
- *
466
- * @private
467
- */
468
- _recreateTextures() {
469
- const gl = this.gl;
470
-
471
- this._updateSize();
472
-
473
- const prevBoundTexture = gl.getParameter(gl.TEXTURE_BINDING_2D);
474
- const prevBoundFramebuffer = gl.getParameter(gl.FRAMEBUFFER_BINDING);
475
-
476
- const colorTexture = gl.createTexture();
477
- if (!colorTexture) {
478
- throw new Error('Unable to create color texture');
479
- }
480
- gl.bindTexture(gl.TEXTURE_2D, colorTexture);
481
- const colorFormat = this._glColorFormat();
482
- gl.texImage2D(
483
- gl.TEXTURE_2D,
484
- 0,
485
- colorFormat.internalFormat,
486
- this.width * this.density,
487
- this.height * this.density,
488
- 0,
489
- colorFormat.format,
490
- colorFormat.type,
491
- null
492
- );
493
- this.colorTexture = colorTexture;
494
- gl.bindFramebuffer(gl.FRAMEBUFFER, this.framebuffer);
495
- gl.framebufferTexture2D(
496
- gl.FRAMEBUFFER,
497
- gl.COLOR_ATTACHMENT0,
498
- gl.TEXTURE_2D,
499
- colorTexture,
500
- 0
501
- );
502
-
503
- if (this.useDepth) {
504
- // Create the depth texture
505
- const depthTexture = gl.createTexture();
506
- if (!depthTexture) {
507
- throw new Error('Unable to create depth texture');
508
- }
509
- const depthFormat = this._glDepthFormat();
510
- gl.bindTexture(gl.TEXTURE_2D, depthTexture);
511
- gl.texImage2D(
512
- gl.TEXTURE_2D,
513
- 0,
514
- depthFormat.internalFormat,
515
- this.width * this.density,
516
- this.height * this.density,
517
- 0,
518
- depthFormat.format,
519
- depthFormat.type,
520
- null
521
- );
522
-
523
- gl.framebufferTexture2D(
524
- gl.FRAMEBUFFER,
525
- this.useStencil ? gl.DEPTH_STENCIL_ATTACHMENT : gl.DEPTH_ATTACHMENT,
526
- gl.TEXTURE_2D,
527
- depthTexture,
528
- 0
529
- );
530
- this.depthTexture = depthTexture;
531
- }
532
-
533
- // Create separate framebuffer for antialiasing
534
- if (this.antialias) {
535
- this.colorRenderbuffer = gl.createRenderbuffer();
536
- gl.bindRenderbuffer(gl.RENDERBUFFER, this.colorRenderbuffer);
537
- gl.renderbufferStorageMultisample(
538
- gl.RENDERBUFFER,
539
- Math.max(
540
- 0,
541
- Math.min(this.antialiasSamples, gl.getParameter(gl.MAX_SAMPLES))
542
- ),
543
- colorFormat.internalFormat,
544
- this.width * this.density,
545
- this.height * this.density
546
- );
547
-
548
- if (this.useDepth) {
549
- const depthFormat = this._glDepthFormat();
550
- this.depthRenderbuffer = gl.createRenderbuffer();
551
- gl.bindRenderbuffer(gl.RENDERBUFFER, this.depthRenderbuffer);
552
- gl.renderbufferStorageMultisample(
553
- gl.RENDERBUFFER,
554
- Math.max(
555
- 0,
556
- Math.min(this.antialiasSamples, gl.getParameter(gl.MAX_SAMPLES))
557
- ),
558
- depthFormat.internalFormat,
559
- this.width * this.density,
560
- this.height * this.density
561
- );
562
- }
563
-
564
- gl.bindFramebuffer(gl.FRAMEBUFFER, this.aaFramebuffer);
565
- gl.framebufferRenderbuffer(
566
- gl.FRAMEBUFFER,
567
- gl.COLOR_ATTACHMENT0,
568
- gl.RENDERBUFFER,
569
- this.colorRenderbuffer
570
- );
571
- if (this.useDepth) {
572
- gl.framebufferRenderbuffer(
573
- gl.FRAMEBUFFER,
574
- this.useStencil ? gl.DEPTH_STENCIL_ATTACHMENT : gl.DEPTH_ATTACHMENT,
575
- gl.RENDERBUFFER,
576
- this.depthRenderbuffer
577
- );
578
- }
579
- }
580
-
581
- if (this.useDepth) {
582
- this.depth = new FramebufferTexture(this, 'depthTexture');
583
- const depthFilter = gl.NEAREST;
584
- this.depthP5Texture = new Texture(
585
- this.renderer,
586
- this.depth,
587
- {
588
- minFilter: depthFilter,
589
- magFilter: depthFilter
590
- }
591
- );
592
- this.renderer.textures.set(this.depth, this.depthP5Texture);
593
- }
594
-
595
- this.color = new FramebufferTexture(this, 'colorTexture');
596
- const filter = this.textureFiltering === constants.LINEAR
597
- ? gl.LINEAR
598
- : gl.NEAREST;
599
- this.colorP5Texture = new Texture(
600
- this.renderer,
601
- this.color,
602
- {
603
- minFilter: filter,
604
- magFilter: filter
605
- }
606
- );
607
- this.renderer.textures.set(this.color, this.colorP5Texture);
608
-
609
- gl.bindTexture(gl.TEXTURE_2D, prevBoundTexture);
610
- gl.bindFramebuffer(gl.FRAMEBUFFER, prevBoundFramebuffer);
611
- }
612
-
613
- /**
614
- * To create a WebGL texture, one needs to supply three pieces of information:
615
- * the type (the data type each channel will be stored as, e.g. int or float),
616
- * the format (the color channels that will each be stored in the previously
617
- * specified type, e.g. rgb or rgba), and the internal format (the specifics
618
- * of how data for each channel, in the aforementioned type, will be packed
619
- * together, such as how many bits to use, e.g. RGBA32F or RGB565.)
620
- *
621
- * The format and channels asked for by the user hint at what these values
622
- * need to be, and the WebGL version affects what options are avaiable.
623
- * This method returns the values for these three properties, given the
624
- * framebuffer's settings.
625
- *
626
- * @private
627
- */
628
- _glColorFormat() {
629
- let type, format, internalFormat;
630
- const gl = this.gl;
631
-
632
- if (this.format === constants.FLOAT) {
633
- type = gl.FLOAT;
634
- } else if (this.format === constants.HALF_FLOAT) {
635
- type = this.renderer.webglVersion === constants.WEBGL2
636
- ? gl.HALF_FLOAT
637
- : gl.getExtension('OES_texture_half_float').HALF_FLOAT_OES;
638
- } else {
639
- type = gl.UNSIGNED_BYTE;
640
- }
641
-
642
- if (this.channels === RGBA) {
643
- format = gl.RGBA;
644
- } else {
645
- format = gl.RGB;
646
- }
647
-
648
- if (this.renderer.webglVersion === constants.WEBGL2) {
649
- // https://webgl2fundamentals.org/webgl/lessons/webgl-data-textures.html
650
- const table = {
651
- [gl.FLOAT]: {
652
- [gl.RGBA]: gl.RGBA32F
653
- // gl.RGB32F is not available in Firefox without an alpha channel
654
- },
655
- [gl.HALF_FLOAT]: {
656
- [gl.RGBA]: gl.RGBA16F
657
- // gl.RGB16F is not available in Firefox without an alpha channel
658
- },
659
- [gl.UNSIGNED_BYTE]: {
660
- [gl.RGBA]: gl.RGBA8, // gl.RGBA4
661
- [gl.RGB]: gl.RGB8 // gl.RGB565
662
- }
663
- };
664
- internalFormat = table[type][format];
665
- } else if (this.format === constants.HALF_FLOAT) {
666
- internalFormat = gl.RGBA;
667
- } else {
668
- internalFormat = format;
669
- }
670
-
671
- return { internalFormat, format, type };
672
- }
673
-
674
- /**
675
- * To create a WebGL texture, one needs to supply three pieces of information:
676
- * the type (the data type each channel will be stored as, e.g. int or float),
677
- * the format (the color channels that will each be stored in the previously
678
- * specified type, e.g. rgb or rgba), and the internal format (the specifics
679
- * of how data for each channel, in the aforementioned type, will be packed
680
- * together, such as how many bits to use, e.g. RGBA32F or RGB565.)
681
- *
682
- * This method takes into account the settings asked for by the user and
683
- * returns values for these three properties that can be used for the
684
- * texture storing depth information.
685
- *
686
- * @private
687
- */
688
- _glDepthFormat() {
689
- let type, format, internalFormat;
690
- const gl = this.gl;
691
-
692
- if (this.useStencil) {
693
- if (this.depthFormat === constants.FLOAT) {
694
- type = gl.FLOAT_32_UNSIGNED_INT_24_8_REV;
695
- } else if (this.renderer.webglVersion === constants.WEBGL2) {
696
- type = gl.UNSIGNED_INT_24_8;
697
- } else {
698
- type = gl.getExtension('WEBGL_depth_texture').UNSIGNED_INT_24_8_WEBGL;
699
- }
700
- } else {
701
- if (this.depthFormat === constants.FLOAT) {
702
- type = gl.FLOAT;
703
- } else {
704
- type = gl.UNSIGNED_INT;
705
- }
706
- }
707
-
708
- if (this.useStencil) {
709
- format = gl.DEPTH_STENCIL;
710
- } else {
711
- format = gl.DEPTH_COMPONENT;
712
- }
713
-
714
- if (this.useStencil) {
715
- if (this.depthFormat === constants.FLOAT) {
716
- internalFormat = gl.DEPTH32F_STENCIL8;
717
- } else if (this.renderer.webglVersion === constants.WEBGL2) {
718
- internalFormat = gl.DEPTH24_STENCIL8;
719
- } else {
720
- internalFormat = gl.DEPTH_STENCIL;
721
- }
722
- } else if (this.renderer.webglVersion === constants.WEBGL2) {
723
- if (this.depthFormat === constants.FLOAT) {
724
- internalFormat = gl.DEPTH_COMPONENT32F;
725
- } else {
726
- internalFormat = gl.DEPTH_COMPONENT24;
727
- }
728
- } else {
729
- internalFormat = gl.DEPTH_COMPONENT;
730
- }
731
-
732
- return { internalFormat, format, type };
733
- }
734
-
735
- /**
736
- * A method that will be called when recreating textures. If the framebuffer
737
- * is auto-sized, it will update its width, height, and density properties.
738
- *
739
- * @private
740
- */
741
- _updateSize() {
742
- if (this._autoSized) {
743
- this.width = this.renderer.width;
744
- this.height = this.renderer.height;
745
- this.density = this.renderer._pixelDensity;
746
- }
747
- }
748
-
749
- /**
750
- * Called when the canvas that the framebuffer is attached to resizes. If the
751
- * framebuffer is auto-sized, it will update its textures to match the new
752
- * size.
753
- *
754
- * @private
755
- */
756
- _canvasSizeChanged() {
757
- if (this._autoSized) {
758
- this._handleResize();
759
- }
760
- }
761
-
762
- /**
763
- * Called when the size of the framebuffer has changed (either by being
764
- * manually updated or from auto-size updates when its canvas changes size.)
765
- * Old textures and renderbuffers will be deleted, and then recreated with the
766
- * new size.
767
- *
768
- * @private
769
- */
770
- _handleResize() {
771
- const oldColor = this.color;
772
- const oldDepth = this.depth;
773
- const oldColorRenderbuffer = this.colorRenderbuffer;
774
- const oldDepthRenderbuffer = this.depthRenderbuffer;
775
-
776
- this._deleteTexture(oldColor);
777
- if (oldDepth) this._deleteTexture(oldDepth);
778
- const gl = this.gl;
779
- if (oldColorRenderbuffer) gl.deleteRenderbuffer(oldColorRenderbuffer);
780
- if (oldDepthRenderbuffer) gl.deleteRenderbuffer(oldDepthRenderbuffer);
781
-
782
- this._recreateTextures();
783
- this.defaultCamera._resize();
784
- }
785
-
786
- /**
787
- * Creates a new
788
- * <a href="#/p5.Camera">p5.Camera</a> object to use with the framebuffer.
789
- *
790
- * The new camera is initialized with a default position `(0, 0, 800)` and a
791
- * default perspective projection. Its properties can be controlled with
792
- * <a href="#/p5.Camera">p5.Camera</a> methods such as `myCamera.lookAt(0, 0, 0)`.
793
- *
794
- * Framebuffer cameras should be created between calls to
795
- * <a href="#/p5.Framebuffer/begin">myBuffer.begin()</a> and
796
- * <a href="#/p5.Framebuffer/end">myBuffer.end()</a> like so:
797
- *
798
- * ```js
799
- * let myCamera;
800
- *
801
- * myBuffer.begin();
802
- *
803
- * // Create the camera for the framebuffer.
804
- * myCamera = myBuffer.createCamera();
805
- *
806
- * myBuffer.end();
807
- * ```
808
- *
809
- * Calling <a href="#/p5/setCamera">setCamera()</a> updates the
810
- * framebuffer's projection using the camera.
811
- * <a href="#/p5/resetMatrix">resetMatrix()</a> must also be called for the
812
- * view to change properly:
813
- *
814
- * ```js
815
- * myBuffer.begin();
816
- *
817
- * // Set the camera for the framebuffer.
818
- * setCamera(myCamera);
819
- *
820
- * // Reset all transformations.
821
- * resetMatrix();
822
- *
823
- * // Draw stuff...
824
- *
825
- * myBuffer.end();
826
- * ```
827
- *
828
- * @returns {p5.Camera} new camera.
829
- *
830
- * @example
831
- * <div>
832
- * <code>
833
- * // Double-click to toggle between cameras.
834
- *
835
- * let myBuffer;
836
- * let cam1;
837
- * let cam2;
838
- * let usingCam1 = true;
839
- *
840
- * function setup() {
841
- * createCanvas(100, 100, WEBGL);
842
- *
843
- * // Create a p5.Framebuffer object.
844
- * myBuffer = createFramebuffer();
845
- *
846
- * // Create the cameras between begin() and end().
847
- * myBuffer.begin();
848
- *
849
- * // Create the first camera.
850
- * // Keep its default settings.
851
- * cam1 = myBuffer.createCamera();
852
- *
853
- * // Create the second camera.
854
- * // Place it at the top-left.
855
- * // Point it at the origin.
856
- * cam2 = myBuffer.createCamera();
857
- * cam2.setPosition(400, -400, 800);
858
- * cam2.lookAt(0, 0, 0);
859
- *
860
- * myBuffer.end();
861
- *
862
- * describe(
863
- * 'A white cube on a gray background. The camera toggles between frontal and aerial views when the user double-clicks.'
864
- * );
865
- * }
866
- *
867
- * function draw() {
868
- * // Draw to the p5.Framebuffer object.
869
- * myBuffer.begin();
870
- * background(200);
871
- *
872
- * // Set the camera.
873
- * if (usingCam1 === true) {
874
- * setCamera(cam1);
875
- * } else {
876
- * setCamera(cam2);
877
- * }
878
- *
879
- * // Reset all transformations.
880
- * resetMatrix();
881
- *
882
- * // Draw the box.
883
- * box();
884
- *
885
- * myBuffer.end();
886
- *
887
- * // Display the p5.Framebuffer object.
888
- * image(myBuffer, -50, -50);
889
- * }
890
- *
891
- * // Toggle the current camera when the user double-clicks.
892
- * function doubleClicked() {
893
- * if (usingCam1 === true) {
894
- * usingCam1 = false;
895
- * } else {
896
- * usingCam1 = true;
897
- * }
898
- * }
899
- * </code>
900
- * </div>
901
- */
902
- createCamera() {
903
- const cam = new FramebufferCamera(this);
904
- cam._computeCameraDefaultSettings();
905
- cam._setDefaultCamera();
906
- return cam;
907
- }
908
-
909
- /**
910
- * Given a raw texture wrapper, delete its stored texture from WebGL memory,
911
- * and remove it from p5's list of active textures.
912
- *
913
- * @param {p5.FramebufferTexture} texture
914
- * @private
915
- */
916
- _deleteTexture(texture) {
917
- const gl = this.gl;
918
- gl.deleteTexture(texture.rawTexture());
919
-
920
- this.renderer.textures.delete(texture);
921
- }
922
-
923
- /**
924
- * Deletes the framebuffer from GPU memory.
925
- *
926
- * Calling `myBuffer.remove()` frees the GPU memory used by the framebuffer.
927
- * The framebuffer also uses a bit of memory on the CPU which can be freed
928
- * like so:
929
- *
930
- * ```js
931
- * // Delete the framebuffer from GPU memory.
932
- * myBuffer.remove();
933
- *
934
- * // Delete the framebuffer from CPU memory.
935
- * myBuffer = undefined;
936
- * ```
937
- *
938
- * Note: All variables that reference the framebuffer must be assigned
939
- * the value `undefined` to delete the framebuffer from CPU memory. If any
940
- * variable still refers to the framebuffer, then it won't be garbage
941
- * collected.
942
- *
943
- * @example
944
- * <div>
945
- * <code>
946
- * // Double-click to remove the p5.Framebuffer object.
947
- *
948
- * let myBuffer;
949
- *
950
- * function setup() {
951
- * createCanvas(100, 100, WEBGL);
952
- *
953
- * // Create an options object.
954
- * let options = { width: 60, height: 60 };
955
- *
956
- * // Create a p5.Framebuffer object and
957
- * // configure it using options.
958
- * myBuffer = createFramebuffer(options);
959
- *
960
- * describe('A white circle at the center of a dark gray square disappears when the user double-clicks.');
961
- * }
962
- *
963
- * function draw() {
964
- * background(200);
965
- *
966
- * // Display the p5.Framebuffer object if
967
- * // it's available.
968
- * if (myBuffer) {
969
- * // Draw to the p5.Framebuffer object.
970
- * myBuffer.begin();
971
- * background(100);
972
- * circle(0, 0, 20);
973
- * myBuffer.end();
974
- *
975
- * image(myBuffer, -30, -30);
976
- * }
977
- * }
978
- *
979
- * // Remove the p5.Framebuffer object when the
980
- * // the user double-clicks.
981
- * function doubleClicked() {
982
- * // Delete the framebuffer from GPU memory.
983
- * myBuffer.remove();
984
- *
985
- * // Delete the framebuffer from CPU memory.
986
- * myBuffer = undefined;
987
- * }
988
- * </code>
989
- * </div>
990
- */
991
- remove() {
992
- const gl = this.gl;
993
- this._deleteTexture(this.color);
994
- if (this.depth) this._deleteTexture(this.depth);
995
- gl.deleteFramebuffer(this.framebuffer);
996
- if (this.aaFramebuffer) {
997
- gl.deleteFramebuffer(this.aaFramebuffer);
998
- }
999
- if (this.depthRenderbuffer) {
1000
- gl.deleteRenderbuffer(this.depthRenderbuffer);
1001
- }
1002
- if (this.colorRenderbuffer) {
1003
- gl.deleteRenderbuffer(this.colorRenderbuffer);
1004
- }
1005
- this.renderer.framebuffers.delete(this);
1006
- }
1007
-
1008
- /**
1009
- * Begins drawing shapes to the framebuffer.
1010
- *
1011
- * `myBuffer.begin()` and <a href="#/p5.Framebuffer/end">myBuffer.end()</a>
1012
- * allow shapes to be drawn to the framebuffer. `myBuffer.begin()` begins
1013
- * drawing to the framebuffer and
1014
- * <a href="#/p5.Framebuffer/end">myBuffer.end()</a> stops drawing to the
1015
- * framebuffer. Changes won't be visible until the framebuffer is displayed
1016
- * as an image or texture.
1017
- *
1018
- * @example
1019
- * <div>
1020
- * <code>
1021
- * let myBuffer;
1022
- *
1023
- * function setup() {
1024
- * createCanvas(100, 100, WEBGL);
1025
- *
1026
- * // Create a p5.Framebuffer object.
1027
- * myBuffer = createFramebuffer();
1028
- *
1029
- * describe('An empty gray canvas. The canvas gets darker and a rotating, multicolor torus appears while the user presses and holds the mouse.');
1030
- * }
1031
- *
1032
- * function draw() {
1033
- * background(200);
1034
- *
1035
- * // Start drawing to the p5.Framebuffer object.
1036
- * myBuffer.begin();
1037
- *
1038
- * background(50);
1039
- * rotateY(frameCount * 0.01);
1040
- * normalMaterial();
1041
- * torus(30);
1042
- *
1043
- * // Stop drawing to the p5.Framebuffer object.
1044
- * myBuffer.end();
1045
- *
1046
- * // Display the p5.Framebuffer object while
1047
- * // the user presses the mouse.
1048
- * if (mouseIsPressed === true) {
1049
- * image(myBuffer, -50, -50);
1050
- * }
1051
- * }
1052
- * </code>
1053
- * </div>
1054
- */
1055
- begin() {
1056
- this.prevFramebuffer = this.renderer.activeFramebuffer();
1057
- if (this.prevFramebuffer) {
1058
- this.prevFramebuffer._beforeEnd();
1059
- }
1060
- this.renderer.activeFramebuffers.push(this);
1061
- this._beforeBegin();
1062
- this.renderer.push();
1063
- // Apply the framebuffer's camera. This does almost what
1064
- // RendererGL.reset() does, but this does not try to clear any buffers;
1065
- // it only sets the camera.
1066
- // this.renderer.setCamera(this.defaultCamera);
1067
- this.renderer.states.setValue('curCamera', this.defaultCamera);
1068
- // set the projection matrix (which is not normally updated each frame)
1069
- this.renderer.states.setValue('uPMatrix', this.renderer.states.uPMatrix.clone());
1070
- this.renderer.states.uPMatrix.set(this.defaultCamera.projMatrix);
1071
- this.renderer.states.setValue('uViewMatrix', this.renderer.states.uViewMatrix.clone());
1072
- this.renderer.states.uViewMatrix.set(this.defaultCamera.cameraMatrix);
1073
-
1074
- this.renderer.resetMatrix();
1075
- this.renderer.states.uViewMatrix
1076
- .set(this.renderer.states.curCamera.cameraMatrix);
1077
- this.renderer.states.uModelMatrix.reset();
1078
- this.renderer._applyStencilTestIfClipping();
1079
- }
1080
-
1081
- /**
1082
- * When making a p5.Framebuffer active so that it may be drawn to, this method
1083
- * returns the underlying WebGL framebuffer that needs to be active to
1084
- * support this. Antialiased framebuffers first write to a multisampled
1085
- * renderbuffer, while other framebuffers can write directly to their main
1086
- * framebuffers.
1087
- *
1088
- * @private
1089
- */
1090
- _framebufferToBind() {
1091
- if (this.antialias) {
1092
- // If antialiasing, draw to an antialiased renderbuffer rather
1093
- // than directly to the texture. In end() we will copy from the
1094
- // renderbuffer to the texture.
1095
- return this.aaFramebuffer;
1096
- } else {
1097
- return this.framebuffer;
1098
- }
1099
- }
1100
-
1101
- /**
1102
- * Ensures that the framebuffer is ready to be drawn to
1103
- *
1104
- * @private
1105
- */
1106
- _beforeBegin() {
1107
- const gl = this.gl;
1108
- gl.bindFramebuffer(gl.FRAMEBUFFER, this._framebufferToBind());
1109
- this.renderer.viewport(
1110
- this.width * this.density,
1111
- this.height * this.density
1112
- );
1113
- }
1114
-
1115
- /**
1116
- * Ensures that the framebuffer is ready to be read by other framebuffers.
1117
- *
1118
- * @private
1119
- */
1120
- _beforeEnd() {
1121
- if (this.antialias) {
1122
- const gl = this.gl;
1123
- gl.bindFramebuffer(gl.READ_FRAMEBUFFER, this.aaFramebuffer);
1124
- gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, this.framebuffer);
1125
- const partsToCopy = [
1126
- [gl.COLOR_BUFFER_BIT, this.colorP5Texture.glMagFilter]
1127
- ];
1128
- if (this.useDepth) {
1129
- partsToCopy.push(
1130
- [gl.DEPTH_BUFFER_BIT, this.depthP5Texture.glMagFilter]
1131
- );
1132
- }
1133
- for (const [flag, filter] of partsToCopy) {
1134
- gl.blitFramebuffer(
1135
- 0, 0,
1136
- this.width * this.density, this.height * this.density,
1137
- 0, 0,
1138
- this.width * this.density, this.height * this.density,
1139
- flag,
1140
- filter
1141
- );
1142
- }
1143
- }
1144
- }
1145
-
1146
- /**
1147
- * Stops drawing shapes to the framebuffer.
1148
- *
1149
- * <a href="#/p5.Framebuffer/begin">myBuffer.begin()</a> and `myBuffer.end()`
1150
- * allow shapes to be drawn to the framebuffer.
1151
- * <a href="#/p5.Framebuffer/begin">myBuffer.begin()</a> begins drawing to
1152
- * the framebuffer and `myBuffer.end()` stops drawing to the framebuffer.
1153
- * Changes won't be visible until the framebuffer is displayed as an image
1154
- * or texture.
1155
- *
1156
- * @example
1157
- * <div>
1158
- * <code>
1159
- * let myBuffer;
1160
- *
1161
- * function setup() {
1162
- * createCanvas(100, 100, WEBGL);
1163
- *
1164
- * // Create a p5.Framebuffer object.
1165
- * myBuffer = createFramebuffer();
1166
- *
1167
- * describe('An empty gray canvas. The canvas gets darker and a rotating, multicolor torus appears while the user presses and holds the mouse.');
1168
- * }
1169
- *
1170
- * function draw() {
1171
- * background(200);
1172
- *
1173
- * // Start drawing to the p5.Framebuffer object.
1174
- * myBuffer.begin();
1175
- *
1176
- * background(50);
1177
- * rotateY(frameCount * 0.01);
1178
- * normalMaterial();
1179
- * torus(30);
1180
- *
1181
- * // Stop drawing to the p5.Framebuffer object.
1182
- * myBuffer.end();
1183
- *
1184
- * // Display the p5.Framebuffer object while
1185
- * // the user presses the mouse.
1186
- * if (mouseIsPressed === true) {
1187
- * image(myBuffer, -50, -50);
1188
- * }
1189
- * }
1190
- * </code>
1191
- * </div>
1192
- */
1193
- end() {
1194
- const gl = this.gl;
1195
- this.renderer.pop();
1196
- const fbo = this.renderer.activeFramebuffers.pop();
1197
- if (fbo !== this) {
1198
- throw new Error("It looks like you've called end() while another Framebuffer is active.");
1199
- }
1200
- this._beforeEnd();
1201
- if (this.prevFramebuffer) {
1202
- this.prevFramebuffer._beforeBegin();
1203
- } else {
1204
- gl.bindFramebuffer(gl.FRAMEBUFFER, null);
1205
- this.renderer.viewport(
1206
- this.renderer._origViewport.width,
1207
- this.renderer._origViewport.height
1208
- );
1209
- }
1210
- this.renderer._applyStencilTestIfClipping();
1211
- }
1212
-
1213
- /**
1214
- * Draws to the framebuffer by calling a function that contains drawing
1215
- * instructions.
1216
- *
1217
- * The parameter, `callback`, is a function with the drawing instructions
1218
- * for the framebuffer. For example, calling `myBuffer.draw(myFunction)`
1219
- * will call a function named `myFunction()` to draw to the framebuffer.
1220
- * Doing so has the same effect as the following:
1221
- *
1222
- * ```js
1223
- * myBuffer.begin();
1224
- * myFunction();
1225
- * myBuffer.end();
1226
- * ```
1227
- *
1228
- * @param {Function} callback function that draws to the framebuffer.
1229
- *
1230
- * @example
1231
- * <div>
1232
- * <code>
1233
- * // Click the canvas to display the framebuffer.
1234
- *
1235
- * let myBuffer;
1236
- *
1237
- * function setup() {
1238
- * createCanvas(100, 100, WEBGL);
1239
- *
1240
- * // Create a p5.Framebuffer object.
1241
- * myBuffer = createFramebuffer();
1242
- *
1243
- * describe('An empty gray canvas. The canvas gets darker and a rotating, multicolor torus appears while the user presses and holds the mouse.');
1244
- * }
1245
- *
1246
- * function draw() {
1247
- * background(200);
1248
- *
1249
- * // Draw to the p5.Framebuffer object.
1250
- * myBuffer.draw(bagel);
1251
- *
1252
- * // Display the p5.Framebuffer object while
1253
- * // the user presses the mouse.
1254
- * if (mouseIsPressed === true) {
1255
- * image(myBuffer, -50, -50);
1256
- * }
1257
- * }
1258
- *
1259
- * // Draw a rotating, multicolor torus.
1260
- * function bagel() {
1261
- * background(50);
1262
- * rotateY(frameCount * 0.01);
1263
- * normalMaterial();
1264
- * torus(30);
1265
- * }
1266
- * </code>
1267
- * </div>
1268
- */
1269
- draw(callback) {
1270
- this.begin();
1271
- callback();
1272
- this.end();
1273
- }
1274
-
1275
- /**
1276
- * Loads the current value of each pixel in the framebuffer into its
1277
- * <a href="#/p5.Framebuffer/pixels">pixels</a> array.
1278
- *
1279
- * `myBuffer.loadPixels()` must be called before reading from or writing to
1280
- * <a href="#/p5.Framebuffer/pixels">myBuffer.pixels</a>.
1281
- *
1282
- * @method loadPixels
1283
- *
1284
- * @example
1285
- * <div>
1286
- * <code>
1287
- * function setup() {
1288
- * createCanvas(100, 100, WEBGL);
1289
- *
1290
- * background(200);
1291
- *
1292
- * // Create a p5.Framebuffer object.
1293
- * let myBuffer = createFramebuffer();
1294
- *
1295
- * // Load the pixels array.
1296
- * myBuffer.loadPixels();
1297
- *
1298
- * // Get the number of pixels in the
1299
- * // top half of the framebuffer.
1300
- * let numPixels = myBuffer.pixels.length / 2;
1301
- *
1302
- * // Set the framebuffer's top half to pink.
1303
- * for (let i = 0; i < numPixels; i += 4) {
1304
- * myBuffer.pixels[i] = 255;
1305
- * myBuffer.pixels[i + 1] = 102;
1306
- * myBuffer.pixels[i + 2] = 204;
1307
- * myBuffer.pixels[i + 3] = 255;
1308
- * }
1309
- *
1310
- * // Update the pixels array.
1311
- * myBuffer.updatePixels();
1312
- *
1313
- * // Draw the p5.Framebuffer object to the canvas.
1314
- * image(myBuffer, -50, -50);
1315
- *
1316
- * describe('A pink rectangle above a gray rectangle.');
1317
- * }
1318
- * </code>
1319
- * </div>
1320
- */
1321
- loadPixels() {
1322
- const gl = this.gl;
1323
- const prevFramebuffer = this.renderer.activeFramebuffer();
1324
- gl.bindFramebuffer(gl.FRAMEBUFFER, this.framebuffer);
1325
- const colorFormat = this._glColorFormat();
1326
- this.pixels = readPixelsWebGL(
1327
- this.pixels,
1328
- gl,
1329
- this.framebuffer,
1330
- 0,
1331
- 0,
1332
- this.width * this.density,
1333
- this.height * this.density,
1334
- colorFormat.format,
1335
- colorFormat.type
1336
- );
1337
- if (prevFramebuffer) {
1338
- gl.bindFramebuffer(gl.FRAMEBUFFER, prevFramebuffer._framebufferToBind());
1339
- } else {
1340
- gl.bindFramebuffer(gl.FRAMEBUFFER, null);
1341
- }
1342
- }
1343
-
1344
- /**
1345
- * Gets a pixel or a region of pixels from the framebuffer.
1346
- *
1347
- * `myBuffer.get()` is easy to use but it's not as fast as
1348
- * <a href="#/p5.Framebuffer/pixels">myBuffer.pixels</a>. Use
1349
- * <a href="#/p5.Framebuffer/pixels">myBuffer.pixels</a> to read many pixel
1350
- * values.
1351
- *
1352
- * The version of `myBuffer.get()` with no parameters returns the entire
1353
- * framebuffer as a a <a href="#/p5.Image">p5.Image</a> object.
1354
- *
1355
- * The version of `myBuffer.get()` with two parameters interprets them as
1356
- * coordinates. It returns an array with the `[R, G, B, A]` values of the
1357
- * pixel at the given point.
1358
- *
1359
- * The version of `myBuffer.get()` with four parameters interprets them as
1360
- * coordinates and dimensions. It returns a subsection of the framebuffer as
1361
- * a <a href="#/p5.Image">p5.Image</a> object. The first two parameters are
1362
- * the coordinates for the upper-left corner of the subsection. The last two
1363
- * parameters are the width and height of the subsection.
1364
- *
1365
- * @param {Number} x x-coordinate of the pixel. Defaults to 0.
1366
- * @param {Number} y y-coordinate of the pixel. Defaults to 0.
1367
- * @param {Number} w width of the subsection to be returned.
1368
- * @param {Number} h height of the subsection to be returned.
1369
- * @return {p5.Image} subsection as a <a href="#/p5.Image">p5.Image</a> object.
1370
- */
1371
- /**
1372
- * @return {p5.Image} entire framebuffer as a <a href="#/p5.Image">p5.Image</a> object.
1373
- */
1374
- /**
1375
- * @param {Number} x
1376
- * @param {Number} y
1377
- * @return {Number[]} color of the pixel at `(x, y)` as an array of color values `[R, G, B, A]`.
1378
- */
1379
- get(x, y, w, h) {
1380
- // p5._validateParameters('p5.Framebuffer.get', arguments);
1381
- const colorFormat = this._glColorFormat();
1382
- if (x === undefined && y === undefined) {
1383
- x = 0;
1384
- y = 0;
1385
- w = this.width;
1386
- h = this.height;
1387
- } else if (w === undefined && h === undefined) {
1388
- if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
1389
- console.warn(
1390
- 'The x and y values passed to p5.Framebuffer.get are outside of its range and will be clamped.'
1391
- );
1392
- x = constrain(x, 0, this.width - 1);
1393
- y = constrain(y, 0, this.height - 1);
1394
- }
1395
-
1396
- return readPixelWebGL(
1397
- this.gl,
1398
- this.framebuffer,
1399
- x * this.density,
1400
- y * this.density,
1401
- colorFormat.format,
1402
- colorFormat.type
1403
- );
1404
- }
1405
-
1406
- x = constrain(x, 0, this.width - 1);
1407
- y = constrain(y, 0, this.height - 1);
1408
- w = constrain(w, 1, this.width - x);
1409
- h = constrain(h, 1, this.height - y);
1410
-
1411
- const rawData = readPixelsWebGL(
1412
- undefined,
1413
- this.gl,
1414
- this.framebuffer,
1415
- x * this.density,
1416
- y * this.density,
1417
- w * this.density,
1418
- h * this.density,
1419
- colorFormat.format,
1420
- colorFormat.type
1421
- );
1422
- // Framebuffer data might be either a Uint8Array or Float32Array
1423
- // depending on its format, and it may or may not have an alpha channel.
1424
- // To turn it into an image, we have to normalize the data into a
1425
- // Uint8ClampedArray with alpha.
1426
- const fullData = new Uint8ClampedArray(
1427
- w * h * this.density * this.density * 4
1428
- );
1429
-
1430
- // Default channels that aren't in the framebuffer (e.g. alpha, if the
1431
- // framebuffer is in RGB mode instead of RGBA) to 255
1432
- fullData.fill(255);
1433
-
1434
- const channels = colorFormat.type === this.gl.RGB ? 3 : 4;
1435
- for (let y = 0; y < h * this.density; y++) {
1436
- for (let x = 0; x < w * this.density; x++) {
1437
- for (let channel = 0; channel < 4; channel++) {
1438
- const idx = (y * w * this.density + x) * 4 + channel;
1439
- if (channel < channels) {
1440
- // Find the index of this pixel in `rawData`, which might have a
1441
- // different number of channels
1442
- const rawDataIdx = channels === 4
1443
- ? idx
1444
- : (y * w * this.density + x) * channels + channel;
1445
- fullData[idx] = rawData[rawDataIdx];
1446
- }
1447
- }
1448
- }
1449
- }
1450
-
1451
- // Create an image from the data
1452
- const region = new Image(w * this.density, h * this.density);
1453
- region.imageData = region.canvas.getContext('2d').createImageData(
1454
- region.width,
1455
- region.height
1456
- );
1457
- region.imageData.data.set(fullData);
1458
- region.pixels = region.imageData.data;
1459
- region.updatePixels();
1460
- if (this.density !== 1) {
1461
- // TODO: support get() at a pixel density > 1
1462
- region.resize(w, h);
1463
- }
1464
- return region;
1465
- }
1466
-
1467
- /**
1468
- * Updates the framebuffer with the RGBA values in the
1469
- * <a href="#/p5.Framebuffer/pixels">pixels</a> array.
1470
- *
1471
- * `myBuffer.updatePixels()` only needs to be called after changing values
1472
- * in the <a href="#/p5.Framebuffer/pixels">myBuffer.pixels</a> array. Such
1473
- * changes can be made directly after calling
1474
- * <a href="#/p5.Framebuffer/loadPixels">myBuffer.loadPixels()</a>.
1475
- *
1476
- * @method updatePixels
1477
- *
1478
- * @example
1479
- * <div>
1480
- * <code>
1481
- * function setup() {
1482
- * createCanvas(100, 100, WEBGL);
1483
- *
1484
- * background(200);
1485
- *
1486
- * // Create a p5.Framebuffer object.
1487
- * let myBuffer = createFramebuffer();
1488
- *
1489
- * // Load the pixels array.
1490
- * myBuffer.loadPixels();
1491
- *
1492
- * // Get the number of pixels in the
1493
- * // top half of the framebuffer.
1494
- * let numPixels = myBuffer.pixels.length / 2;
1495
- *
1496
- * // Set the framebuffer's top half to pink.
1497
- * for (let i = 0; i < numPixels; i += 4) {
1498
- * myBuffer.pixels[i] = 255;
1499
- * myBuffer.pixels[i + 1] = 102;
1500
- * myBuffer.pixels[i + 2] = 204;
1501
- * myBuffer.pixels[i + 3] = 255;
1502
- * }
1503
- *
1504
- * // Update the pixels array.
1505
- * myBuffer.updatePixels();
1506
- *
1507
- * // Draw the p5.Framebuffer object to the canvas.
1508
- * image(myBuffer, -50, -50);
1509
- *
1510
- * describe('A pink rectangle above a gray rectangle.');
1511
- * }
1512
- * </code>
1513
- * </div>
1514
- */
1515
- updatePixels() {
1516
- const gl = this.gl;
1517
- this.colorP5Texture.bindTexture();
1518
- const colorFormat = this._glColorFormat();
1519
-
1520
- const channels = colorFormat.format === gl.RGBA ? 4 : 3;
1521
- const len =
1522
- this.width * this.height * this.density * this.density * channels;
1523
- const TypedArrayClass = colorFormat.type === gl.UNSIGNED_BYTE
1524
- ? Uint8Array
1525
- : Float32Array;
1526
- if (
1527
- !(this.pixels instanceof TypedArrayClass) || this.pixels.length !== len
1528
- ) {
1529
- throw new Error(
1530
- 'The pixels array has not been set correctly. Please call loadPixels() before updatePixels().'
1531
- );
1532
- }
1533
-
1534
- gl.texImage2D(
1535
- gl.TEXTURE_2D,
1536
- 0,
1537
- colorFormat.internalFormat,
1538
- this.width * this.density,
1539
- this.height * this.density,
1540
- 0,
1541
- colorFormat.format,
1542
- colorFormat.type,
1543
- this.pixels
1544
- );
1545
- this.colorP5Texture.unbindTexture();
1546
-
1547
- const prevFramebuffer = this.renderer.activeFramebuffer();
1548
- if (this.antialias) {
1549
- // We need to make sure the antialiased framebuffer also has the updated
1550
- // pixels so that if more is drawn to it, it goes on top of the updated
1551
- // pixels instead of replacing them.
1552
- // We can't blit the framebuffer to the multisampled antialias
1553
- // framebuffer to leave both in the same state, so instead we have
1554
- // to use image() to put the framebuffer texture onto the antialiased
1555
- // framebuffer.
1556
- this.begin();
1557
- this.renderer.push();
1558
- // this.renderer.imageMode(constants.CENTER);
1559
- this.renderer.states.setValue('imageMode', constants.CORNER);
1560
- this.renderer.setCamera(this.filterCamera);
1561
- this.renderer.resetMatrix();
1562
- this.renderer.states.setValue('strokeColor', null);
1563
- this.renderer.clear();
1564
- this.renderer._drawingFilter = true;
1565
- this.renderer.image(
1566
- this,
1567
- 0, 0,
1568
- this.width, this.height,
1569
- -this.renderer.width / 2, -this.renderer.height / 2,
1570
- this.renderer.width, this.renderer.height
1571
- );
1572
- this.renderer._drawingFilter = false;
1573
- this.renderer.pop();
1574
- if (this.useDepth) {
1575
- gl.clearDepth(1);
1576
- gl.clear(gl.DEPTH_BUFFER_BIT);
1577
- }
1578
- this.end();
1579
- } else {
1580
- gl.bindFramebuffer(gl.FRAMEBUFFER, this.framebuffer);
1581
- if (this.useDepth) {
1582
- gl.clearDepth(1);
1583
- gl.clear(gl.DEPTH_BUFFER_BIT);
1584
- }
1585
- if (prevFramebuffer) {
1586
- gl.bindFramebuffer(
1587
- gl.FRAMEBUFFER,
1588
- prevFramebuffer._framebufferToBind()
1589
- );
1590
- } else {
1591
- gl.bindFramebuffer(gl.FRAMEBUFFER, null);
1592
- }
1593
- }
1594
- }
1595
- }
1596
-
1597
- function framebuffer(p5, fn){
1598
- /**
1599
- * A <a href="#/p5.Camera">p5.Camera</a> attached to a
1600
- * <a href="#/p5.Framebuffer">p5.Framebuffer</a>.
1601
- *
1602
- * @class p5.FramebufferCamera
1603
- * @param {p5.Framebuffer} framebuffer The framebuffer this camera is
1604
- * attached to
1605
- * @private
1606
- */
1607
- p5.FramebufferCamera = FramebufferCamera;
1608
-
1609
- /**
1610
- * A <a href="#/p5.Texture">p5.Texture</a> corresponding to a property of a
1611
- * <a href="#/p5.Framebuffer">p5.Framebuffer</a>.
1612
- *
1613
- * @class p5.FramebufferTexture
1614
- * @param {p5.Framebuffer} framebuffer The framebuffer represented by this
1615
- * texture
1616
- * @param {String} property The property of the framebuffer represented by
1617
- * this texture, either `color` or `depth`
1618
- * @private
1619
- */
1620
- p5.FramebufferTexture = FramebufferTexture;
1621
-
1622
- /**
1623
- * A class to describe a high-performance drawing surface for textures.
1624
- *
1625
- * Each `p5.Framebuffer` object provides a dedicated drawing surface called
1626
- * a *framebuffer*. They're similar to
1627
- * <a href="#/p5.Graphics">p5.Graphics</a> objects but can run much faster.
1628
- * Performance is improved because the framebuffer shares the same WebGL
1629
- * context as the canvas used to create it.
1630
- *
1631
- * `p5.Framebuffer` objects have all the drawing features of the main
1632
- * canvas. Drawing instructions meant for the framebuffer must be placed
1633
- * between calls to
1634
- * <a href="#/p5.Framebuffer/begin">myBuffer.begin()</a> and
1635
- * <a href="#/p5.Framebuffer/end">myBuffer.end()</a>. The resulting image
1636
- * can be applied as a texture by passing the `p5.Framebuffer` object to the
1637
- * <a href="#/p5/texture">texture()</a> function, as in `texture(myBuffer)`.
1638
- * It can also be displayed on the main canvas by passing it to the
1639
- * <a href="#/p5/image">image()</a> function, as in `image(myBuffer, 0, 0)`.
1640
- *
1641
- * Note: <a href="#/p5/createFramebuffer">createFramebuffer()</a> is the
1642
- * recommended way to create an instance of this class.
1643
- *
1644
- * @class p5.Framebuffer
1645
- * @param {p5.Graphics|p5} target sketch instance or
1646
- * <a href="#/p5.Graphics">p5.Graphics</a>
1647
- * object.
1648
- * @param {Object} [settings] configuration options.
1649
- */
1650
- p5.Framebuffer = Framebuffer;
1651
-
1652
- /**
1653
- * An object that stores the framebuffer's color data.
1654
- *
1655
- * Each framebuffer uses a
1656
- * <a href="https://developer.mozilla.org/en-US/docs/Web/API/WebGLTexture" target="_blank">WebGLTexture</a>
1657
- * object internally to store its color data. The `myBuffer.color` property
1658
- * makes it possible to pass this data directly to other functions. For
1659
- * example, calling `texture(myBuffer.color)` or
1660
- * `myShader.setUniform('colorTexture', myBuffer.color)` may be helpful for
1661
- * advanced use cases.
1662
- *
1663
- * Note: By default, a framebuffer's y-coordinates are flipped compared to
1664
- * images and videos. It's easy to flip a framebuffer's y-coordinates as
1665
- * needed when applying it as a texture. For example, calling
1666
- * `plane(myBuffer.width, -myBuffer.height)` will flip the framebuffer.
1667
- *
1668
- * @property {p5.FramebufferTexture} color
1669
- * @for p5.Framebuffer
1670
- *
1671
- * @example
1672
- * <div>
1673
- * <code>
1674
- * function setup() {
1675
- * createCanvas(100, 100, WEBGL);
1676
- *
1677
- * background(200);
1678
- *
1679
- * // Create a p5.Framebuffer object.
1680
- * let myBuffer = createFramebuffer();
1681
- *
1682
- * // Start drawing to the p5.Framebuffer object.
1683
- * myBuffer.begin();
1684
- *
1685
- * triangle(-25, 25, 0, -25, 25, 25);
1686
- *
1687
- * // Stop drawing to the p5.Framebuffer object.
1688
- * myBuffer.end();
1689
- *
1690
- * // Use the p5.Framebuffer object's WebGLTexture.
1691
- * texture(myBuffer.color);
1692
- *
1693
- * // Style the plane.
1694
- * noStroke();
1695
- *
1696
- * // Draw the plane.
1697
- * plane(myBuffer.width, myBuffer.height);
1698
- *
1699
- * describe('A white triangle on a gray background.');
1700
- * }
1701
- * </code>
1702
- * </div>
1703
- */
1704
-
1705
- /**
1706
- * An object that stores the framebuffer's depth data.
1707
- *
1708
- * Each framebuffer uses a
1709
- * <a href="https://developer.mozilla.org/en-US/docs/Web/API/WebGLTexture" target="_blank">WebGLTexture</a>
1710
- * object internally to store its depth data. The `myBuffer.depth` property
1711
- * makes it possible to pass this data directly to other functions. For
1712
- * example, calling `texture(myBuffer.depth)` or
1713
- * `myShader.setUniform('depthTexture', myBuffer.depth)` may be helpful for
1714
- * advanced use cases.
1715
- *
1716
- * Note: By default, a framebuffer's y-coordinates are flipped compared to
1717
- * images and videos. It's easy to flip a framebuffer's y-coordinates as
1718
- * needed when applying it as a texture. For example, calling
1719
- * `plane(myBuffer.width, -myBuffer.height)` will flip the framebuffer.
1720
- *
1721
- * @property {p5.FramebufferTexture} depth
1722
- * @for p5.Framebuffer
1723
- *
1724
- * @example
1725
- * <div>
1726
- * <code>
1727
- * // Note: A "uniform" is a global variable within a shader program.
1728
- *
1729
- * // Create a string with the vertex shader program.
1730
- * // The vertex shader is called for each vertex.
1731
- * let vertSrc = `
1732
- * precision highp float;
1733
- * attribute vec3 aPosition;
1734
- * attribute vec2 aTexCoord;
1735
- * uniform mat4 uModelViewMatrix;
1736
- * uniform mat4 uProjectionMatrix;
1737
- * varying vec2 vTexCoord;
1738
- *
1739
- * void main() {
1740
- * vec4 viewModelPosition = uModelViewMatrix * vec4(aPosition, 1.0);
1741
- * gl_Position = uProjectionMatrix * viewModelPosition;
1742
- * vTexCoord = aTexCoord;
1743
- * }
1744
- * `;
1745
- *
1746
- * // Create a string with the fragment shader program.
1747
- * // The fragment shader is called for each pixel.
1748
- * let fragSrc = `
1749
- * precision highp float;
1750
- * varying vec2 vTexCoord;
1751
- * uniform sampler2D depth;
1752
- *
1753
- * void main() {
1754
- * // Get the pixel's depth value.
1755
- * float depthVal = texture2D(depth, vTexCoord).r;
1756
- *
1757
- * // Set the pixel's color based on its depth.
1758
- * gl_FragColor = mix(
1759
- * vec4(0., 0., 0., 1.),
1760
- * vec4(1., 0., 1., 1.),
1761
- * depthVal);
1762
- * }
1763
- * `;
1764
- *
1765
- * let myBuffer;
1766
- * let myShader;
1767
- *
1768
- * function setup() {
1769
- * createCanvas(100, 100, WEBGL);
1770
- *
1771
- * // Create a p5.Framebuffer object.
1772
- * myBuffer = createFramebuffer();
1773
- *
1774
- * // Create a p5.Shader object.
1775
- * myShader = createShader(vertSrc, fragSrc);
1776
- *
1777
- * // Compile and apply the shader.
1778
- * shader(myShader);
1779
- *
1780
- * describe('The shadow of a box rotates slowly against a magenta background.');
1781
- * }
1782
- *
1783
- * function draw() {
1784
- * // Draw to the p5.Framebuffer object.
1785
- * myBuffer.begin();
1786
- * background(255);
1787
- * rotateX(frameCount * 0.01);
1788
- * box(20, 20, 80);
1789
- * myBuffer.end();
1790
- *
1791
- * // Set the shader's depth uniform using
1792
- * // the framebuffer's depth texture.
1793
- * myShader.setUniform('depth', myBuffer.depth);
1794
- *
1795
- * // Style the plane.
1796
- * noStroke();
1797
- *
1798
- * // Draw the plane.
1799
- * plane(myBuffer.width, myBuffer.height);
1800
- * }
1801
- * </code>
1802
- * </div>
1803
- */
1804
-
1805
- /**
1806
- * An array containing the color of each pixel in the framebuffer.
1807
- *
1808
- * <a href="#/p5.Framebuffer/loadPixels">myBuffer.loadPixels()</a> must be
1809
- * called before accessing the `myBuffer.pixels` array.
1810
- * <a href="#/p5.Framebuffer/updatePixels">myBuffer.updatePixels()</a>
1811
- * must be called after any changes are made.
1812
- *
1813
- * Note: Updating pixels via this property is slower than drawing to the
1814
- * framebuffer directly. Consider using a
1815
- * <a href="#/p5.Shader">p5.Shader</a> object instead of looping over
1816
- * `myBuffer.pixels`.
1817
- *
1818
- * @property {Number[]} pixels
1819
- * @for p5.Framebuffer
1820
- *
1821
- * @example
1822
- * <div>
1823
- * <code>
1824
- * function setup() {
1825
- * createCanvas(100, 100, WEBGL);
1826
- *
1827
- * background(200);
1828
- *
1829
- * // Create a p5.Framebuffer object.
1830
- * let myBuffer = createFramebuffer();
1831
- *
1832
- * // Load the pixels array.
1833
- * myBuffer.loadPixels();
1834
- *
1835
- * // Get the number of pixels in the
1836
- * // top half of the framebuffer.
1837
- * let numPixels = myBuffer.pixels.length / 2;
1838
- *
1839
- * // Set the framebuffer's top half to pink.
1840
- * for (let i = 0; i < numPixels; i += 4) {
1841
- * myBuffer.pixels[i] = 255;
1842
- * myBuffer.pixels[i + 1] = 102;
1843
- * myBuffer.pixels[i + 2] = 204;
1844
- * myBuffer.pixels[i + 3] = 255;
1845
- * }
1846
- *
1847
- * // Update the pixels array.
1848
- * myBuffer.updatePixels();
1849
- *
1850
- * // Draw the p5.Framebuffer object to the canvas.
1851
- * image(myBuffer, -50, -50);
1852
- *
1853
- * describe('A pink rectangle above a gray rectangle.');
1854
- * }
1855
- * </code>
1856
- * </div>
1857
- */
1858
- }
1859
-
1860
- export default framebuffer;
1861
- export { FramebufferTexture, FramebufferCamera, Framebuffer };
1862
-
1863
- if(typeof p5 !== 'undefined'){
1864
- framebuffer(p5, p5.prototype);
1865
- }