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.
- package/{src → dist}/accessibility/color_namer.js +48 -3
- package/{src → dist}/accessibility/describe.js +2 -2
- package/{src → dist}/accessibility/gridOutput.js +2 -2
- package/dist/accessibility/index.js +60 -0
- package/{src → dist}/accessibility/outputs.js +2 -2
- package/{src → dist}/accessibility/textOutput.js +2 -2
- package/dist/app.js +120 -0
- package/{src → dist}/color/color_conversion.js +48 -10
- package/{src → dist}/color/color_spaces/hsb.js +3 -1
- package/dist/color/creating_reading.js +3 -0
- package/dist/color/index.js +13 -0
- package/dist/color/p5.Color.culori.js +1 -0
- package/dist/color/p5.Color.js +3 -0
- package/{src → dist}/color/setting.js +9 -6
- package/{src/core/constants.js → dist/constants-C-g_eAdC.js} +266 -130
- package/{src → dist}/core/States.js +3 -1
- package/dist/core/constants.js +1 -0
- package/{src → dist}/core/environment.js +7 -6
- package/{src → dist}/core/friendly_errors/browser_errors.js +1 -1
- package/{src → dist}/core/friendly_errors/fes_core.js +14 -44
- package/{src → dist}/core/friendly_errors/file_errors.js +6 -3
- package/dist/core/friendly_errors/index.js +23 -0
- package/dist/core/friendly_errors/param_validator.js +5455 -0
- package/{src → dist}/core/friendly_errors/sketch_reader.js +50 -4
- package/{src → dist}/core/friendly_errors/sketch_verifier.js +6 -6
- package/{src → dist}/core/friendly_errors/stacktrace.js +3 -5
- package/{src → dist}/core/friendly_errors/validate_params.js +50 -41
- package/{src → dist}/core/helpers.js +9 -6
- package/dist/core/init.js +105 -0
- package/dist/core/internationalization.js +302 -0
- package/dist/core/legacy.js +73 -0
- package/dist/core/main.js +44 -0
- package/dist/core/noop.js +3 -0
- package/dist/core/p5.Graphics.js +40 -0
- package/dist/core/p5.Renderer.js +11 -0
- package/dist/core/p5.Renderer2D.js +44 -0
- package/dist/core/reference.js +1 -0
- package/dist/core/rendering.js +40 -0
- package/{src → dist}/core/structure.js +3 -3
- package/{src → dist}/core/transform.js +2 -2
- package/{src/color/creating_reading.js → dist/creating_reading-D4AAKRbx.js} +841 -13
- package/{src → dist}/data/index.js +3 -1
- package/{src → dist}/data/local_storage.js +2 -8
- package/{src → dist}/dom/dom.js +11 -5
- package/dist/dom/index.js +18 -0
- package/{src → dist}/dom/p5.Element.js +14 -12
- package/{src → dist}/dom/p5.File.js +4 -4
- package/{src → dist}/dom/p5.MediaElement.js +10 -4
- package/{src → dist}/events/acceleration.js +2 -2
- package/{src → dist}/events/index.js +3 -1
- package/{src → dist}/events/keyboard.js +14 -11
- package/{src → dist}/events/pointer.js +16 -17
- package/dist/image/const.js +9 -0
- package/{src → dist}/image/filterRenderer2D.js +57 -37
- package/{src → dist}/image/filters.js +1 -3
- package/dist/image/image.js +40 -0
- package/dist/image/index.js +51 -0
- package/dist/image/loading_displaying.js +40 -0
- package/dist/image/p5.Image.js +11 -0
- package/{src → dist}/image/pixels.js +4 -3
- package/{src → dist}/io/csv.js +72 -70
- package/dist/io/files.js +40 -0
- package/dist/io/index.js +51 -0
- package/{src → dist}/io/p5.Table.js +6 -6
- package/{src → dist}/io/p5.TableRow.js +3 -4
- package/{src → dist}/io/p5.XML.js +2 -5
- package/{src → dist}/io/utilities.js +1 -1
- package/{src/core/p5.Renderer2D.js → dist/main-s72KWcUy.js} +735 -57
- package/{src → dist}/math/Matrices/Matrix.js +10 -8
- package/{src → dist}/math/Matrices/MatrixInterface.js +5 -3
- package/{src → dist}/math/Matrices/MatrixNumjs.js +12 -26
- package/{src → dist}/math/calculation.js +2 -2
- package/{src → dist}/math/index.js +6 -3
- package/{src → dist}/math/math.js +2 -2
- package/{src → dist}/math/noise.js +2 -2
- package/{src → dist}/math/p5.Matrix.js +7 -4
- package/{src → dist}/math/p5.Vector.js +6 -6
- package/{src → dist}/math/random.js +2 -2
- package/{src → dist}/math/trigonometry.js +16 -15
- package/{src/image/p5.Image.js → dist/p5.Renderer-CwAYZOC2.js} +390 -19
- package/dist/rendering--aAe5aq3.js +24925 -0
- package/{src → dist}/shape/2d_primitives.js +18 -17
- package/{src → dist}/shape/attributes.js +18 -17
- package/{src → dist}/shape/curves.js +2 -2
- package/{src → dist}/shape/custom_shapes.js +44 -64
- package/{src → dist}/shape/index.js +10 -2
- package/{src → dist}/shape/vertex.js +2 -3
- package/dist/type/index.js +25 -0
- package/{src → dist}/type/lib/Typr.js +76 -94
- package/{src → dist}/type/p5.Font.js +37 -61
- package/{src → dist}/type/textCore.js +34 -57
- package/{src → dist}/type/unicodeRanges.js +3 -1
- package/{src → dist}/utilities/conversion.js +2 -2
- package/{src → dist}/utilities/index.js +3 -1
- package/{src → dist}/utilities/time_date.js +6 -7
- package/{src → dist}/utilities/utility_functions.js +2 -2
- package/dist/webgl/3d_primitives.js +40 -0
- package/{src → dist}/webgl/GeometryBufferCache.js +3 -1
- package/{src → dist}/webgl/GeometryBuilder.js +12 -8
- package/{src → dist}/webgl/ShaderGenerator.js +79 -82
- package/{src → dist}/webgl/ShapeBuilder.js +26 -23
- package/dist/webgl/index.js +76 -0
- package/{src → dist}/webgl/interaction.js +7 -6
- package/dist/webgl/light.js +40 -0
- package/{src → dist}/webgl/loading.js +45 -12
- package/dist/webgl/material.js +40 -0
- package/dist/webgl/p5.Camera.js +40 -0
- package/{src → dist}/webgl/p5.DataArray.js +3 -5
- package/dist/webgl/p5.Framebuffer.js +40 -0
- package/{src → dist}/webgl/p5.Geometry.js +12 -15
- package/{src → dist}/webgl/p5.Quat.js +5 -4
- package/{src → dist}/webgl/p5.RenderBuffer.js +2 -3
- package/dist/webgl/p5.RendererGL.js +40 -0
- package/dist/webgl/p5.Shader.js +40 -0
- package/dist/webgl/p5.Texture.js +40 -0
- package/{src → dist}/webgl/text.js +51 -9
- package/lib/p5.esm.js +102 -48
- package/lib/p5.js +102 -48
- package/lib/p5.min.js +1 -1
- package/package.json +17 -16
- package/translations/dev.js +6 -6
- package/translations/index.js +1 -1
- package/src/README.md +0 -27
- package/src/accessibility/index.js +0 -13
- package/src/app.js +0 -61
- package/src/color/index.js +0 -9
- package/src/color/p5.Color.culori.js +0 -66
- package/src/color/p5.Color.js +0 -851
- package/src/core/README.md +0 -91
- package/src/core/friendly_errors/index.js +0 -13
- package/src/core/friendly_errors/param_validator.js +0 -561
- package/src/core/init.js +0 -58
- package/src/core/internationalization.js +0 -195
- package/src/core/legacy.js +0 -29
- package/src/core/main.js +0 -689
- package/src/core/noop.js +0 -1
- package/src/core/p5.Graphics.js +0 -696
- package/src/core/p5.Renderer.js +0 -408
- package/src/core/reference.js +0 -2060
- package/src/core/rendering.js +0 -697
- package/src/dom/index.js +0 -11
- package/src/image/const.js +0 -6
- package/src/image/image.js +0 -731
- package/src/image/index.js +0 -15
- package/src/image/loading_displaying.js +0 -1431
- package/src/io/files.js +0 -2210
- package/src/io/index.js +0 -11
- package/src/math/README.md +0 -40
- package/src/type/index.js +0 -9
- package/src/webgl/3d_primitives.js +0 -2741
- package/src/webgl/index.js +0 -37
- package/src/webgl/light.js +0 -1851
- package/src/webgl/material.js +0 -3854
- package/src/webgl/p5.Camera.js +0 -4010
- package/src/webgl/p5.Framebuffer.js +0 -1865
- package/src/webgl/p5.RendererGL.js +0 -2867
- package/src/webgl/p5.Shader.js +0 -1505
- package/src/webgl/p5.Texture.js +0 -541
- package/src/webgl/shaders/basic.frag +0 -6
- package/src/webgl/shaders/filters/base.frag +0 -22
- package/src/webgl/shaders/filters/base.vert +0 -19
- package/src/webgl/shaders/filters/blur.frag +0 -60
- package/src/webgl/shaders/filters/default.vert +0 -18
- package/src/webgl/shaders/filters/dilate.frag +0 -39
- package/src/webgl/shaders/filters/erode.frag +0 -39
- package/src/webgl/shaders/filters/gray.frag +0 -16
- package/src/webgl/shaders/filters/invert.frag +0 -15
- package/src/webgl/shaders/filters/opaque.frag +0 -12
- package/src/webgl/shaders/filters/posterize.frag +0 -29
- package/src/webgl/shaders/filters/threshold.frag +0 -23
- package/src/webgl/shaders/font.frag +0 -216
- package/src/webgl/shaders/font.vert +0 -44
- package/src/webgl/shaders/imageLight.vert +0 -33
- package/src/webgl/shaders/imageLightDiffused.frag +0 -82
- package/src/webgl/shaders/imageLightSpecular.frag +0 -134
- package/src/webgl/shaders/light.vert +0 -37
- package/src/webgl/shaders/light_texture.frag +0 -26
- package/src/webgl/shaders/lighting.glsl +0 -227
- package/src/webgl/shaders/line.frag +0 -74
- package/src/webgl/shaders/line.vert +0 -294
- package/src/webgl/shaders/normal.frag +0 -6
- package/src/webgl/shaders/normal.vert +0 -72
- package/src/webgl/shaders/phong.frag +0 -84
- package/src/webgl/shaders/phong.vert +0 -87
- package/src/webgl/shaders/point.frag +0 -29
- package/src/webgl/shaders/point.vert +0 -19
- package/src/webgl/shaders/sphereMapping.frag +0 -26
- 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
|
-
}
|