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,2867 +0,0 @@
1
- import * as constants from "../core/constants";
2
- import GeometryBuilder from "./GeometryBuilder";
3
- import { Renderer } from "../core/p5.Renderer";
4
- import { Matrix } from "../math/p5.Matrix";
5
- import { Camera } from "./p5.Camera";
6
- import { Vector } from "../math/p5.Vector";
7
- import { RenderBuffer } from "./p5.RenderBuffer";
8
- import { DataArray } from "./p5.DataArray";
9
- import { Shader } from "./p5.Shader";
10
- import { Image } from "../image/p5.Image";
11
- import { Texture, MipmapTexture } from "./p5.Texture";
12
- import { Framebuffer } from "./p5.Framebuffer";
13
- import { Graphics } from "../core/p5.Graphics";
14
- import { Element } from "../dom/p5.Element";
15
- import { ShapeBuilder } from "./ShapeBuilder";
16
- import { GeometryBufferCache } from "./GeometryBufferCache";
17
- import { filterParamDefaults } from "../image/const";
18
-
19
- import filterBaseVert from "./shaders/filters/base.vert";
20
- import lightingShader from "./shaders/lighting.glsl";
21
- import webgl2CompatibilityShader from "./shaders/webgl2Compatibility.glsl";
22
- import normalVert from "./shaders/normal.vert";
23
- import normalFrag from "./shaders/normal.frag";
24
- import basicFrag from "./shaders/basic.frag";
25
- import sphereMappingFrag from "./shaders/sphereMapping.frag";
26
- import lightVert from "./shaders/light.vert";
27
- import lightTextureFrag from "./shaders/light_texture.frag";
28
- import phongVert from "./shaders/phong.vert";
29
- import phongFrag from "./shaders/phong.frag";
30
- import fontVert from "./shaders/font.vert";
31
- import fontFrag from "./shaders/font.frag";
32
- import lineVert from "./shaders/line.vert";
33
- import lineFrag from "./shaders/line.frag";
34
- import pointVert from "./shaders/point.vert";
35
- import pointFrag from "./shaders/point.frag";
36
- import imageLightVert from "./shaders/imageLight.vert";
37
- import imageLightDiffusedFrag from "./shaders/imageLightDiffused.frag";
38
- import imageLightSpecularFrag from "./shaders/imageLightSpecular.frag";
39
-
40
- import filterBaseFrag from "./shaders/filters/base.frag";
41
- import filterGrayFrag from "./shaders/filters/gray.frag";
42
- import filterErodeFrag from "./shaders/filters/erode.frag";
43
- import filterDilateFrag from "./shaders/filters/dilate.frag";
44
- import filterBlurFrag from "./shaders/filters/blur.frag";
45
- import filterPosterizeFrag from "./shaders/filters/posterize.frag";
46
- import filterOpaqueFrag from "./shaders/filters/opaque.frag";
47
- import filterInvertFrag from "./shaders/filters/invert.frag";
48
- import filterThresholdFrag from "./shaders/filters/threshold.frag";
49
- import filterShaderVert from "./shaders/filters/default.vert";
50
- import { PrimitiveToVerticesConverter } from "../shape/custom_shapes";
51
- import { Color } from "../color/p5.Color";
52
-
53
- const STROKE_CAP_ENUM = {};
54
- const STROKE_JOIN_ENUM = {};
55
- let lineDefs = "";
56
- const defineStrokeCapEnum = function (key, val) {
57
- lineDefs += `#define STROKE_CAP_${key} ${val}\n`;
58
- STROKE_CAP_ENUM[constants[key]] = val;
59
- };
60
- const defineStrokeJoinEnum = function (key, val) {
61
- lineDefs += `#define STROKE_JOIN_${key} ${val}\n`;
62
- STROKE_JOIN_ENUM[constants[key]] = val;
63
- };
64
-
65
- // Define constants in line shaders for each type of cap/join, and also record
66
- // the values in JS objects
67
- defineStrokeCapEnum("ROUND", 0);
68
- defineStrokeCapEnum("PROJECT", 1);
69
- defineStrokeCapEnum("SQUARE", 2);
70
- defineStrokeJoinEnum("ROUND", 0);
71
- defineStrokeJoinEnum("MITER", 1);
72
- defineStrokeJoinEnum("BEVEL", 2);
73
-
74
- const defaultShaders = {
75
- normalVert,
76
- normalFrag,
77
- basicFrag,
78
- sphereMappingFrag,
79
- lightVert: lightingShader + lightVert,
80
- lightTextureFrag,
81
- phongVert,
82
- phongFrag: lightingShader + phongFrag,
83
- fontVert,
84
- fontFrag,
85
- lineVert: lineDefs + lineVert,
86
- lineFrag: lineDefs + lineFrag,
87
- pointVert,
88
- pointFrag,
89
- imageLightVert,
90
- imageLightDiffusedFrag,
91
- imageLightSpecularFrag,
92
- filterBaseVert,
93
- filterBaseFrag,
94
- };
95
- let sphereMapping = defaultShaders.sphereMappingFrag;
96
- for (const key in defaultShaders) {
97
- defaultShaders[key] = webgl2CompatibilityShader + defaultShaders[key];
98
- }
99
-
100
- const filterShaderFrags = {
101
- [constants.GRAY]: filterGrayFrag,
102
- [constants.ERODE]: filterErodeFrag,
103
- [constants.DILATE]: filterDilateFrag,
104
- [constants.BLUR]: filterBlurFrag,
105
- [constants.POSTERIZE]: filterPosterizeFrag,
106
- [constants.OPAQUE]: filterOpaqueFrag,
107
- [constants.INVERT]: filterInvertFrag,
108
- [constants.THRESHOLD]: filterThresholdFrag,
109
- };
110
-
111
- /**
112
- * 3D graphics class
113
- * @private
114
- * @class p5.RendererGL
115
- * @extends p5.Renderer
116
- * @todo extend class to include public method for offscreen
117
- * rendering (FBO).
118
- */
119
- class RendererGL extends Renderer {
120
- constructor(pInst, w, h, isMainCanvas, elt, attr) {
121
- super(pInst, w, h, isMainCanvas);
122
-
123
- // Create new canvas
124
- this.canvas = this.elt = elt || document.createElement("canvas");
125
- this._setAttributeDefaults(pInst);
126
- this._initContext();
127
- // This redundant property is useful in reminding you that you are
128
- // interacting with WebGLRenderingContext, still worth considering future removal
129
- this.GL = this.drawingContext;
130
-
131
- if (this._isMainCanvas) {
132
- // for pixel method sharing with pimage
133
- this._pInst._curElement = this;
134
- this._pInst.canvas = this.canvas;
135
- } else {
136
- // hide if offscreen buffer by default
137
- this.canvas.style.display = "none";
138
- }
139
- this.elt.id = "defaultCanvas0";
140
- this.elt.classList.add("p5Canvas");
141
-
142
- // Set and return p5.Element
143
- this.wrappedElt = new Element(this.elt, this._pInst);
144
-
145
- // Extend renderer with methods of p5.Element with getters
146
- for (const p of Object.getOwnPropertyNames(Element.prototype)) {
147
- if (p !== 'constructor' && p[0] !== '_') {
148
- Object.defineProperty(this, p, {
149
- get() {
150
- return this.wrappedElt[p];
151
- }
152
- })
153
- }
154
- }
155
-
156
- const dimensions = this._adjustDimensions(w, h);
157
- w = dimensions.adjustedWidth;
158
- h = dimensions.adjustedHeight;
159
-
160
- this.width = w;
161
- this.height = h;
162
-
163
- // Set canvas size
164
- this.elt.width = w * this._pixelDensity;
165
- this.elt.height = h * this._pixelDensity;
166
- this.elt.style.width = `${w}px`;
167
- this.elt.style.height = `${h}px`;
168
- this._origViewport = {
169
- width: this.GL.drawingBufferWidth,
170
- height: this.GL.drawingBufferHeight,
171
- };
172
- this.viewport(this._origViewport.width, this._origViewport.height);
173
-
174
- // Attach canvas element to DOM
175
- if (this._pInst._userNode) {
176
- // user input node case
177
- this._pInst._userNode.appendChild(this.elt);
178
- } else {
179
- //create main element
180
- if (document.getElementsByTagName("main").length === 0) {
181
- let m = document.createElement("main");
182
- document.body.appendChild(m);
183
- }
184
- //append canvas to main
185
- document.getElementsByTagName("main")[0].appendChild(this.elt);
186
- }
187
-
188
- this.isP3D = true; //lets us know we're in 3d mode
189
-
190
- // When constructing a new Geometry, this will represent the builder
191
- this.geometryBuilder = undefined;
192
-
193
- // Push/pop state
194
- this.states.uModelMatrix = new Matrix(4);
195
- this.states.uViewMatrix = new Matrix(4);
196
- this.states.uPMatrix = new Matrix(4);
197
-
198
- this.states.curCamera = new Camera(this);
199
- this.states.uPMatrix.set(this.states.curCamera.projMatrix);
200
- this.states.uViewMatrix.set(this.states.curCamera.cameraMatrix);
201
-
202
- this.states.enableLighting = false;
203
- this.states.ambientLightColors = [];
204
- this.states.specularColors = [1, 1, 1];
205
- this.states.directionalLightDirections = [];
206
- this.states.directionalLightDiffuseColors = [];
207
- this.states.directionalLightSpecularColors = [];
208
- this.states.pointLightPositions = [];
209
- this.states.pointLightDiffuseColors = [];
210
- this.states.pointLightSpecularColors = [];
211
- this.states.spotLightPositions = [];
212
- this.states.spotLightDirections = [];
213
- this.states.spotLightDiffuseColors = [];
214
- this.states.spotLightSpecularColors = [];
215
- this.states.spotLightAngle = [];
216
- this.states.spotLightConc = [];
217
- this.states.activeImageLight = null;
218
-
219
- this.states.curFillColor = [1, 1, 1, 1];
220
- this.states.curAmbientColor = [1, 1, 1, 1];
221
- this.states.curSpecularColor = [0, 0, 0, 0];
222
- this.states.curEmissiveColor = [0, 0, 0, 0];
223
- this.states.curStrokeColor = [0, 0, 0, 1];
224
-
225
- this.states.curBlendMode = constants.BLEND;
226
-
227
- this.states._hasSetAmbient = false;
228
- this.states._useSpecularMaterial = false;
229
- this.states._useEmissiveMaterial = false;
230
- this.states._useNormalMaterial = false;
231
- this.states._useShininess = 1;
232
- this.states._useMetalness = 0;
233
-
234
- this.states.tint = [255, 255, 255, 255];
235
-
236
- this.states.constantAttenuation = 1;
237
- this.states.linearAttenuation = 0;
238
- this.states.quadraticAttenuation = 0;
239
-
240
- this.states._currentNormal = new Vector(0, 0, 1);
241
-
242
- this.states.drawMode = constants.FILL;
243
-
244
- this.states._tex = null;
245
- this.states.textureMode = constants.IMAGE;
246
- this.states.textureWrapX = constants.CLAMP;
247
- this.states.textureWrapY = constants.CLAMP;
248
-
249
- // erasing
250
- this._isErasing = false;
251
-
252
- // simple lines
253
- this._simpleLines = false;
254
-
255
- // clipping
256
- this._clipDepths = [];
257
- this._isClipApplied = false;
258
- this._stencilTestOn = false;
259
-
260
- this.mixedAmbientLight = [];
261
- this.mixedSpecularColor = [];
262
-
263
- // p5.framebuffer for this are calculated in getDiffusedTexture function
264
- this.diffusedTextures = new Map();
265
- // p5.framebuffer for this are calculated in getSpecularTexture function
266
- this.specularTextures = new Map();
267
-
268
- this.preEraseBlend = undefined;
269
- this._cachedBlendMode = undefined;
270
- this._cachedFillStyle = [1, 1, 1, 1];
271
- this._cachedStrokeStyle = [0, 0, 0, 1];
272
- if (this.webglVersion === constants.WEBGL2) {
273
- this.blendExt = this.GL;
274
- } else {
275
- this.blendExt = this.GL.getExtension("EXT_blend_minmax");
276
- }
277
- this._isBlending = false;
278
-
279
- this._useLineColor = false;
280
- this._useVertexColor = false;
281
-
282
- this.registerEnabled = new Set();
283
-
284
- // Camera
285
- this.states.curCamera._computeCameraDefaultSettings();
286
- this.states.curCamera._setDefaultCamera();
287
-
288
- // FilterCamera
289
- this.filterCamera = new Camera(this);
290
- this.filterCamera._computeCameraDefaultSettings();
291
- this.filterCamera._setDefaultCamera();
292
- // Information about the previous frame's touch object
293
- // for executing orbitControl()
294
- this.prevTouches = [];
295
- // Velocity variable for use with orbitControl()
296
- this.zoomVelocity = 0;
297
- this.rotateVelocity = new Vector(0, 0);
298
- this.moveVelocity = new Vector(0, 0);
299
- // Flags for recording the state of zooming, rotation and moving
300
- this.executeZoom = false;
301
- this.executeRotateAndMove = false;
302
-
303
- this._drawingFilter = false;
304
- this._drawingImage = false;
305
-
306
- this.specularShader = undefined;
307
- this.sphereMapping = undefined;
308
- this.diffusedShader = undefined;
309
- this._baseFilterShader = undefined;
310
- this._defaultLightShader = undefined;
311
- this._defaultImmediateModeShader = undefined;
312
- this._defaultNormalShader = undefined;
313
- this._defaultColorShader = undefined;
314
- this._defaultPointShader = undefined;
315
-
316
- this.states.userFillShader = undefined;
317
- this.states.userStrokeShader = undefined;
318
- this.states.userPointShader = undefined;
319
- this.states.userImageShader = undefined;
320
-
321
- this.states.curveDetail = 1 / 4;
322
-
323
- // Used by beginShape/endShape functions to construct a p5.Geometry
324
- this.shapeBuilder = new ShapeBuilder(this);
325
-
326
- this.buffers = {
327
- fill: [
328
- new RenderBuffer(
329
- 3,
330
- "vertices",
331
- "vertexBuffer",
332
- "aPosition",
333
- this,
334
- this._vToNArray
335
- ),
336
- new RenderBuffer(
337
- 3,
338
- "vertexNormals",
339
- "normalBuffer",
340
- "aNormal",
341
- this,
342
- this._vToNArray
343
- ),
344
- new RenderBuffer(
345
- 4,
346
- "vertexColors",
347
- "colorBuffer",
348
- "aVertexColor",
349
- this
350
- ),
351
- new RenderBuffer(
352
- 3,
353
- "vertexAmbients",
354
- "ambientBuffer",
355
- "aAmbientColor",
356
- this
357
- ),
358
- new RenderBuffer(2, "uvs", "uvBuffer", "aTexCoord", this, (arr) =>
359
- arr.flat()
360
- ),
361
- ],
362
- stroke: [
363
- new RenderBuffer(
364
- 4,
365
- "lineVertexColors",
366
- "lineColorBuffer",
367
- "aVertexColor",
368
- this
369
- ),
370
- new RenderBuffer(
371
- 3,
372
- "lineVertices",
373
- "lineVerticesBuffer",
374
- "aPosition",
375
- this
376
- ),
377
- new RenderBuffer(
378
- 3,
379
- "lineTangentsIn",
380
- "lineTangentsInBuffer",
381
- "aTangentIn",
382
- this
383
- ),
384
- new RenderBuffer(
385
- 3,
386
- "lineTangentsOut",
387
- "lineTangentsOutBuffer",
388
- "aTangentOut",
389
- this
390
- ),
391
- new RenderBuffer(1, "lineSides", "lineSidesBuffer", "aSide", this),
392
- ],
393
- text: [
394
- new RenderBuffer(
395
- 3,
396
- "vertices",
397
- "vertexBuffer",
398
- "aPosition",
399
- this,
400
- this._vToNArray
401
- ),
402
- new RenderBuffer(2, "uvs", "uvBuffer", "aTexCoord", this, (arr) =>
403
- arr.flat()
404
- ),
405
- ],
406
- point: this.GL.createBuffer(),
407
- user: [],
408
- };
409
-
410
- this.geometryBufferCache = new GeometryBufferCache(this);
411
-
412
- this.curStrokeCap = constants.ROUND;
413
- this.curStrokeJoin = constants.ROUND;
414
-
415
- // map of texture sources to textures created in this gl context via this.getTexture(src)
416
- this.textures = new Map();
417
-
418
- // set of framebuffers in use
419
- this.framebuffers = new Set();
420
- // stack of active framebuffers
421
- this.activeFramebuffers = [];
422
-
423
- // for post processing step
424
- this.states.filterShader = undefined;
425
- this.filterLayer = undefined;
426
- this.filterLayerTemp = undefined;
427
- this.defaultFilterShaders = {};
428
-
429
- this.fontInfos = {};
430
-
431
- this._curShader = undefined;
432
- this.drawShapeCount = 1;
433
-
434
- this.scratchMat3 = new Matrix(3);
435
-
436
- this._userEnabledStencil = false;
437
- // Store original methods for internal use
438
- this._internalEnable = this.drawingContext.enable;
439
- this._internalDisable = this.drawingContext.disable;
440
-
441
- // Override WebGL enable function
442
- this.drawingContext.enable = (key) => {
443
- if (key === this.drawingContext.STENCIL_TEST) {
444
- if (!this._clipping) {
445
- this._userEnabledStencil = true;
446
- }
447
- }
448
- return this._internalEnable.call(this.drawingContext, key);
449
- };
450
-
451
- // Override WebGL disable function
452
- this.drawingContext.disable = (key) => {
453
- if (key === this.drawingContext.STENCIL_TEST) {
454
- this._userEnabledStencil = false;
455
- }
456
- return this._internalDisable.call(this.drawingContext, key);
457
- };
458
- }
459
-
460
- remove() {
461
- this.wrappedElt.remove();
462
- this.wrappedElt = null;
463
- this.canvas = null;
464
- this.elt = null;
465
- }
466
-
467
- //////////////////////////////////////////////
468
- // Geometry Building
469
- //////////////////////////////////////////////
470
-
471
- /**
472
- * Starts creating a new p5.Geometry. Subsequent shapes drawn will be added
473
- * to the geometry and then returned when
474
- * <a href="#/p5/endGeometry">endGeometry()</a> is called. One can also use
475
- * <a href="#/p5/buildGeometry">buildGeometry()</a> to pass a function that
476
- * draws shapes.
477
- *
478
- * If you need to draw complex shapes every frame which don't change over time,
479
- * combining them upfront with `beginGeometry()` and `endGeometry()` and then
480
- * drawing that will run faster than repeatedly drawing the individual pieces.
481
- * @private
482
- */
483
- beginGeometry() {
484
- if (this.geometryBuilder) {
485
- throw new Error(
486
- "It looks like `beginGeometry()` is being called while another p5.Geometry is already being build."
487
- );
488
- }
489
- this.geometryBuilder = new GeometryBuilder(this);
490
- this.geometryBuilder.prevFillColor = this.states.fillColor;
491
- this.fill(new Color([-1, -1, -1, -1]));
492
- }
493
-
494
- /**
495
- * Finishes creating a new <a href="#/p5.Geometry">p5.Geometry</a> that was
496
- * started using <a href="#/p5/beginGeometry">beginGeometry()</a>. One can also
497
- * use <a href="#/p5/buildGeometry">buildGeometry()</a> to pass a function that
498
- * draws shapes.
499
- * @private
500
- *
501
- * @returns {p5.Geometry} The model that was built.
502
- */
503
- endGeometry() {
504
- if (!this.geometryBuilder) {
505
- throw new Error(
506
- "Make sure you call beginGeometry() before endGeometry()!"
507
- );
508
- }
509
- const geometry = this.geometryBuilder.finish();
510
- this.fill(this.geometryBuilder.prevFillColor);
511
- this.geometryBuilder = undefined;
512
- return geometry;
513
- }
514
-
515
- /**
516
- * Creates a new <a href="#/p5.Geometry">p5.Geometry</a> that contains all
517
- * the shapes drawn in a provided callback function. The returned combined shape
518
- * can then be drawn all at once using <a href="#/p5/model">model()</a>.
519
- *
520
- * If you need to draw complex shapes every frame which don't change over time,
521
- * combining them with `buildGeometry()` once and then drawing that will run
522
- * faster than repeatedly drawing the individual pieces.
523
- *
524
- * One can also draw shapes directly between
525
- * <a href="#/p5/beginGeometry">beginGeometry()</a> and
526
- * <a href="#/p5/endGeometry">endGeometry()</a> instead of using a callback
527
- * function.
528
- * @param {Function} callback A function that draws shapes.
529
- * @returns {p5.Geometry} The model that was built from the callback function.
530
- */
531
- buildGeometry(callback) {
532
- this.beginGeometry();
533
- callback();
534
- return this.endGeometry();
535
- }
536
-
537
- //////////////////////////////////////////////
538
- // Shape drawing
539
- //////////////////////////////////////////////
540
-
541
- beginShape(...args) {
542
- super.beginShape(...args);
543
- // TODO remove when shape refactor is complete
544
- // this.shapeBuilder.beginShape(...args);
545
- }
546
-
547
- curveDetail(d) {
548
- if (d === undefined) {
549
- return this.states.curveDetail;
550
- } else {
551
- this.states.setValue("curveDetail", d);
552
- }
553
- }
554
-
555
- drawShape(shape) {
556
- const visitor = new PrimitiveToVerticesConverter({
557
- curveDetail: this.states.curveDetail,
558
- });
559
- shape.accept(visitor);
560
- this.shapeBuilder.constructFromContours(shape, visitor.contours);
561
-
562
- if (this.geometryBuilder) {
563
- this.geometryBuilder.addImmediate(
564
- this.shapeBuilder.geometry,
565
- this.shapeBuilder.shapeMode
566
- );
567
- } else if (this.states.fillColor || this.states.strokeColor) {
568
- if (this.shapeBuilder.shapeMode === constants.POINTS) {
569
- this._drawPoints(
570
- this.shapeBuilder.geometry.vertices,
571
- this.buffers.point
572
- );
573
- } else {
574
- this._drawGeometry(this.shapeBuilder.geometry, {
575
- mode: this.shapeBuilder.shapeMode,
576
- count: this.drawShapeCount,
577
- });
578
- }
579
- }
580
- this.drawShapeCount = 1;
581
- }
582
-
583
- endShape(mode, count) {
584
- this.drawShapeCount = count;
585
- super.endShape(mode, count);
586
- }
587
-
588
- vertexProperty(...args) {
589
- this.currentShape.vertexProperty(...args);
590
- }
591
-
592
- normal(xorv, y, z) {
593
- if (xorv instanceof Vector) {
594
- this.states.setValue("_currentNormal", xorv);
595
- } else {
596
- this.states.setValue("_currentNormal", new Vector(xorv, y, z));
597
- }
598
- this.updateShapeVertexProperties();
599
- }
600
-
601
- model(model, count = 1) {
602
- if (model.vertices.length > 0) {
603
- if (this.geometryBuilder) {
604
- this.geometryBuilder.addRetained(model);
605
- } else {
606
- if (!this.geometryInHash(model.gid)) {
607
- model._edgesToVertices();
608
- this._getOrMakeCachedBuffers(model);
609
- }
610
-
611
- this._drawGeometry(model, { count });
612
- }
613
- }
614
- }
615
-
616
- //////////////////////////////////////////////
617
- // Rendering
618
- //////////////////////////////////////////////
619
-
620
- _drawGeometry(geometry, { mode = constants.TRIANGLES, count = 1 } = {}) {
621
- for (const propName in geometry.userVertexProperties) {
622
- const prop = geometry.userVertexProperties[propName];
623
- this.buffers.user.push(
624
- new RenderBuffer(
625
- prop.getDataSize(),
626
- prop.getSrcName(),
627
- prop.getDstName(),
628
- prop.getName(),
629
- this
630
- )
631
- );
632
- }
633
-
634
- if (
635
- this.states.fillColor &&
636
- geometry.vertices.length >= 3 &&
637
- ![constants.LINES, constants.POINTS].includes(mode)
638
- ) {
639
- this._drawFills(geometry, { mode, count });
640
- }
641
-
642
- if (this.states.strokeColor && geometry.lineVertices.length >= 1) {
643
- this._drawStrokes(geometry, { count });
644
- }
645
-
646
- this.buffers.user = [];
647
- }
648
-
649
- _drawGeometryScaled(model, scaleX, scaleY, scaleZ) {
650
- let originalModelMatrix = this.states.uModelMatrix;
651
- this.states.setValue("uModelMatrix", this.states.uModelMatrix.clone());
652
- try {
653
- this.states.uModelMatrix.scale(scaleX, scaleY, scaleZ);
654
-
655
- if (this.geometryBuilder) {
656
- this.geometryBuilder.addRetained(model);
657
- } else {
658
- this._drawGeometry(model);
659
- }
660
- } finally {
661
- this.states.setValue("uModelMatrix", originalModelMatrix);
662
- }
663
- }
664
-
665
- _drawFills(geometry, { count, mode } = {}) {
666
- this._useVertexColor = geometry.vertexColors.length > 0;
667
-
668
- const shader =
669
- !this._drawingFilter && this.states.userFillShader
670
- ? this.states.userFillShader
671
- : this._getFillShader();
672
- shader.bindShader();
673
- this._setGlobalUniforms(shader);
674
- this._setFillUniforms(shader);
675
- shader.bindTextures();
676
-
677
- for (const buff of this.buffers.fill) {
678
- buff._prepareBuffer(geometry, shader);
679
- }
680
- this._prepareUserAttributes(geometry, shader);
681
- shader.disableRemainingAttributes();
682
-
683
- this._applyColorBlend(
684
- this.states.curFillColor,
685
- geometry.hasFillTransparency()
686
- );
687
-
688
- this._drawBuffers(geometry, { mode, count });
689
-
690
- shader.unbindShader();
691
- }
692
-
693
- _drawStrokes(geometry, { count } = {}) {
694
- const gl = this.GL;
695
-
696
- this._useLineColor = geometry.vertexStrokeColors.length > 0;
697
-
698
- const shader = this._getStrokeShader();
699
- shader.bindShader();
700
- this._setGlobalUniforms(shader);
701
- this._setStrokeUniforms(shader);
702
- shader.bindTextures();
703
-
704
- for (const buff of this.buffers.stroke) {
705
- buff._prepareBuffer(geometry, shader);
706
- }
707
- this._prepareUserAttributes(geometry, shader);
708
- shader.disableRemainingAttributes();
709
-
710
- this._applyColorBlend(
711
- this.states.curStrokeColor,
712
- geometry.hasStrokeTransparency()
713
- );
714
-
715
- if (count === 1) {
716
- gl.drawArrays(gl.TRIANGLES, 0, geometry.lineVertices.length / 3);
717
- } else {
718
- try {
719
- gl.drawArraysInstanced(
720
- gl.TRIANGLES,
721
- 0,
722
- geometry.lineVertices.length / 3,
723
- count
724
- );
725
- } catch (e) {
726
- console.log(
727
- "🌸 p5.js says: Instancing is only supported in WebGL2 mode"
728
- );
729
- }
730
- }
731
-
732
- shader.unbindShader();
733
- }
734
-
735
- _drawPoints(vertices, vertexBuffer) {
736
- const gl = this.GL;
737
- const pointShader = this._getPointShader();
738
- pointShader.bindShader();
739
- this._setGlobalUniforms(pointShader);
740
- this._setPointUniforms(pointShader);
741
- pointShader.bindTextures();
742
-
743
- this._bindBuffer(
744
- vertexBuffer,
745
- gl.ARRAY_BUFFER,
746
- this._vToNArray(vertices),
747
- Float32Array,
748
- gl.STATIC_DRAW
749
- );
750
-
751
- pointShader.enableAttrib(pointShader.attributes.aPosition, 3);
752
-
753
- this._applyColorBlend(this.states.curStrokeColor);
754
-
755
- gl.drawArrays(gl.Points, 0, vertices.length);
756
-
757
- pointShader.unbindShader();
758
- }
759
-
760
- _prepareUserAttributes(geometry, shader) {
761
- for (const buff of this.buffers.user) {
762
- if (!this._pInst.constructor.disableFriendleErrors) {
763
- // Check for the right data size
764
- const prop = geometry.userVertexProperties[buff.attr];
765
- if (prop) {
766
- const adjustedLength = prop.getSrcArray().length / prop.getDataSize();
767
- if (adjustedLength > geometry.vertices.length) {
768
- this._pInst.constructor._friendlyError(
769
- `One of the geometries has a custom vertex property '${prop.getName()}' with more values than vertices. This is probably caused by directly using the Geometry.vertexProperty() method.`,
770
- "vertexProperty()"
771
- );
772
- } else if (adjustedLength < geometry.vertices.length) {
773
- this._pInst.constructor._friendlyError(
774
- `One of the geometries has a custom vertex property '${prop.getName()}' with fewer values than vertices. This is probably caused by directly using the Geometry.vertexProperty() method.`,
775
- "vertexProperty()"
776
- );
777
- }
778
- }
779
- }
780
- buff._prepareBuffer(geometry, shader);
781
- }
782
- }
783
-
784
- _drawBuffers(geometry, { mode = this.GL.TRIANGLES, count }) {
785
- const gl = this.GL;
786
- const glBuffers = this.geometryBufferCache.getCached(geometry);
787
-
788
- if (!glBuffers) return;
789
-
790
- if (glBuffers.indexBuffer) {
791
- this._bindBuffer(glBuffers.indexBuffer, gl.ELEMENT_ARRAY_BUFFER);
792
-
793
- // If this model is using a Uint32Array we need to ensure the
794
- // OES_element_index_uint WebGL extension is enabled.
795
- if (
796
- this._pInst.webglVersion !== constants.WEBGL2 &&
797
- glBuffers.indexBufferType === gl.UNSIGNED_INT
798
- ) {
799
- if (!gl.getExtension("OES_element_index_uint")) {
800
- throw new Error(
801
- "Unable to render a 3d model with > 65535 triangles. Your web browser does not support the WebGL Extension OES_element_index_uint."
802
- );
803
- }
804
- }
805
-
806
- if (count === 1) {
807
- gl.drawElements(
808
- gl.TRIANGLES,
809
- geometry.faces.length * 3,
810
- glBuffers.indexBufferType,
811
- 0
812
- );
813
- } else {
814
- try {
815
- gl.drawElementsInstanced(
816
- gl.TRIANGLES,
817
- geometry.faces.length * 3,
818
- glBuffers.indexBufferType,
819
- 0,
820
- count
821
- );
822
- } catch (e) {
823
- console.log(
824
- "🌸 p5.js says: Instancing is only supported in WebGL2 mode"
825
- );
826
- }
827
- }
828
- } else {
829
- if (count === 1) {
830
- gl.drawArrays(mode, 0, geometry.vertices.length);
831
- } else {
832
- try {
833
- gl.drawArraysInstanced(mode, 0, geometry.vertices.length, count);
834
- } catch (e) {
835
- console.log(
836
- "🌸 p5.js says: Instancing is only supported in WebGL2 mode"
837
- );
838
- }
839
- }
840
- }
841
- }
842
-
843
- _getOrMakeCachedBuffers(geometry) {
844
- return this.geometryBufferCache.ensureCached(geometry);
845
- }
846
-
847
- //////////////////////////////////////////////
848
- // Setting
849
- //////////////////////////////////////////////
850
-
851
- _setAttributeDefaults(pInst) {
852
- // See issue #3850, safer to enable AA in Safari
853
- const applyAA = navigator.userAgent.toLowerCase().includes("safari");
854
- const defaults = {
855
- alpha: true,
856
- depth: true,
857
- stencil: true,
858
- antialias: applyAA,
859
- premultipliedAlpha: true,
860
- preserveDrawingBuffer: true,
861
- perPixelLighting: true,
862
- version: 2,
863
- };
864
- if (pInst._glAttributes === null) {
865
- pInst._glAttributes = defaults;
866
- } else {
867
- pInst._glAttributes = Object.assign(defaults, pInst._glAttributes);
868
- }
869
- return;
870
- }
871
-
872
- _initContext() {
873
- if (this._pInst._glAttributes?.version !== 1) {
874
- // Unless WebGL1 is explicitly asked for, try to create a WebGL2 context
875
- this.drawingContext = this.canvas.getContext(
876
- "webgl2",
877
- this._pInst._glAttributes
878
- );
879
- }
880
- this.webglVersion = this.drawingContext
881
- ? constants.WEBGL2
882
- : constants.WEBGL;
883
- // If this is the main canvas, make sure the global `webglVersion` is set
884
- this._pInst.webglVersion = this.webglVersion;
885
- if (!this.drawingContext) {
886
- // If we were unable to create a WebGL2 context (either because it was
887
- // disabled via `setAttributes({ version: 1 })` or because the device
888
- // doesn't support it), fall back to a WebGL1 context
889
- this.drawingContext =
890
- this.canvas.getContext("webgl", this._pInst._glAttributes) ||
891
- this.canvas.getContext("experimental-webgl", this._pInst._glAttributes);
892
- }
893
- if (this.drawingContext === null) {
894
- throw new Error("Error creating webgl context");
895
- } else {
896
- const gl = this.drawingContext;
897
- gl.enable(gl.DEPTH_TEST);
898
- gl.depthFunc(gl.LEQUAL);
899
- gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
900
- // Make sure all images are loaded into the canvas premultiplied so that
901
- // they match the way we render colors. This will make framebuffer textures
902
- // be encoded the same way as textures from everything else.
903
- gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);
904
- this._viewport = this.drawingContext.getParameter(
905
- this.drawingContext.VIEWPORT
906
- );
907
- }
908
- }
909
-
910
- _getMaxTextureSize() {
911
- const gl = this.drawingContext;
912
- return gl.getParameter(gl.MAX_TEXTURE_SIZE);
913
- }
914
-
915
- _adjustDimensions(width, height) {
916
- if (!this._maxTextureSize) {
917
- this._maxTextureSize = this._getMaxTextureSize();
918
- }
919
- let maxTextureSize = this._maxTextureSize;
920
-
921
- let maxAllowedPixelDimensions = Math.floor(
922
- maxTextureSize / this._pixelDensity
923
- );
924
- let adjustedWidth = Math.min(width, maxAllowedPixelDimensions);
925
- let adjustedHeight = Math.min(height, maxAllowedPixelDimensions);
926
-
927
- if (adjustedWidth !== width || adjustedHeight !== height) {
928
- console.warn(
929
- "Warning: The requested width/height exceeds hardware limits. " +
930
- `Adjusting dimensions to width: ${adjustedWidth}, height: ${adjustedHeight}.`
931
- );
932
- }
933
-
934
- return { adjustedWidth, adjustedHeight };
935
- }
936
-
937
- //This is helper function to reset the context anytime the attributes
938
- //are changed with setAttributes()
939
-
940
- _resetContext(options, callback) {
941
- const w = this.width;
942
- const h = this.height;
943
- const defaultId = this.canvas.id;
944
- const isPGraphics = this._pInst instanceof Graphics;
945
-
946
- // Preserve existing position and styles before recreation
947
- const prevStyle = {
948
- position: this.canvas.style.position,
949
- top: this.canvas.style.top,
950
- left: this.canvas.style.left,
951
- };
952
-
953
- if (isPGraphics) {
954
- // Handle PGraphics: remove and recreate the canvas
955
- const pg = this._pInst;
956
- pg.canvas.parentNode.removeChild(pg.canvas);
957
- pg.canvas = document.createElement("canvas");
958
- const node = pg._pInst._userNode || document.body;
959
- node.appendChild(pg.canvas);
960
- Element.call(pg, pg.canvas, pg._pInst);
961
- // Restore previous width and height
962
- pg.width = w;
963
- pg.height = h;
964
- } else {
965
- // Handle main canvas: remove and recreate it
966
- let c = this.canvas;
967
- if (c) {
968
- c.parentNode.removeChild(c);
969
- }
970
- c = document.createElement("canvas");
971
- c.id = defaultId;
972
- // Attach the new canvas to the correct parent node
973
- if (this._pInst._userNode) {
974
- this._pInst._userNode.appendChild(c);
975
- } else {
976
- document.body.appendChild(c);
977
- }
978
- this._pInst.canvas = c;
979
- this.canvas = c;
980
-
981
- // Restore the saved position
982
- this.canvas.style.position = prevStyle.position;
983
- this.canvas.style.top = prevStyle.top;
984
- this.canvas.style.left = prevStyle.left;
985
- }
986
-
987
- const renderer = new RendererGL(
988
- this._pInst,
989
- w,
990
- h,
991
- !isPGraphics,
992
- this._pInst.canvas
993
- );
994
- this._pInst._renderer = renderer;
995
-
996
- renderer._applyDefaults();
997
-
998
- if (typeof callback === "function") {
999
- //setTimeout with 0 forces the task to the back of the queue, this ensures that
1000
- //we finish switching out the renderer
1001
- setTimeout(() => {
1002
- callback.apply(window._renderer, options);
1003
- }, 0);
1004
- }
1005
- }
1006
-
1007
- _update() {
1008
- // reset model view and apply initial camera transform
1009
- // (containing only look at info; no projection).
1010
- this.states.setValue("uModelMatrix", this.states.uModelMatrix.clone());
1011
- this.states.uModelMatrix.reset();
1012
- this.states.setValue("uViewMatrix", this.states.uViewMatrix.clone());
1013
- this.states.uViewMatrix.set(this.states.curCamera.cameraMatrix);
1014
-
1015
- // reset light data for new frame.
1016
-
1017
- this.states.setValue("ambientLightColors", []);
1018
- this.states.setValue("specularColors", [1, 1, 1]);
1019
-
1020
- this.states.setValue("directionalLightDirections", []);
1021
- this.states.setValue("directionalLightDiffuseColors", []);
1022
- this.states.setValue("directionalLightSpecularColors", []);
1023
-
1024
- this.states.setValue("pointLightPositions", []);
1025
- this.states.setValue("pointLightDiffuseColors", []);
1026
- this.states.setValue("pointLightSpecularColors", []);
1027
-
1028
- this.states.setValue("spotLightPositions", []);
1029
- this.states.setValue("spotLightDirections", []);
1030
- this.states.setValue("spotLightDiffuseColors", []);
1031
- this.states.setValue("spotLightSpecularColors", []);
1032
- this.states.setValue("spotLightAngle", []);
1033
- this.states.setValue("spotLightConc", []);
1034
-
1035
- this.states.setValue("enableLighting", false);
1036
-
1037
- //reset tint value for new frame
1038
- this.states.setValue("tint", [255, 255, 255, 255]);
1039
-
1040
- //Clear depth every frame
1041
- this.GL.clearStencil(0);
1042
- this.GL.clear(this.GL.DEPTH_BUFFER_BIT | this.GL.STENCIL_BUFFER_BIT);
1043
- if (!this._userEnabledStencil) {
1044
- this._internalDisable.call(this.GL, this.GL.STENCIL_TEST);
1045
- }
1046
-
1047
- }
1048
-
1049
- /**
1050
- * [background description]
1051
- */
1052
- background(...args) {
1053
- const _col = this._pInst.color(...args);
1054
- this.clear(..._col._getRGBA());
1055
- }
1056
-
1057
- //////////////////////////////////////////////
1058
- // Positioning
1059
- //////////////////////////////////////////////
1060
-
1061
- get uModelMatrix() {
1062
- return this.states.uModelMatrix;
1063
- }
1064
-
1065
- get uViewMatrix() {
1066
- return this.states.uViewMatrix;
1067
- }
1068
-
1069
- get uPMatrix() {
1070
- return this.states.uPMatrix;
1071
- }
1072
-
1073
- get uMVMatrix() {
1074
- const m = this.uModelMatrix.copy();
1075
- m.mult(this.uViewMatrix);
1076
- return m;
1077
- }
1078
-
1079
- /**
1080
- * Get a matrix from world-space to screen-space
1081
- */
1082
- getWorldToScreenMatrix() {
1083
- const modelMatrix = this.states.uModelMatrix;
1084
- const viewMatrix = this.states.uViewMatrix;
1085
- const projectionMatrix = this.states.uPMatrix;
1086
- const projectedToScreenMatrix = new Matrix(4);
1087
- projectedToScreenMatrix.scale(this.width, this.height, 1);
1088
- projectedToScreenMatrix.translate([0.5, 0.5, 0.5]);
1089
- projectedToScreenMatrix.scale(0.5, -0.5, 0.5);
1090
-
1091
- const modelViewMatrix = modelMatrix.copy().mult(viewMatrix);
1092
- const modelViewProjectionMatrix = modelViewMatrix.mult(projectionMatrix);
1093
- const worldToScreenMatrix = modelViewProjectionMatrix.mult(projectedToScreenMatrix);
1094
- return worldToScreenMatrix;
1095
- }
1096
-
1097
- //////////////////////////////////////////////
1098
- // COLOR
1099
- //////////////////////////////////////////////
1100
- /**
1101
- * Basic fill material for geometry with a given color
1102
- * @param {Number|Number[]|String|p5.Color} v1 gray value,
1103
- * red or hue value (depending on the current color mode),
1104
- * or color Array, or CSS color string
1105
- * @param {Number} [v2] green or saturation value
1106
- * @param {Number} [v3] blue or brightness value
1107
- * @param {Number} [a] opacity
1108
- * @chainable
1109
- * @example
1110
- * <div>
1111
- * <code>
1112
- * function setup() {
1113
- * createCanvas(200, 200, WEBGL);
1114
- * }
1115
- *
1116
- * function draw() {
1117
- * background(0);
1118
- * noStroke();
1119
- * fill(100, 100, 240);
1120
- * rotateX(frameCount * 0.01);
1121
- * rotateY(frameCount * 0.01);
1122
- * box(75, 75, 75);
1123
- * }
1124
- * </code>
1125
- * </div>
1126
- *
1127
- * @alt
1128
- * black canvas with purple cube spinning
1129
- */
1130
- fill(...args) {
1131
- super.fill(...args);
1132
- //see material.js for more info on color blending in webgl
1133
- // const color = fn.color.apply(this._pInst, arguments);
1134
- const color = this.states.fillColor;
1135
- this.states.setValue("curFillColor", color._array);
1136
- this.states.setValue("drawMode", constants.FILL);
1137
- this.states.setValue("_useNormalMaterial", false);
1138
- this.states.setValue("_tex", null);
1139
- }
1140
-
1141
- /**
1142
- * Basic stroke material for geometry with a given color
1143
- * @param {Number|Number[]|String|p5.Color} v1 gray value,
1144
- * red or hue value (depending on the current color mode),
1145
- * or color Array, or CSS color string
1146
- * @param {Number} [v2] green or saturation value
1147
- * @param {Number} [v3] blue or brightness value
1148
- * @param {Number} [a] opacity
1149
- * @example
1150
- * <div>
1151
- * <code>
1152
- * function setup() {
1153
- * createCanvas(200, 200, WEBGL);
1154
- * }
1155
- *
1156
- * function draw() {
1157
- * background(0);
1158
- * stroke(240, 150, 150);
1159
- * fill(100, 100, 240);
1160
- * rotateX(frameCount * 0.01);
1161
- * rotateY(frameCount * 0.01);
1162
- * box(75, 75, 75);
1163
- * }
1164
- * </code>
1165
- * </div>
1166
- *
1167
- * @alt
1168
- * black canvas with purple cube with pink outline spinning
1169
- */
1170
- stroke(...args) {
1171
- super.stroke(...args);
1172
- // const color = fn.color.apply(this._pInst, arguments);
1173
- this.states.setValue("curStrokeColor", this.states.strokeColor._array);
1174
- }
1175
-
1176
- getCommonVertexProperties() {
1177
- return {
1178
- ...super.getCommonVertexProperties(),
1179
- stroke: this.states.strokeColor,
1180
- fill: this.states.fillColor,
1181
- normal: this.states._currentNormal,
1182
- };
1183
- }
1184
-
1185
- getSupportedIndividualVertexProperties() {
1186
- return {
1187
- textureCoordinates: true,
1188
- };
1189
- }
1190
-
1191
- strokeCap(cap) {
1192
- this.curStrokeCap = cap;
1193
- }
1194
-
1195
- strokeJoin(join) {
1196
- this.curStrokeJoin = join;
1197
- }
1198
- getFilterLayer() {
1199
- if (!this.filterLayer) {
1200
- this.filterLayer = new Framebuffer(this);
1201
- }
1202
- return this.filterLayer;
1203
- }
1204
- getFilterLayerTemp() {
1205
- if (!this.filterLayerTemp) {
1206
- this.filterLayerTemp = new Framebuffer(this);
1207
- }
1208
- return this.filterLayerTemp;
1209
- }
1210
- matchSize(fboToMatch, target) {
1211
- if (
1212
- fboToMatch.width !== target.width ||
1213
- fboToMatch.height !== target.height
1214
- ) {
1215
- fboToMatch.resize(target.width, target.height);
1216
- }
1217
-
1218
- if (fboToMatch.pixelDensity() !== target.pixelDensity()) {
1219
- fboToMatch.pixelDensity(target.pixelDensity());
1220
- }
1221
- }
1222
- filter(...args) {
1223
- let fbo = this.getFilterLayer();
1224
-
1225
- // use internal shader for filter constants BLUR, INVERT, etc
1226
- let filterParameter = undefined;
1227
- let operation = undefined;
1228
- if (typeof args[0] === "string") {
1229
- operation = args[0];
1230
- let useDefaultParam =
1231
- operation in filterParamDefaults && args[1] === undefined;
1232
- filterParameter = useDefaultParam
1233
- ? filterParamDefaults[operation]
1234
- : args[1];
1235
-
1236
- // Create and store shader for constants once on initial filter call.
1237
- // Need to store multiple in case user calls different filters,
1238
- // eg. filter(BLUR) then filter(GRAY)
1239
- if (!(operation in this.defaultFilterShaders)) {
1240
- this.defaultFilterShaders[operation] = new Shader(
1241
- fbo.renderer,
1242
- filterShaderVert,
1243
- filterShaderFrags[operation]
1244
- );
1245
- }
1246
- this.states.setValue(
1247
- "filterShader",
1248
- this.defaultFilterShaders[operation]
1249
- );
1250
- }
1251
- // use custom user-supplied shader
1252
- else {
1253
- this.states.setValue("filterShader", args[0]);
1254
- }
1255
-
1256
- // Setting the target to the framebuffer when applying a filter to a framebuffer.
1257
-
1258
- const target = this.activeFramebuffer() || this;
1259
-
1260
- // Resize the framebuffer 'fbo' and adjust its pixel density if it doesn't match the target.
1261
- this.matchSize(fbo, target);
1262
-
1263
- fbo.draw(() => this.clear()); // prevent undesirable feedback effects accumulating secretly.
1264
-
1265
- let texelSize = [
1266
- 1 / (target.width * target.pixelDensity()),
1267
- 1 / (target.height * target.pixelDensity()),
1268
- ];
1269
-
1270
- // apply blur shader with multiple passes.
1271
- if (operation === constants.BLUR) {
1272
- // Treating 'tmp' as a framebuffer.
1273
- const tmp = this.getFilterLayerTemp();
1274
- // Resize the framebuffer 'tmp' and adjust its pixel density if it doesn't match the target.
1275
- this.matchSize(tmp, target);
1276
- // setup
1277
- this.push();
1278
- this.states.setValue("strokeColor", null);
1279
- this.blendMode(constants.BLEND);
1280
-
1281
- // draw main to temp buffer
1282
- this.shader(this.states.filterShader);
1283
- this.states.filterShader.setUniform("texelSize", texelSize);
1284
- this.states.filterShader.setUniform("canvasSize", [
1285
- target.width,
1286
- target.height,
1287
- ]);
1288
- this.states.filterShader.setUniform(
1289
- "radius",
1290
- Math.max(1, filterParameter)
1291
- );
1292
-
1293
- // Horiz pass: draw `target` to `tmp`
1294
- tmp.draw(() => {
1295
- this.states.filterShader.setUniform("direction", [1, 0]);
1296
- this.states.filterShader.setUniform("tex0", target);
1297
- this.clear();
1298
- this.shader(this.states.filterShader);
1299
- this.noLights();
1300
- this.plane(target.width, target.height);
1301
- });
1302
-
1303
- // Vert pass: draw `tmp` to `fbo`
1304
- fbo.draw(() => {
1305
- this.states.filterShader.setUniform("direction", [0, 1]);
1306
- this.states.filterShader.setUniform("tex0", tmp);
1307
- this.clear();
1308
- this.shader(this.states.filterShader);
1309
- this.noLights();
1310
- this.plane(target.width, target.height);
1311
- });
1312
-
1313
- this.pop();
1314
- }
1315
- // every other non-blur shader uses single pass
1316
- else {
1317
- fbo.draw(() => {
1318
- this.states.setValue("strokeColor", null);
1319
- this.blendMode(constants.BLEND);
1320
- this.shader(this.states.filterShader);
1321
- this.states.filterShader.setUniform("tex0", target);
1322
- this.states.filterShader.setUniform("texelSize", texelSize);
1323
- this.states.filterShader.setUniform("canvasSize", [
1324
- target.width,
1325
- target.height,
1326
- ]);
1327
- // filterParameter uniform only used for POSTERIZE, and THRESHOLD
1328
- // but shouldn't hurt to always set
1329
- this.states.filterShader.setUniform("filterParameter", filterParameter);
1330
- this.noLights();
1331
- this.plane(target.width, target.height);
1332
- });
1333
- }
1334
- // draw fbo contents onto main renderer.
1335
- this.push();
1336
- this.states.setValue("strokeColor", null);
1337
- this.clear();
1338
- this.push();
1339
- this.states.setValue("imageMode", constants.CORNER);
1340
- this.blendMode(constants.BLEND);
1341
- target.filterCamera._resize();
1342
- this.setCamera(target.filterCamera);
1343
- this.resetMatrix();
1344
- this._drawingFilter = true;
1345
- this.image(
1346
- fbo,
1347
- 0,
1348
- 0,
1349
- this.width,
1350
- this.height,
1351
- -target.width / 2,
1352
- -target.height / 2,
1353
- target.width,
1354
- target.height
1355
- );
1356
- this._drawingFilter = false;
1357
- this.clearDepth();
1358
- this.pop();
1359
- this.pop();
1360
- }
1361
-
1362
- // Pass this off to the host instance so that we can treat a renderer and a
1363
- // framebuffer the same in filter()
1364
-
1365
- pixelDensity(newDensity) {
1366
- if (newDensity) {
1367
- return this._pInst.pixelDensity(newDensity);
1368
- }
1369
- return this._pInst.pixelDensity();
1370
- }
1371
-
1372
- blendMode(mode) {
1373
- if (
1374
- mode === constants.DARKEST ||
1375
- mode === constants.LIGHTEST ||
1376
- mode === constants.ADD ||
1377
- mode === constants.BLEND ||
1378
- mode === constants.SUBTRACT ||
1379
- mode === constants.SCREEN ||
1380
- mode === constants.EXCLUSION ||
1381
- mode === constants.REPLACE ||
1382
- mode === constants.MULTIPLY ||
1383
- mode === constants.REMOVE
1384
- )
1385
- this.states.setValue("curBlendMode", mode);
1386
- else if (
1387
- mode === constants.BURN ||
1388
- mode === constants.OVERLAY ||
1389
- mode === constants.HARD_LIGHT ||
1390
- mode === constants.SOFT_LIGHT ||
1391
- mode === constants.DODGE
1392
- ) {
1393
- console.warn(
1394
- "BURN, OVERLAY, HARD_LIGHT, SOFT_LIGHT, and DODGE only work for blendMode in 2D mode."
1395
- );
1396
- }
1397
- }
1398
-
1399
- erase(opacityFill, opacityStroke) {
1400
- if (!this._isErasing) {
1401
- this.preEraseBlend = this.states.curBlendMode;
1402
- this._isErasing = true;
1403
- this.blendMode(constants.REMOVE);
1404
- this._cachedFillStyle = this.states.curFillColor.slice();
1405
- this.states.setValue("curFillColor", [1, 1, 1, opacityFill / 255]);
1406
- this._cachedStrokeStyle = this.states.curStrokeColor.slice();
1407
- this.states.setValue("curStrokeColor", [1, 1, 1, opacityStroke / 255]);
1408
- }
1409
- }
1410
-
1411
- noErase() {
1412
- if (this._isErasing) {
1413
- // Restore colors
1414
- this.states.setValue("curFillColor", this._cachedFillStyle.slice());
1415
- this.states.setValue("curStrokeColor", this._cachedStrokeStyle.slice());
1416
- // Restore blend mode
1417
- this.states.setValue("curBlendMode", this.preEraseBlend);
1418
- this.blendMode(this.preEraseBlend);
1419
- // Ensure that _applyBlendMode() sets preEraseBlend back to the original blend mode
1420
- this._isErasing = false;
1421
- this._applyBlendMode();
1422
- }
1423
- }
1424
-
1425
- drawTarget() {
1426
- return this.activeFramebuffers[this.activeFramebuffers.length - 1] || this;
1427
- }
1428
-
1429
- beginClip(options = {}) {
1430
- super.beginClip(options);
1431
-
1432
- this.drawTarget()._isClipApplied = true;
1433
-
1434
- const gl = this.GL;
1435
- gl.clearStencil(0);
1436
- gl.clear(gl.STENCIL_BUFFER_BIT);
1437
- this._internalEnable.call(gl, gl.STENCIL_TEST);
1438
- this._stencilTestOn = true;
1439
- gl.stencilFunc(
1440
- gl.ALWAYS, // the test
1441
- 1, // reference value
1442
- 0xff // mask
1443
- );
1444
- gl.stencilOp(
1445
- gl.KEEP, // what to do if the stencil test fails
1446
- gl.KEEP, // what to do if the depth test fails
1447
- gl.REPLACE // what to do if both tests pass
1448
- );
1449
- gl.disable(gl.DEPTH_TEST);
1450
-
1451
- this.push();
1452
- this.resetShader();
1453
- if (this.states.fillColor) this.fill(0, 0);
1454
- if (this.states.strokeColor) this.stroke(0, 0);
1455
- }
1456
-
1457
- endClip() {
1458
- this.pop();
1459
-
1460
- const gl = this.GL;
1461
- gl.stencilOp(
1462
- gl.KEEP, // what to do if the stencil test fails
1463
- gl.KEEP, // what to do if the depth test fails
1464
- gl.KEEP // what to do if both tests pass
1465
- );
1466
- gl.stencilFunc(
1467
- this._clipInvert ? gl.EQUAL : gl.NOTEQUAL, // the test
1468
- 0, // reference value
1469
- 0xff // mask
1470
- );
1471
- gl.enable(gl.DEPTH_TEST);
1472
-
1473
- // Mark the depth at which the clip has been applied so that we can clear it
1474
- // when we pop past this depth
1475
- this._clipDepths.push(this._pushPopDepth);
1476
-
1477
- super.endClip();
1478
- }
1479
-
1480
- _clearClip() {
1481
- this.GL.clearStencil(1);
1482
- this.GL.clear(this.GL.STENCIL_BUFFER_BIT);
1483
- if (this._clipDepths.length > 0) {
1484
- this._clipDepths.pop();
1485
- }
1486
- this.drawTarget()._isClipApplied = false;
1487
- }
1488
-
1489
- // x,y are canvas-relative (pre-scaled by _pixelDensity)
1490
- _getPixel(x, y) {
1491
- const gl = this.GL;
1492
- return readPixelWebGL(
1493
- gl,
1494
- null,
1495
- x,
1496
- y,
1497
- gl.RGBA,
1498
- gl.UNSIGNED_BYTE,
1499
- this._pInst.height * this._pInst.pixelDensity()
1500
- );
1501
- }
1502
-
1503
- /**
1504
- * Loads the pixels data for this canvas into the pixels[] attribute.
1505
- * Note that updatePixels() and set() do not work.
1506
- * Any pixel manipulation must be done directly to the pixels[] array.
1507
- *
1508
- * @private
1509
- */
1510
- loadPixels() {
1511
- //@todo_FES
1512
- if (this._pInst._glAttributes.preserveDrawingBuffer !== true) {
1513
- console.log(
1514
- "loadPixels only works in WebGL when preserveDrawingBuffer " +
1515
- "is true."
1516
- );
1517
- return;
1518
- }
1519
-
1520
- const pd = this._pixelDensity;
1521
- const gl = this.GL;
1522
-
1523
- this.pixels = readPixelsWebGL(
1524
- this.pixels,
1525
- gl,
1526
- null,
1527
- 0,
1528
- 0,
1529
- this.width * pd,
1530
- this.height * pd,
1531
- gl.RGBA,
1532
- gl.UNSIGNED_BYTE,
1533
- this.height * pd
1534
- );
1535
- }
1536
-
1537
- updatePixels() {
1538
- const fbo = this._getTempFramebuffer();
1539
- fbo.pixels = this.pixels;
1540
- fbo.updatePixels();
1541
- this.push();
1542
- this.resetMatrix();
1543
- this.clear();
1544
- this.states.setValue("imageMode", constants.CORNER);
1545
- this.image(
1546
- fbo,
1547
- 0,
1548
- 0,
1549
- fbo.width,
1550
- fbo.height,
1551
- -fbo.width / 2,
1552
- -fbo.height / 2,
1553
- fbo.width,
1554
- fbo.height
1555
- );
1556
- this.pop();
1557
- this.GL.clearDepth(1);
1558
- this.GL.clear(this.GL.DEPTH_BUFFER_BIT);
1559
- }
1560
-
1561
- /**
1562
- * @private
1563
- * @returns {p5.Framebuffer} A p5.Framebuffer set to match the size and settings
1564
- * of the renderer's canvas. It will be created if it does not yet exist, and
1565
- * reused if it does.
1566
- */
1567
- _getTempFramebuffer() {
1568
- if (!this._tempFramebuffer) {
1569
- this._tempFramebuffer = new Framebuffer(this, {
1570
- format: constants.UNSIGNED_BYTE,
1571
- useDepth: this._pInst._glAttributes.depth,
1572
- depthFormat: constants.UNSIGNED_INT,
1573
- antialias: this._pInst._glAttributes.antialias,
1574
- });
1575
- }
1576
- return this._tempFramebuffer;
1577
- }
1578
-
1579
- //////////////////////////////////////////////
1580
- // HASH | for geometry
1581
- //////////////////////////////////////////////
1582
-
1583
- geometryInHash(gid) {
1584
- return this.geometryBufferCache.isCached(gid);
1585
- }
1586
-
1587
- viewport(w, h) {
1588
- this._viewport = [0, 0, w, h];
1589
- this.GL.viewport(0, 0, w, h);
1590
- }
1591
-
1592
- /**
1593
- * [resize description]
1594
- * @private
1595
- * @param {Number} w [description]
1596
- * @param {Number} h [description]
1597
- */
1598
- resize(w, h) {
1599
- super.resize(w, h);
1600
-
1601
- // save canvas properties
1602
- const props = {};
1603
- for (const key in this.drawingContext) {
1604
- const val = this.drawingContext[key];
1605
- if (typeof val !== "object" && typeof val !== "function") {
1606
- props[key] = val;
1607
- }
1608
- }
1609
-
1610
- const dimensions = this._adjustDimensions(w, h);
1611
- w = dimensions.adjustedWidth;
1612
- h = dimensions.adjustedHeight;
1613
-
1614
- this.width = w;
1615
- this.height = h;
1616
-
1617
- this.canvas.width = w * this._pixelDensity;
1618
- this.canvas.height = h * this._pixelDensity;
1619
- this.canvas.style.width = `${w}px`;
1620
- this.canvas.style.height = `${h}px`;
1621
- this._origViewport = {
1622
- width: this.GL.drawingBufferWidth,
1623
- height: this.GL.drawingBufferHeight,
1624
- };
1625
- this.viewport(this._origViewport.width, this._origViewport.height);
1626
-
1627
- this.states.curCamera._resize();
1628
-
1629
- //resize pixels buffer
1630
- if (typeof this.pixels !== "undefined") {
1631
- this.pixels = new Uint8Array(
1632
- this.GL.drawingBufferWidth * this.GL.drawingBufferHeight * 4
1633
- );
1634
- }
1635
-
1636
- for (const framebuffer of this.framebuffers) {
1637
- // Notify framebuffers of the resize so that any auto-sized framebuffers
1638
- // can also update their size
1639
- framebuffer._canvasSizeChanged();
1640
- }
1641
-
1642
- // reset canvas properties
1643
- for (const savedKey in props) {
1644
- try {
1645
- this.drawingContext[savedKey] = props[savedKey];
1646
- } catch (err) {
1647
- // ignore read-only property errors
1648
- }
1649
- }
1650
- }
1651
-
1652
- /**
1653
- * clears color and depth buffers
1654
- * with r,g,b,a
1655
- * @private
1656
- * @param {Number} r normalized red val.
1657
- * @param {Number} g normalized green val.
1658
- * @param {Number} b normalized blue val.
1659
- * @param {Number} a normalized alpha val.
1660
- */
1661
- clear(...args) {
1662
- const _r = args[0] || 0;
1663
- const _g = args[1] || 0;
1664
- const _b = args[2] || 0;
1665
- let _a = args[3] || 0;
1666
-
1667
- const activeFramebuffer = this.activeFramebuffer();
1668
- if (
1669
- activeFramebuffer &&
1670
- activeFramebuffer.format === constants.UNSIGNED_BYTE &&
1671
- !activeFramebuffer.antialias &&
1672
- _a === 0
1673
- ) {
1674
- // Drivers on Intel Macs check for 0,0,0,0 exactly when drawing to a
1675
- // framebuffer and ignore the command if it's the only drawing command to
1676
- // the framebuffer. To work around it, we can set the alpha to a value so
1677
- // low that it still rounds down to 0, but that circumvents the buggy
1678
- // check in the driver.
1679
- _a = 1e-10;
1680
- }
1681
-
1682
- this.GL.clearColor(_r * _a, _g * _a, _b * _a, _a);
1683
- this.GL.clearDepth(1);
1684
- this.GL.clear(this.GL.COLOR_BUFFER_BIT | this.GL.DEPTH_BUFFER_BIT);
1685
- }
1686
-
1687
- /**
1688
- * Resets all depth information so that nothing previously drawn will
1689
- * occlude anything subsequently drawn.
1690
- */
1691
- clearDepth(depth = 1) {
1692
- this.GL.clearDepth(depth);
1693
- this.GL.clear(this.GL.DEPTH_BUFFER_BIT);
1694
- }
1695
-
1696
- applyMatrix(a, b, c, d, e, f) {
1697
- this.states.setValue("uModelMatrix", this.states.uModelMatrix.clone());
1698
- if (arguments.length === 16) {
1699
- // this.states.uModelMatrix.apply(arguments);
1700
- Matrix.prototype.apply.apply(this.states.uModelMatrix, arguments);
1701
- } else {
1702
- this.states.uModelMatrix.apply([
1703
- a,
1704
- b,
1705
- 0,
1706
- 0,
1707
- c,
1708
- d,
1709
- 0,
1710
- 0,
1711
- 0,
1712
- 0,
1713
- 1,
1714
- 0,
1715
- e,
1716
- f,
1717
- 0,
1718
- 1,
1719
- ]);
1720
- }
1721
- }
1722
-
1723
- /**
1724
- * [translate description]
1725
- * @private
1726
- * @param {Number} x [description]
1727
- * @param {Number} y [description]
1728
- * @param {Number} z [description]
1729
- * @chainable
1730
- * @todo implement handle for components or vector as args
1731
- */
1732
- translate(x, y, z) {
1733
- if (x instanceof Vector) {
1734
- z = x.z;
1735
- y = x.y;
1736
- x = x.x;
1737
- }
1738
- this.states.setValue("uModelMatrix", this.states.uModelMatrix.clone());
1739
- this.states.uModelMatrix.translate([x, y, z]);
1740
- return this;
1741
- }
1742
-
1743
- /**
1744
- * Scales the Model View Matrix by a vector
1745
- * @private
1746
- * @param {Number | p5.Vector | Array} x [description]
1747
- * @param {Number} [y] y-axis scalar
1748
- * @param {Number} [z] z-axis scalar
1749
- * @chainable
1750
- */
1751
- scale(x, y, z) {
1752
- this.states.setValue("uModelMatrix", this.states.uModelMatrix.clone());
1753
- this.states.uModelMatrix.scale(x, y, z);
1754
- return this;
1755
- }
1756
-
1757
- rotate(rad, axis) {
1758
- if (typeof axis === "undefined") {
1759
- return this.rotateZ(rad);
1760
- }
1761
- this.states.setValue("uModelMatrix", this.states.uModelMatrix.clone());
1762
- Matrix.prototype.rotate4x4.apply(this.states.uModelMatrix, arguments);
1763
- return this;
1764
- }
1765
-
1766
- rotateX(rad) {
1767
- this.rotate(rad, 1, 0, 0);
1768
- return this;
1769
- }
1770
-
1771
- rotateY(rad) {
1772
- this.rotate(rad, 0, 1, 0);
1773
- return this;
1774
- }
1775
-
1776
- rotateZ(rad) {
1777
- this.rotate(rad, 0, 0, 1);
1778
- return this;
1779
- }
1780
-
1781
- pop(...args) {
1782
- if (
1783
- this._clipDepths.length > 0 &&
1784
- this._pushPopDepth === this._clipDepths[this._clipDepths.length - 1]
1785
- ) {
1786
- this._clearClip();
1787
- if (!this._userEnabledStencil) {
1788
- this._internalDisable.call(this.GL, this.GL.STENCIL_TEST);
1789
- }
1790
-
1791
- // Reset saved state
1792
- // this._userEnabledStencil = this._savedStencilTestState;
1793
- }
1794
- super.pop(...args);
1795
- this._applyStencilTestIfClipping();
1796
- }
1797
- _applyStencilTestIfClipping() {
1798
- const drawTarget = this.drawTarget();
1799
- if (drawTarget._isClipApplied !== this._stencilTestOn) {
1800
- if (drawTarget._isClipApplied) {
1801
- this._internalEnable.call(this.GL, this.GL.STENCIL_TEST);
1802
- this._stencilTestOn = true;
1803
- } else {
1804
- if (!this._userEnabledStencil) {
1805
- this._internalDisable.call(this.GL, this.GL.STENCIL_TEST);
1806
- }
1807
- this._stencilTestOn = false;
1808
- }
1809
- }
1810
- }
1811
- resetMatrix() {
1812
- this.states.setValue("uModelMatrix", this.states.uModelMatrix.clone());
1813
- this.states.uModelMatrix.reset();
1814
- this.states.setValue("uViewMatrix", this.states.uViewMatrix.clone());
1815
- this.states.uViewMatrix.set(this.states.curCamera.cameraMatrix);
1816
- return this;
1817
- }
1818
-
1819
- //////////////////////////////////////////////
1820
- // SHADER
1821
- //////////////////////////////////////////////
1822
-
1823
- /*
1824
- * shaders are created and cached on a per-renderer basis,
1825
- * on the grounds that each renderer will have its own gl context
1826
- * and the shader must be valid in that context.
1827
- */
1828
-
1829
- _getStrokeShader() {
1830
- // select the stroke shader to use
1831
- const stroke = this.states.userStrokeShader;
1832
- if (stroke) {
1833
- return stroke;
1834
- }
1835
- return this._getLineShader();
1836
- }
1837
-
1838
- _getSphereMapping(img) {
1839
- if (!this.sphereMapping) {
1840
- this.sphereMapping = this._pInst.createFilterShader(sphereMapping);
1841
- }
1842
- this.scratchMat3.inverseTranspose4x4(this.states.uViewMatrix);
1843
- this.scratchMat3.invert(this.scratchMat3); // uNMMatrix is 3x3
1844
- this.sphereMapping.setUniform("uFovY", this.states.curCamera.cameraFOV);
1845
- this.sphereMapping.setUniform("uAspect", this.states.curCamera.aspectRatio);
1846
- this.sphereMapping.setUniform("uNewNormalMatrix", this.scratchMat3.mat3);
1847
- this.sphereMapping.setUniform("uEnvMap", img);
1848
- return this.sphereMapping;
1849
- }
1850
-
1851
- /*
1852
- * This method will handle both image shaders and
1853
- * fill shaders, returning the appropriate shader
1854
- * depending on the current context (image or shape).
1855
- */
1856
- _getFillShader() {
1857
- // If drawing an image, check for user-defined image shader and filters
1858
- if (this._drawingImage) {
1859
- // Use user-defined image shader if available and no filter is applied
1860
- if (this.states.userImageShader && !this._drawingFilter) {
1861
- return this.states.userImageShader;
1862
- } else {
1863
- return this._getLightShader(); // Fallback to light shader
1864
- }
1865
- }
1866
- // If user has defined a fill shader, return that
1867
- else if (this.states.userFillShader) {
1868
- return this.states.userFillShader;
1869
- }
1870
- // Use normal shader if normal material is active
1871
- else if (this.states._useNormalMaterial) {
1872
- return this._getNormalShader();
1873
- }
1874
- // Use light shader if lighting or textures are enabled
1875
- else if (this.states.enableLighting || this.states._tex) {
1876
- return this._getLightShader();
1877
- }
1878
- // Default to color shader if no other conditions are met
1879
- return this._getColorShader();
1880
- }
1881
-
1882
- _getPointShader() {
1883
- // select the point shader to use
1884
- const point = this.states.userPointShader;
1885
- if (!point || !point.isPointShader()) {
1886
- return this._getPointShader();
1887
- }
1888
- return point;
1889
- }
1890
-
1891
- baseMaterialShader() {
1892
- if (!this._pInst._glAttributes.perPixelLighting) {
1893
- throw new Error(
1894
- "The material shader does not support hooks without perPixelLighting. Try turning it back on."
1895
- );
1896
- }
1897
- return this._getLightShader();
1898
- }
1899
-
1900
- _getLightShader() {
1901
- if (!this._defaultLightShader) {
1902
- if (this._pInst._glAttributes.perPixelLighting) {
1903
- this._defaultLightShader = new Shader(
1904
- this,
1905
- this._webGL2CompatibilityPrefix("vert", "highp") +
1906
- defaultShaders.phongVert,
1907
- this._webGL2CompatibilityPrefix("frag", "highp") +
1908
- defaultShaders.phongFrag,
1909
- {
1910
- vertex: {
1911
- "void beforeVertex": "() {}",
1912
- "Vertex getObjectInputs": "(Vertex inputs) { return inputs; }",
1913
- "Vertex getWorldInputs": "(Vertex inputs) { return inputs; }",
1914
- "Vertex getCameraInputs": "(Vertex inputs) { return inputs; }",
1915
- "void afterVertex": "() {}",
1916
- },
1917
- fragment: {
1918
- "void beforeFragment": "() {}",
1919
- "Inputs getPixelInputs": "(Inputs inputs) { return inputs; }",
1920
- "vec4 combineColors": `(ColorComponents components) {
1921
- vec4 color = vec4(0.);
1922
- color.rgb += components.diffuse * components.baseColor;
1923
- color.rgb += components.ambient * components.ambientColor;
1924
- color.rgb += components.specular * components.specularColor;
1925
- color.rgb += components.emissive;
1926
- color.a = components.opacity;
1927
- return color;
1928
- }`,
1929
- "vec4 getFinalColor": "(vec4 color) { return color; }",
1930
- "void afterFragment": "() {}",
1931
- },
1932
- }
1933
- );
1934
- } else {
1935
- this._defaultLightShader = new Shader(
1936
- this,
1937
- this._webGL2CompatibilityPrefix("vert", "highp") +
1938
- defaultShaders.lightVert,
1939
- this._webGL2CompatibilityPrefix("frag", "highp") +
1940
- defaultShaders.lightTextureFrag
1941
- );
1942
- }
1943
- }
1944
-
1945
- return this._defaultLightShader;
1946
- }
1947
-
1948
- baseNormalShader() {
1949
- return this._getNormalShader();
1950
- }
1951
-
1952
- _getNormalShader() {
1953
- if (!this._defaultNormalShader) {
1954
- this._defaultNormalShader = new Shader(
1955
- this,
1956
- this._webGL2CompatibilityPrefix("vert", "mediump") +
1957
- defaultShaders.normalVert,
1958
- this._webGL2CompatibilityPrefix("frag", "mediump") +
1959
- defaultShaders.normalFrag,
1960
- {
1961
- vertex: {
1962
- "void beforeVertex": "() {}",
1963
- "Vertex getObjectInputs": "(Vertex inputs) { return inputs; }",
1964
- "Vertex getWorldInputs": "(Vertex inputs) { return inputs; }",
1965
- "Vertex getCameraInputs": "(Vertex inputs) { return inputs; }",
1966
- "void afterVertex": "() {}",
1967
- },
1968
- fragment: {
1969
- "void beforeFragment": "() {}",
1970
- "vec4 getFinalColor": "(vec4 color) { return color; }",
1971
- "void afterFragment": "() {}",
1972
- },
1973
- }
1974
- );
1975
- }
1976
-
1977
- return this._defaultNormalShader;
1978
- }
1979
-
1980
- baseColorShader() {
1981
- return this._getColorShader();
1982
- }
1983
-
1984
- _getColorShader() {
1985
- if (!this._defaultColorShader) {
1986
- this._defaultColorShader = new Shader(
1987
- this,
1988
- this._webGL2CompatibilityPrefix("vert", "mediump") +
1989
- defaultShaders.normalVert,
1990
- this._webGL2CompatibilityPrefix("frag", "mediump") +
1991
- defaultShaders.basicFrag,
1992
- {
1993
- vertex: {
1994
- "void beforeVertex": "() {}",
1995
- "Vertex getObjectInputs": "(Vertex inputs) { return inputs; }",
1996
- "Vertex getWorldInputs": "(Vertex inputs) { return inputs; }",
1997
- "Vertex getCameraInputs": "(Vertex inputs) { return inputs; }",
1998
- "void afterVertex": "() {}",
1999
- },
2000
- fragment: {
2001
- "void beforeFragment": "() {}",
2002
- "vec4 getFinalColor": "(vec4 color) { return color; }",
2003
- "void afterFragment": "() {}",
2004
- },
2005
- }
2006
- );
2007
- }
2008
-
2009
- return this._defaultColorShader;
2010
- }
2011
-
2012
- /**
2013
- * TODO(dave): un-private this when there is a way to actually override the
2014
- * shader used for points
2015
- *
2016
- * Get the shader used when drawing points with <a href="#/p5/point">`point()`</a>.
2017
- *
2018
- * You can call <a href="#/p5.Shader/modify">`pointShader().modify()`</a>
2019
- * and change any of the following hooks:
2020
- * - `void beforeVertex`: Called at the start of the vertex shader.
2021
- * - `vec3 getLocalPosition`: Update the position of vertices before transforms are applied. It takes in `vec3 position` and must return a modified version.
2022
- * - `vec3 getWorldPosition`: Update the position of vertices after transforms are applied. It takes in `vec3 position` and pust return a modified version.
2023
- * - `float getPointSize`: Update the size of the point. It takes in `float size` and must return a modified version.
2024
- * - `void afterVertex`: Called at the end of the vertex shader.
2025
- * - `void beforeFragment`: Called at the start of the fragment shader.
2026
- * - `bool shouldDiscard`: Points are drawn inside a square, with the corners discarded in the fragment shader to create a circle. Use this to change this logic. It takes in a `bool willDiscard` and must return a modified version.
2027
- * - `vec4 getFinalColor`: Update the final color after mixing. It takes in a `vec4 color` and must return a modified version.
2028
- * - `void afterFragment`: Called at the end of the fragment shader.
2029
- *
2030
- * Call `pointShader().inspectHooks()` to see all the possible hooks and
2031
- * their default implementations.
2032
- *
2033
- * @returns {p5.Shader} The `point()` shader
2034
- * @private()
2035
- */
2036
- pointShader() {
2037
- return this._getPointShader();
2038
- }
2039
-
2040
- _getPointShader() {
2041
- if (!this._defaultPointShader) {
2042
- this._defaultPointShader = new Shader(
2043
- this,
2044
- this._webGL2CompatibilityPrefix("vert", "mediump") +
2045
- defaultShaders.pointVert,
2046
- this._webGL2CompatibilityPrefix("frag", "mediump") +
2047
- defaultShaders.pointFrag,
2048
- {
2049
- vertex: {
2050
- "void beforeVertex": "() {}",
2051
- "vec3 getLocalPosition": "(vec3 position) { return position; }",
2052
- "vec3 getWorldPosition": "(vec3 position) { return position; }",
2053
- "float getPointSize": "(float size) { return size; }",
2054
- "void afterVertex": "() {}",
2055
- },
2056
- fragment: {
2057
- "void beforeFragment": "() {}",
2058
- "vec4 getFinalColor": "(vec4 color) { return color; }",
2059
- "bool shouldDiscard": "(bool outside) { return outside; }",
2060
- "void afterFragment": "() {}",
2061
- },
2062
- }
2063
- );
2064
- }
2065
- return this._defaultPointShader;
2066
- }
2067
-
2068
- baseStrokeShader() {
2069
- return this._getLineShader();
2070
- }
2071
-
2072
- _getLineShader() {
2073
- if (!this._defaultLineShader) {
2074
- this._defaultLineShader = new Shader(
2075
- this,
2076
- this._webGL2CompatibilityPrefix("vert", "mediump") +
2077
- defaultShaders.lineVert,
2078
- this._webGL2CompatibilityPrefix("frag", "mediump") +
2079
- defaultShaders.lineFrag,
2080
- {
2081
- vertex: {
2082
- "void beforeVertex": "() {}",
2083
- "StrokeVertex getObjectInputs":
2084
- "(StrokeVertex inputs) { return inputs; }",
2085
- "StrokeVertex getWorldInputs":
2086
- "(StrokeVertex inputs) { return inputs; }",
2087
- "StrokeVertex getCameraInputs":
2088
- "(StrokeVertex inputs) { return inputs; }",
2089
- "void afterVertex": "() {}",
2090
- },
2091
- fragment: {
2092
- "void beforeFragment": "() {}",
2093
- "Inputs getPixelInputs": "(Inputs inputs) { return inputs; }",
2094
- "vec4 getFinalColor": "(vec4 color) { return color; }",
2095
- "bool shouldDiscard": "(bool outside) { return outside; }",
2096
- "void afterFragment": "() {}",
2097
- },
2098
- }
2099
- );
2100
- }
2101
-
2102
- return this._defaultLineShader;
2103
- }
2104
-
2105
- _getFontShader() {
2106
- if (!this._defaultFontShader) {
2107
- if (this.webglVersion === constants.WEBGL) {
2108
- this.GL.getExtension("OES_standard_derivatives");
2109
- }
2110
- this._defaultFontShader = new Shader(
2111
- this,
2112
- this._webGL2CompatibilityPrefix("vert", "highp") +
2113
- defaultShaders.fontVert,
2114
- this._webGL2CompatibilityPrefix("frag", "highp") +
2115
- defaultShaders.fontFrag
2116
- );
2117
- }
2118
- return this._defaultFontShader;
2119
- }
2120
-
2121
- baseFilterShader() {
2122
- if (!this._baseFilterShader) {
2123
- this._baseFilterShader = new Shader(
2124
- this,
2125
- this._webGL2CompatibilityPrefix("vert", "highp") +
2126
- defaultShaders.filterBaseVert,
2127
- this._webGL2CompatibilityPrefix("frag", "highp") +
2128
- defaultShaders.filterBaseFrag,
2129
- {
2130
- vertex: {},
2131
- fragment: {
2132
- "vec4 getColor": `(FilterInputs inputs, in sampler2D canvasContent) {
2133
- return getTexture(canvasContent, inputs.texCoord);
2134
- }`,
2135
- },
2136
- }
2137
- );
2138
- }
2139
- return this._baseFilterShader;
2140
- }
2141
-
2142
- _webGL2CompatibilityPrefix(shaderType, floatPrecision) {
2143
- let code = "";
2144
- if (this.webglVersion === constants.WEBGL2) {
2145
- code += "#version 300 es\n#define WEBGL2\n";
2146
- }
2147
- if (shaderType === "vert") {
2148
- code += "#define VERTEX_SHADER\n";
2149
- } else if (shaderType === "frag") {
2150
- code += "#define FRAGMENT_SHADER\n";
2151
- }
2152
- if (floatPrecision) {
2153
- code += `precision ${floatPrecision} float;\n`;
2154
- }
2155
- return code;
2156
- }
2157
-
2158
- /**
2159
- * @private
2160
- * Note: DO NOT CALL THIS while in the middle of binding another texture,
2161
- * since it will change the texture binding in order to allocate the empty
2162
- * texture! Grab its value beforehand!
2163
- */
2164
- _getEmptyTexture() {
2165
- if (!this._emptyTexture) {
2166
- // a plain white texture RGBA, full alpha, single pixel.
2167
- const im = new Image(1, 1);
2168
- im.set(0, 0, 255);
2169
- this._emptyTexture = new Texture(this, im);
2170
- }
2171
- return this._emptyTexture;
2172
- }
2173
-
2174
- getTexture(input) {
2175
- let src = input;
2176
- if (src instanceof Framebuffer) {
2177
- src = src.color;
2178
- }
2179
-
2180
- const texture = this.textures.get(src);
2181
- if (texture) {
2182
- return texture;
2183
- }
2184
-
2185
- const tex = new Texture(this, src);
2186
- this.textures.set(src, tex);
2187
- return tex;
2188
- }
2189
- /*
2190
- * used in imageLight,
2191
- * To create a blurry image from the input non blurry img, if it doesn't already exist
2192
- * Add it to the diffusedTexture map,
2193
- * Returns the blurry image
2194
- * maps a Image used by imageLight() to a p5.Framebuffer
2195
- */
2196
- getDiffusedTexture(input) {
2197
- // if one already exists for a given input image
2198
- if (this.diffusedTextures.get(input) != null) {
2199
- return this.diffusedTextures.get(input);
2200
- }
2201
- // if not, only then create one
2202
- let newFramebuffer;
2203
- // hardcoded to 200px, because it's going to be blurry and smooth
2204
- let smallWidth = 200;
2205
- let width = smallWidth;
2206
- let height = Math.floor(smallWidth * (input.height / input.width));
2207
- newFramebuffer = new Framebuffer(this, {
2208
- width,
2209
- height,
2210
- density: 1,
2211
- });
2212
- // create framebuffer is like making a new sketch, all functions on main
2213
- // sketch it would be available on framebuffer
2214
- if (!this.diffusedShader) {
2215
- this.diffusedShader = this._pInst.createShader(
2216
- defaultShaders.imageLightVert,
2217
- defaultShaders.imageLightDiffusedFrag
2218
- );
2219
- }
2220
- newFramebuffer.draw(() => {
2221
- this.shader(this.diffusedShader);
2222
- this.diffusedShader.setUniform("environmentMap", input);
2223
- this.states.setValue("strokeColor", null);
2224
- this.noLights();
2225
- this.plane(width, height);
2226
- });
2227
- this.diffusedTextures.set(input, newFramebuffer);
2228
- return newFramebuffer;
2229
- }
2230
-
2231
- /*
2232
- * used in imageLight,
2233
- * To create a texture from the input non blurry image, if it doesn't already exist
2234
- * Creating 8 different levels of textures according to different
2235
- * sizes and atoring them in `levels` array
2236
- * Creating a new Mipmap texture with that `levels` array
2237
- * Storing the texture for input image in map called `specularTextures`
2238
- * maps the input Image to a p5.MipmapTexture
2239
- */
2240
- getSpecularTexture(input) {
2241
- // check if already exits (there are tex of diff resolution so which one to check)
2242
- // currently doing the whole array
2243
- if (this.specularTextures.get(input) != null) {
2244
- return this.specularTextures.get(input);
2245
- }
2246
- // Hardcoded size
2247
- const size = 512;
2248
- let tex;
2249
- const levels = [];
2250
- const framebuffer = new Framebuffer(this, {
2251
- width: size,
2252
- height: size,
2253
- density: 1,
2254
- });
2255
- let count = Math.log(size) / Math.log(2);
2256
- if (!this.specularShader) {
2257
- this.specularShader = this._pInst.createShader(
2258
- defaultShaders.imageLightVert,
2259
- defaultShaders.imageLightSpecularFrag
2260
- );
2261
- }
2262
- // currently only 8 levels
2263
- // This loop calculates 8 framebuffers of varying size of canvas
2264
- // and corresponding different roughness levels.
2265
- // Roughness increases with the decrease in canvas size,
2266
- // because rougher surfaces have less detailed/more blurry reflections.
2267
- for (let w = size; w >= 1; w /= 2) {
2268
- framebuffer.resize(w, w);
2269
- let currCount = Math.log(w) / Math.log(2);
2270
- let roughness = 1 - currCount / count;
2271
- framebuffer.draw(() => {
2272
- this.shader(this.specularShader);
2273
- this.clear();
2274
- this.specularShader.setUniform("environmentMap", input);
2275
- this.specularShader.setUniform("roughness", roughness);
2276
- this.states.setValue("strokeColor", null);
2277
- this.noLights();
2278
- this.plane(w, w);
2279
- });
2280
- levels.push(framebuffer.get().drawingContext.getImageData(0, 0, w, w));
2281
- }
2282
- // Free the Framebuffer
2283
- framebuffer.remove();
2284
- tex = new MipmapTexture(this, levels, {});
2285
- this.specularTextures.set(input, tex);
2286
- return tex;
2287
- }
2288
-
2289
- /**
2290
- * @private
2291
- * @returns {p5.Framebuffer|null} The currently active framebuffer, or null if
2292
- * the main canvas is the current draw target.
2293
- */
2294
- activeFramebuffer() {
2295
- return this.activeFramebuffers[this.activeFramebuffers.length - 1] || null;
2296
- }
2297
-
2298
- createFramebuffer(options) {
2299
- return new Framebuffer(this, options);
2300
- }
2301
-
2302
- _setGlobalUniforms(shader) {
2303
- const modelMatrix = this.states.uModelMatrix;
2304
- const viewMatrix = this.states.uViewMatrix;
2305
- const projectionMatrix = this.states.uPMatrix;
2306
- const modelViewMatrix = modelMatrix.copy().mult(viewMatrix);
2307
-
2308
- shader.setUniform(
2309
- "uPerspective",
2310
- this.states.curCamera.useLinePerspective ? 1 : 0
2311
- );
2312
- shader.setUniform("uViewMatrix", viewMatrix.mat4);
2313
- shader.setUniform("uProjectionMatrix", projectionMatrix.mat4);
2314
- shader.setUniform("uModelMatrix", modelMatrix.mat4);
2315
- shader.setUniform("uModelViewMatrix", modelViewMatrix.mat4);
2316
- if (shader.uniforms.uModelViewProjectionMatrix) {
2317
- const modelViewProjectionMatrix = modelViewMatrix.copy();
2318
- modelViewProjectionMatrix.mult(projectionMatrix);
2319
- shader.setUniform(
2320
- "uModelViewProjectionMatrix",
2321
- modelViewProjectionMatrix.mat4
2322
- );
2323
- }
2324
- if (shader.uniforms.uNormalMatrix) {
2325
- this.scratchMat3.inverseTranspose4x4(modelViewMatrix);
2326
- shader.setUniform("uNormalMatrix", this.scratchMat3.mat3);
2327
- }
2328
- if (shader.uniforms.uModelNormalMatrix) {
2329
- this.scratchMat3.inverseTranspose4x4(this.states.uModelMatrix);
2330
- shader.setUniform("uModelNormalMatrix", this.scratchMat3.mat3);
2331
- }
2332
- if (shader.uniforms.uCameraNormalMatrix) {
2333
- this.scratchMat3.inverseTranspose4x4(this.states.uViewMatrix);
2334
- shader.setUniform("uCameraNormalMatrix", this.scratchMat3.mat3);
2335
- }
2336
- if (shader.uniforms.uCameraRotation) {
2337
- this.scratchMat3.inverseTranspose4x4(this.states.uViewMatrix);
2338
- shader.setUniform("uCameraRotation", this.scratchMat3.mat3);
2339
- }
2340
- shader.setUniform("uViewport", this._viewport);
2341
- }
2342
-
2343
- _setStrokeUniforms(strokeShader) {
2344
- // set the uniform values
2345
- strokeShader.setUniform("uSimpleLines", this._simpleLines);
2346
- strokeShader.setUniform("uUseLineColor", this._useLineColor);
2347
- strokeShader.setUniform("uMaterialColor", this.states.curStrokeColor);
2348
- strokeShader.setUniform("uStrokeWeight", this.states.strokeWeight);
2349
- strokeShader.setUniform("uStrokeCap", STROKE_CAP_ENUM[this.curStrokeCap]);
2350
- strokeShader.setUniform(
2351
- "uStrokeJoin",
2352
- STROKE_JOIN_ENUM[this.curStrokeJoin]
2353
- );
2354
- }
2355
-
2356
- _setFillUniforms(fillShader) {
2357
- this.mixedSpecularColor = [...this.states.curSpecularColor];
2358
- const empty = this._getEmptyTexture();
2359
-
2360
- if (this.states._useMetalness > 0) {
2361
- this.mixedSpecularColor = this.mixedSpecularColor.map(
2362
- (mixedSpecularColor, index) =>
2363
- this.states.curFillColor[index] * this.states._useMetalness +
2364
- mixedSpecularColor * (1 - this.states._useMetalness)
2365
- );
2366
- }
2367
-
2368
- // TODO: optimize
2369
- fillShader.setUniform("uUseVertexColor", this._useVertexColor);
2370
- fillShader.setUniform("uMaterialColor", this.states.curFillColor);
2371
- fillShader.setUniform("isTexture", !!this.states._tex);
2372
- // We need to explicitly set uSampler back to an empty texture here.
2373
- // In general, we record the last set texture so we can re-apply it
2374
- // the next time a shader is used. However, the texture() function
2375
- // works differently and is global p5 state. If the p5 state has
2376
- // been cleared, we also need to clear the value in uSampler to match.
2377
- fillShader.setUniform("uSampler", this.states._tex || empty);
2378
- fillShader.setUniform("uTint", this.states.tint);
2379
-
2380
- fillShader.setUniform("uHasSetAmbient", this.states._hasSetAmbient);
2381
- fillShader.setUniform("uAmbientMatColor", this.states.curAmbientColor);
2382
- fillShader.setUniform("uSpecularMatColor", this.mixedSpecularColor);
2383
- fillShader.setUniform("uEmissiveMatColor", this.states.curEmissiveColor);
2384
- fillShader.setUniform("uSpecular", this.states._useSpecularMaterial);
2385
- fillShader.setUniform("uEmissive", this.states._useEmissiveMaterial);
2386
- fillShader.setUniform("uShininess", this.states._useShininess);
2387
- fillShader.setUniform("uMetallic", this.states._useMetalness);
2388
-
2389
- this._setImageLightUniforms(fillShader);
2390
-
2391
- fillShader.setUniform("uUseLighting", this.states.enableLighting);
2392
-
2393
- const pointLightCount = this.states.pointLightDiffuseColors.length / 3;
2394
- fillShader.setUniform("uPointLightCount", pointLightCount);
2395
- fillShader.setUniform(
2396
- "uPointLightLocation",
2397
- this.states.pointLightPositions
2398
- );
2399
- fillShader.setUniform(
2400
- "uPointLightDiffuseColors",
2401
- this.states.pointLightDiffuseColors
2402
- );
2403
- fillShader.setUniform(
2404
- "uPointLightSpecularColors",
2405
- this.states.pointLightSpecularColors
2406
- );
2407
-
2408
- const directionalLightCount =
2409
- this.states.directionalLightDiffuseColors.length / 3;
2410
- fillShader.setUniform("uDirectionalLightCount", directionalLightCount);
2411
- fillShader.setUniform(
2412
- "uLightingDirection",
2413
- this.states.directionalLightDirections
2414
- );
2415
- fillShader.setUniform(
2416
- "uDirectionalDiffuseColors",
2417
- this.states.directionalLightDiffuseColors
2418
- );
2419
- fillShader.setUniform(
2420
- "uDirectionalSpecularColors",
2421
- this.states.directionalLightSpecularColors
2422
- );
2423
-
2424
- // TODO: sum these here...
2425
- const ambientLightCount = this.states.ambientLightColors.length / 3;
2426
- this.mixedAmbientLight = [...this.states.ambientLightColors];
2427
-
2428
- if (this.states._useMetalness > 0) {
2429
- this.mixedAmbientLight = this.mixedAmbientLight.map((ambientColors) => {
2430
- let mixing = ambientColors - this.states._useMetalness;
2431
- return Math.max(0, mixing);
2432
- });
2433
- }
2434
- fillShader.setUniform("uAmbientLightCount", ambientLightCount);
2435
- fillShader.setUniform("uAmbientColor", this.mixedAmbientLight);
2436
-
2437
- const spotLightCount = this.states.spotLightDiffuseColors.length / 3;
2438
- fillShader.setUniform("uSpotLightCount", spotLightCount);
2439
- fillShader.setUniform("uSpotLightAngle", this.states.spotLightAngle);
2440
- fillShader.setUniform("uSpotLightConc", this.states.spotLightConc);
2441
- fillShader.setUniform(
2442
- "uSpotLightDiffuseColors",
2443
- this.states.spotLightDiffuseColors
2444
- );
2445
- fillShader.setUniform(
2446
- "uSpotLightSpecularColors",
2447
- this.states.spotLightSpecularColors
2448
- );
2449
- fillShader.setUniform("uSpotLightLocation", this.states.spotLightPositions);
2450
- fillShader.setUniform(
2451
- "uSpotLightDirection",
2452
- this.states.spotLightDirections
2453
- );
2454
-
2455
- fillShader.setUniform(
2456
- "uConstantAttenuation",
2457
- this.states.constantAttenuation
2458
- );
2459
- fillShader.setUniform("uLinearAttenuation", this.states.linearAttenuation);
2460
- fillShader.setUniform(
2461
- "uQuadraticAttenuation",
2462
- this.states.quadraticAttenuation
2463
- );
2464
- }
2465
-
2466
- // getting called from _setFillUniforms
2467
- _setImageLightUniforms(shader) {
2468
- //set uniform values
2469
- shader.setUniform("uUseImageLight", this.states.activeImageLight != null);
2470
- // true
2471
- if (this.states.activeImageLight) {
2472
- // this.states.activeImageLight has image as a key
2473
- // look up the texture from the diffusedTexture map
2474
- let diffusedLight = this.getDiffusedTexture(this.states.activeImageLight);
2475
- shader.setUniform("environmentMapDiffused", diffusedLight);
2476
- let specularLight = this.getSpecularTexture(this.states.activeImageLight);
2477
-
2478
- shader.setUniform("environmentMapSpecular", specularLight);
2479
- }
2480
- }
2481
-
2482
- _setPointUniforms(pointShader) {
2483
- // set the uniform values
2484
- pointShader.setUniform("uMaterialColor", this.states.curStrokeColor);
2485
- // @todo is there an instance where this isn't stroke weight?
2486
- // should be they be same var?
2487
- pointShader.setUniform(
2488
- "uPointSize",
2489
- this.states.strokeWeight * this._pixelDensity
2490
- );
2491
- }
2492
-
2493
- /* Binds a buffer to the drawing context
2494
- * when passed more than two arguments it also updates or initializes
2495
- * the data associated with the buffer
2496
- */
2497
- _bindBuffer(buffer, target, values, type, usage) {
2498
- if (!target) target = this.GL.ARRAY_BUFFER;
2499
- this.GL.bindBuffer(target, buffer);
2500
- if (values !== undefined) {
2501
- let data = values;
2502
- if (values instanceof DataArray) {
2503
- data = values.dataArray();
2504
- } else if (!(data instanceof (type || Float32Array))) {
2505
- data = new (type || Float32Array)(data);
2506
- }
2507
- this.GL.bufferData(target, data, usage || this.GL.STATIC_DRAW);
2508
- }
2509
- }
2510
-
2511
- ///////////////////////////////
2512
- //// UTILITY FUNCTIONS
2513
- //////////////////////////////
2514
- _arraysEqual(a, b) {
2515
- const aLength = a.length;
2516
- if (aLength !== b.length) return false;
2517
- return a.every((ai, i) => ai === b[i]);
2518
- }
2519
-
2520
- _isTypedArray(arr) {
2521
- return [
2522
- Float32Array,
2523
- Float64Array,
2524
- Int16Array,
2525
- Uint16Array,
2526
- Uint32Array,
2527
- ].some((x) => arr instanceof x);
2528
- }
2529
-
2530
- /**
2531
- * turn a p5.Vector Array into a one dimensional number array
2532
- * @private
2533
- * @param {p5.Vector[]} arr an array of p5.Vector
2534
- * @return {Number[]} a one dimensional array of numbers
2535
- * [p5.Vector(1, 2, 3), p5.Vector(4, 5, 6)] ->
2536
- * [1, 2, 3, 4, 5, 6]
2537
- */
2538
- _vToNArray(arr) {
2539
- return arr.flatMap((item) => [item.x, item.y, item.z]);
2540
- }
2541
- }
2542
-
2543
- function rendererGL(p5, fn) {
2544
- p5.RendererGL = RendererGL;
2545
-
2546
- /**
2547
- * @module Rendering
2548
- * @submodule Rendering
2549
- * @for p5
2550
- */
2551
- /**
2552
- * Set attributes for the WebGL Drawing context.
2553
- * This is a way of adjusting how the WebGL
2554
- * renderer works to fine-tune the display and performance.
2555
- *
2556
- * Note that this will reinitialize the drawing context
2557
- * if called after the WebGL canvas is made.
2558
- *
2559
- * If an object is passed as the parameter, all attributes
2560
- * not declared in the object will be set to defaults.
2561
- *
2562
- * The available attributes are:
2563
- * <br>
2564
- * alpha - indicates if the canvas contains an alpha buffer
2565
- * default is true
2566
- *
2567
- * depth - indicates whether the drawing buffer has a depth buffer
2568
- * of at least 16 bits - default is true
2569
- *
2570
- * stencil - indicates whether the drawing buffer has a stencil buffer
2571
- * of at least 8 bits
2572
- *
2573
- * antialias - indicates whether or not to perform anti-aliasing
2574
- * default is false (true in Safari)
2575
- *
2576
- * premultipliedAlpha - indicates that the page compositor will assume
2577
- * the drawing buffer contains colors with pre-multiplied alpha
2578
- * default is true
2579
- *
2580
- * preserveDrawingBuffer - if true the buffers will not be cleared and
2581
- * and will preserve their values until cleared or overwritten by author
2582
- * (note that p5 clears automatically on draw loop)
2583
- * default is true
2584
- *
2585
- * perPixelLighting - if true, per-pixel lighting will be used in the
2586
- * lighting shader otherwise per-vertex lighting is used.
2587
- * default is true.
2588
- *
2589
- * version - either 1 or 2, to specify which WebGL version to ask for. By
2590
- * default, WebGL 2 will be requested. If WebGL2 is not available, it will
2591
- * fall back to WebGL 1. You can check what version is used with by looking at
2592
- * the global `webglVersion` property.
2593
- *
2594
- * @method setAttributes
2595
- * @for p5
2596
- * @param {String} key Name of attribute
2597
- * @param {Boolean} value New value of named attribute
2598
- * @example
2599
- * <div>
2600
- * <code>
2601
- * function setup() {
2602
- * createCanvas(100, 100, WEBGL);
2603
- * }
2604
- *
2605
- * function draw() {
2606
- * background(255);
2607
- * push();
2608
- * rotateZ(frameCount * 0.02);
2609
- * rotateX(frameCount * 0.02);
2610
- * rotateY(frameCount * 0.02);
2611
- * fill(0, 0, 0);
2612
- * box(50);
2613
- * pop();
2614
- * }
2615
- * </code>
2616
- * </div>
2617
- * <br>
2618
- * Now with the antialias attribute set to true.
2619
- * <br>
2620
- * <div>
2621
- * <code>
2622
- * function setup() {
2623
- * setAttributes('antialias', true);
2624
- * createCanvas(100, 100, WEBGL);
2625
- * }
2626
- *
2627
- * function draw() {
2628
- * background(255);
2629
- * push();
2630
- * rotateZ(frameCount * 0.02);
2631
- * rotateX(frameCount * 0.02);
2632
- * rotateY(frameCount * 0.02);
2633
- * fill(0, 0, 0);
2634
- * box(50);
2635
- * pop();
2636
- * }
2637
- * </code>
2638
- * </div>
2639
- *
2640
- * <div>
2641
- * <code>
2642
- * // press the mouse button to disable perPixelLighting
2643
- * function setup() {
2644
- * createCanvas(100, 100, WEBGL);
2645
- * noStroke();
2646
- * fill(255);
2647
- * }
2648
- *
2649
- * let lights = [
2650
- * { c: '#f00', t: 1.12, p: 1.91, r: 0.2 },
2651
- * { c: '#0f0', t: 1.21, p: 1.31, r: 0.2 },
2652
- * { c: '#00f', t: 1.37, p: 1.57, r: 0.2 },
2653
- * { c: '#ff0', t: 1.12, p: 1.91, r: 0.7 },
2654
- * { c: '#0ff', t: 1.21, p: 1.31, r: 0.7 },
2655
- * { c: '#f0f', t: 1.37, p: 1.57, r: 0.7 }
2656
- * ];
2657
- *
2658
- * function draw() {
2659
- * let t = millis() / 1000 + 1000;
2660
- * background(0);
2661
- * directionalLight(color('#222'), 1, 1, 1);
2662
- *
2663
- * for (let i = 0; i < lights.length; i++) {
2664
- * let light = lights[i];
2665
- * pointLight(
2666
- * color(light.c),
2667
- * p5.Vector.fromAngles(t * light.t, t * light.p, width * light.r)
2668
- * );
2669
- * }
2670
- *
2671
- * specularMaterial(255);
2672
- * sphere(width * 0.1);
2673
- *
2674
- * rotateX(t * 0.77);
2675
- * rotateY(t * 0.83);
2676
- * rotateZ(t * 0.91);
2677
- * torus(width * 0.3, width * 0.07, 24, 10);
2678
- * }
2679
- *
2680
- * function mousePressed() {
2681
- * setAttributes('perPixelLighting', false);
2682
- * noStroke();
2683
- * fill(255);
2684
- * }
2685
- * function mouseReleased() {
2686
- * setAttributes('perPixelLighting', true);
2687
- * noStroke();
2688
- * fill(255);
2689
- * }
2690
- * </code>
2691
- * </div>
2692
- *
2693
- * @alt a rotating cube with smoother edges
2694
- */
2695
- /**
2696
- * @method setAttributes
2697
- * @for p5
2698
- * @param {Object} obj object with key-value pairs
2699
- */
2700
- fn.setAttributes = function (key, value) {
2701
- if (typeof this._glAttributes === "undefined") {
2702
- console.log(
2703
- "You are trying to use setAttributes on a p5.Graphics object " +
2704
- "that does not use a WEBGL renderer."
2705
- );
2706
- return;
2707
- }
2708
- let unchanged = true;
2709
- if (typeof value !== "undefined") {
2710
- //first time modifying the attributes
2711
- if (this._glAttributes === null) {
2712
- this._glAttributes = {};
2713
- }
2714
- if (this._glAttributes[key] !== value) {
2715
- //changing value of previously altered attribute
2716
- this._glAttributes[key] = value;
2717
- unchanged = false;
2718
- }
2719
- //setting all attributes with some change
2720
- } else if (key instanceof Object) {
2721
- if (this._glAttributes !== key) {
2722
- this._glAttributes = key;
2723
- unchanged = false;
2724
- }
2725
- }
2726
- //@todo_FES
2727
- if (!this._renderer.isP3D || unchanged) {
2728
- return;
2729
- }
2730
-
2731
- if (!this._setupDone) {
2732
- if (this._renderer.geometryBufferCache.numCached() > 0) {
2733
- p5._friendlyError(
2734
- "Sorry, Could not set the attributes, you need to call setAttributes() " +
2735
- "before calling the other drawing methods in setup()"
2736
- );
2737
- return;
2738
- }
2739
- }
2740
-
2741
- this._renderer._resetContext();
2742
-
2743
- if (this._renderer.states.curCamera) {
2744
- this._renderer.states.curCamera._renderer = this._renderer;
2745
- }
2746
- };
2747
-
2748
- /**
2749
- * ensures that p5 is using a 3d renderer. throws an error if not.
2750
- */
2751
- fn._assert3d = function (name) {
2752
- if (!this._renderer.isP3D)
2753
- throw new Error(
2754
- `${name}() is only supported in WEBGL mode. If you'd like to use 3D graphics and WebGL, see https://p5js.org/examples/form-3d-primitives.html for more information.`
2755
- );
2756
- };
2757
-
2758
- p5.renderers[constants.WEBGL] = p5.RendererGL;
2759
- p5.renderers[constants.WEBGL2] = p5.RendererGL;
2760
- }
2761
-
2762
- /**
2763
- * @private
2764
- * @param {Uint8Array|Float32Array|undefined} pixels An existing pixels array to reuse if the size is the same
2765
- * @param {WebGLRenderingContext} gl The WebGL context
2766
- * @param {WebGLFramebuffer|null} framebuffer The Framebuffer to read
2767
- * @param {Number} x The x coordiante to read, premultiplied by pixel density
2768
- * @param {Number} y The y coordiante to read, premultiplied by pixel density
2769
- * @param {Number} width The width in pixels to be read (factoring in pixel density)
2770
- * @param {Number} height The height in pixels to be read (factoring in pixel density)
2771
- * @param {GLEnum} format Either RGB or RGBA depending on how many channels to read
2772
- * @param {GLEnum} type The datatype of each channel, e.g. UNSIGNED_BYTE or FLOAT
2773
- * @param {Number|undefined} flipY If provided, the total height with which to flip the y axis about
2774
- * @returns {Uint8Array|Float32Array} pixels A pixels array with the current state of the
2775
- * WebGL context read into it
2776
- */
2777
- export function readPixelsWebGL(
2778
- pixels,
2779
- gl,
2780
- framebuffer,
2781
- x,
2782
- y,
2783
- width,
2784
- height,
2785
- format,
2786
- type,
2787
- flipY
2788
- ) {
2789
- // Record the currently bound framebuffer so we can go back to it after, and
2790
- // bind the framebuffer we want to read from
2791
- const prevFramebuffer = gl.getParameter(gl.FRAMEBUFFER_BINDING);
2792
- gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
2793
-
2794
- const channels = format === gl.RGBA ? 4 : 3;
2795
-
2796
- // Make a pixels buffer if it doesn't already exist
2797
- const len = width * height * channels;
2798
- const TypedArrayClass = type === gl.UNSIGNED_BYTE ? Uint8Array : Float32Array;
2799
- if (!(pixels instanceof TypedArrayClass) || pixels.length !== len) {
2800
- pixels = new TypedArrayClass(len);
2801
- }
2802
-
2803
- gl.readPixels(
2804
- x,
2805
- flipY ? flipY - y - height : y,
2806
- width,
2807
- height,
2808
- format,
2809
- type,
2810
- pixels
2811
- );
2812
-
2813
- // Re-bind whatever was previously bound
2814
- gl.bindFramebuffer(gl.FRAMEBUFFER, prevFramebuffer);
2815
-
2816
- if (flipY) {
2817
- // WebGL pixels are inverted compared to 2D pixels, so we have to flip
2818
- // the resulting rows. Adapted from https://stackoverflow.com/a/41973289
2819
- const halfHeight = Math.floor(height / 2);
2820
- const tmpRow = new TypedArrayClass(width * channels);
2821
- for (let y = 0; y < halfHeight; y++) {
2822
- const topOffset = y * width * 4;
2823
- const bottomOffset = (height - y - 1) * width * 4;
2824
- tmpRow.set(pixels.subarray(topOffset, topOffset + width * 4));
2825
- pixels.copyWithin(topOffset, bottomOffset, bottomOffset + width * 4);
2826
- pixels.set(tmpRow, bottomOffset);
2827
- }
2828
- }
2829
-
2830
- return pixels;
2831
- }
2832
-
2833
- /**
2834
- * @private
2835
- * @param {WebGLRenderingContext} gl The WebGL context
2836
- * @param {WebGLFramebuffer|null} framebuffer The Framebuffer to read
2837
- * @param {Number} x The x coordinate to read, premultiplied by pixel density
2838
- * @param {Number} y The y coordinate to read, premultiplied by pixel density
2839
- * @param {GLEnum} format Either RGB or RGBA depending on how many channels to read
2840
- * @param {GLEnum} type The datatype of each channel, e.g. UNSIGNED_BYTE or FLOAT
2841
- * @param {Number|undefined} flipY If provided, the total height with which to flip the y axis about
2842
- * @returns {Number[]} pixels The channel data for the pixel at that location
2843
- */
2844
- export function readPixelWebGL(gl, framebuffer, x, y, format, type, flipY) {
2845
- // Record the currently bound framebuffer so we can go back to it after, and
2846
- // bind the framebuffer we want to read from
2847
- const prevFramebuffer = gl.getParameter(gl.FRAMEBUFFER_BINDING);
2848
- gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
2849
-
2850
- const channels = format === gl.RGBA ? 4 : 3;
2851
- const TypedArrayClass = type === gl.UNSIGNED_BYTE ? Uint8Array : Float32Array;
2852
- const pixels = new TypedArrayClass(channels);
2853
-
2854
- gl.readPixels(x, flipY ? flipY - y - 1 : y, 1, 1, format, type, pixels);
2855
-
2856
- // Re-bind whatever was previously bound
2857
- gl.bindFramebuffer(gl.FRAMEBUFFER, prevFramebuffer);
2858
-
2859
- return Array.from(pixels);
2860
- }
2861
-
2862
- export default rendererGL;
2863
- export { RendererGL };
2864
-
2865
- if (typeof p5 !== "undefined") {
2866
- rendererGL(p5, p5.prototype);
2867
- }