@thi.ng/webgl 6.6.11 → 6.6.12
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/CHANGELOG.md +1 -1
- package/README.md +1 -1
- package/api/blend.js +36 -32
- package/api/buffers.js +0 -1
- package/api/canvas.js +0 -1
- package/api/ext.js +12 -9
- package/api/glsl.js +0 -1
- package/api/material.js +0 -1
- package/api/model.js +13 -10
- package/api/multipass.js +0 -1
- package/api/shader.js +4 -1
- package/api/stencil.js +26 -22
- package/api/texture.js +589 -252
- package/buffer.js +145 -127
- package/canvas.js +53 -61
- package/checks.js +6 -6
- package/draw.js +84 -69
- package/error.js +7 -3
- package/fbo.js +95 -90
- package/geo/cube.js +28 -26
- package/geo/quad.js +34 -33
- package/logger.js +6 -2
- package/material.js +14 -11
- package/matrices.js +12 -19
- package/multipass.js +155 -146
- package/package.json +22 -19
- package/rbo.js +43 -34
- package/readpixels.js +14 -10
- package/shader.js +342 -335
- package/shaders/lambert.js +79 -48
- package/shaders/phong.js +92 -60
- package/shaders/pipeline.js +35 -27
- package/syntax.js +64 -77
- package/texture.js +277 -230
- package/textures/checkerboard.js +28 -25
- package/textures/stripes.js +19 -18
- package/uniforms.js +70 -67
- package/utils.js +6 -8
package/shader.js
CHANGED
|
@@ -11,8 +11,12 @@ import { targetGLSL } from "@thi.ng/shader-ast-glsl/target";
|
|
|
11
11
|
import { program } from "@thi.ng/shader-ast/ast/scope";
|
|
12
12
|
import { input, output, sym, uniform } from "@thi.ng/shader-ast/ast/sym";
|
|
13
13
|
import { vals } from "@thi.ng/transducers/vals";
|
|
14
|
-
import {
|
|
15
|
-
|
|
14
|
+
import {
|
|
15
|
+
GL_EXT_INFO
|
|
16
|
+
} from "./api/ext.js";
|
|
17
|
+
import {
|
|
18
|
+
DEFAULT_OUTPUT
|
|
19
|
+
} from "./api/shader.js";
|
|
16
20
|
import { getExtensions } from "./canvas.js";
|
|
17
21
|
import { isGL2Context } from "./checks.js";
|
|
18
22
|
import { error } from "./error.js";
|
|
@@ -20,379 +24,382 @@ import { LOGGER } from "./logger.js";
|
|
|
20
24
|
import { GLSL_HEADER, NO_PREFIXES, SYNTAX } from "./syntax.js";
|
|
21
25
|
import { UNIFORM_SETTERS } from "./uniforms.js";
|
|
22
26
|
const ERROR_REGEXP = /ERROR: \d+:(\d+): (.*)/;
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
27
|
+
class Shader {
|
|
28
|
+
gl;
|
|
29
|
+
program;
|
|
30
|
+
attribs;
|
|
31
|
+
uniforms;
|
|
32
|
+
state;
|
|
33
|
+
warnAttrib = doOnce(
|
|
34
|
+
(id) => LOGGER.warn(
|
|
35
|
+
`unknown attrib: ${id} (no further warnings will be shown...)`
|
|
36
|
+
)
|
|
37
|
+
);
|
|
38
|
+
warnUni = doOnce(
|
|
39
|
+
(id) => LOGGER.warn(
|
|
40
|
+
`unknown uniform: ${id} (no further warnings will be shown...)`
|
|
41
|
+
)
|
|
42
|
+
);
|
|
43
|
+
constructor(gl, program2, attribs, uniforms, state) {
|
|
44
|
+
this.gl = gl;
|
|
45
|
+
this.program = program2;
|
|
46
|
+
this.attribs = attribs;
|
|
47
|
+
this.uniforms = uniforms;
|
|
48
|
+
this.state = state || {};
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Returns a shallow copy of this shader with its state config merged with
|
|
52
|
+
* given options (priority). Useful for re-using a shader, but applying
|
|
53
|
+
* different settings.
|
|
54
|
+
*
|
|
55
|
+
* @param state
|
|
56
|
+
*/
|
|
57
|
+
withState(state) {
|
|
58
|
+
return new Shader(this.gl, this.program, this.attribs, this.uniforms, {
|
|
59
|
+
...this.state,
|
|
60
|
+
...state
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
bind(spec) {
|
|
64
|
+
if (this.program) {
|
|
65
|
+
this.gl.useProgram(this.program);
|
|
66
|
+
this.bindAttribs(spec.attribs);
|
|
67
|
+
this.bindUniforms(spec.uniforms);
|
|
68
|
+
return true;
|
|
37
69
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
return new Shader(this.gl, this.program, this.attribs, this.uniforms, {
|
|
47
|
-
...this.state,
|
|
48
|
-
...state,
|
|
49
|
-
});
|
|
70
|
+
return false;
|
|
71
|
+
}
|
|
72
|
+
unbind() {
|
|
73
|
+
let shaderAttrib;
|
|
74
|
+
for (let id in this.attribs) {
|
|
75
|
+
if (shaderAttrib = this.attribs[id]) {
|
|
76
|
+
this.gl.disableVertexAttribArray(shaderAttrib.loc);
|
|
77
|
+
}
|
|
50
78
|
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
79
|
+
this.gl.useProgram(null);
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
release() {
|
|
83
|
+
if (this.program) {
|
|
84
|
+
this.gl.deleteProgram(this.program);
|
|
85
|
+
delete this.program;
|
|
86
|
+
return true;
|
|
59
87
|
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
bindAttribs(specAttribs) {
|
|
91
|
+
const gl = this.gl;
|
|
92
|
+
let shaderAttrib;
|
|
93
|
+
for (let id in specAttribs) {
|
|
94
|
+
if (shaderAttrib = this.attribs[id]) {
|
|
95
|
+
const attr = specAttribs[id];
|
|
96
|
+
attr.buffer.bind();
|
|
97
|
+
gl.enableVertexAttribArray(shaderAttrib.loc);
|
|
98
|
+
gl.vertexAttribPointer(
|
|
99
|
+
shaderAttrib.loc,
|
|
100
|
+
attr.size || 3,
|
|
101
|
+
asGLType(attr.type || gl.FLOAT),
|
|
102
|
+
attr.normalized || false,
|
|
103
|
+
attr.stride || 0,
|
|
104
|
+
attr.offset || 0
|
|
105
|
+
);
|
|
106
|
+
} else {
|
|
107
|
+
this.warnAttrib(id);
|
|
108
|
+
}
|
|
69
109
|
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
110
|
+
}
|
|
111
|
+
bindUniforms(specUnis = {}) {
|
|
112
|
+
const shaderUnis = this.uniforms;
|
|
113
|
+
for (let id in specUnis) {
|
|
114
|
+
const u = shaderUnis[id];
|
|
115
|
+
if (u) {
|
|
116
|
+
let val = specUnis[id];
|
|
117
|
+
val = isFunction(val) ? val(shaderUnis, specUnis) : deref(val);
|
|
118
|
+
u.setter(val);
|
|
119
|
+
} else {
|
|
120
|
+
this.warnUni(id);
|
|
121
|
+
}
|
|
77
122
|
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
attr.buffer.bind();
|
|
85
|
-
gl.enableVertexAttribArray(shaderAttrib.loc);
|
|
86
|
-
gl.vertexAttribPointer(shaderAttrib.loc, attr.size || 3, asGLType(attr.type || gl.FLOAT), attr.normalized || false, attr.stride || 0, attr.offset || 0);
|
|
87
|
-
}
|
|
88
|
-
else {
|
|
89
|
-
this.warnAttrib(id);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
123
|
+
for (let id in shaderUnis) {
|
|
124
|
+
if (shaderUnis.hasOwnProperty(id) && (!specUnis || !existsAndNotNull(specUnis[id]))) {
|
|
125
|
+
const u = shaderUnis[id];
|
|
126
|
+
const val = u.defaultFn ? u.defaultFn(shaderUnis, specUnis) : u.defaultVal;
|
|
127
|
+
u.setter(val);
|
|
128
|
+
}
|
|
92
129
|
}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
// console.log(id, val);
|
|
101
|
-
u.setter(val);
|
|
102
|
-
}
|
|
103
|
-
else {
|
|
104
|
-
this.warnUni(id);
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
// apply defaults for non-specified uniforms in user spec
|
|
108
|
-
for (let id in shaderUnis) {
|
|
109
|
-
if (shaderUnis.hasOwnProperty(id) &&
|
|
110
|
-
(!specUnis || !existsAndNotNull(specUnis[id]))) {
|
|
111
|
-
const u = shaderUnis[id];
|
|
112
|
-
const val = u.defaultFn
|
|
113
|
-
? u.defaultFn(shaderUnis, specUnis)
|
|
114
|
-
: u.defaultVal;
|
|
115
|
-
// console.log("default", id, val);
|
|
116
|
-
u.setter(val);
|
|
117
|
-
}
|
|
118
|
-
}
|
|
130
|
+
}
|
|
131
|
+
prepareState(state = this.state) {
|
|
132
|
+
const gl = this.gl;
|
|
133
|
+
state.depth !== void 0 && this.setState(gl.DEPTH_TEST, state.depth);
|
|
134
|
+
if (state.cull !== void 0) {
|
|
135
|
+
this.setState(gl.CULL_FACE, state.cull);
|
|
136
|
+
state.cullMode && gl.cullFace(state.cullMode);
|
|
119
137
|
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
this.setState(gl.CULL_FACE, state.cull);
|
|
125
|
-
state.cullMode && gl.cullFace(state.cullMode);
|
|
126
|
-
}
|
|
127
|
-
if (state.blend !== undefined) {
|
|
128
|
-
this.setState(gl.BLEND, state.blend);
|
|
129
|
-
state.blendFn && gl.blendFunc(state.blendFn[0], state.blendFn[1]);
|
|
130
|
-
state.blendEq !== undefined && gl.blendEquation(state.blendEq);
|
|
131
|
-
}
|
|
132
|
-
if (state.stencil !== undefined) {
|
|
133
|
-
this.setState(gl.STENCIL_TEST, state.stencil);
|
|
134
|
-
state.stencilFn &&
|
|
135
|
-
gl.stencilFunc(state.stencilFn[0], state.stencilFn[1], state.stencilFn[2]);
|
|
136
|
-
state.stencilOp &&
|
|
137
|
-
gl.stencilOp(state.stencilOp[0], state.stencilOp[1], state.stencilOp[2]);
|
|
138
|
-
state.stencilMask !== undefined &&
|
|
139
|
-
gl.stencilMask(state.stencilMask);
|
|
140
|
-
}
|
|
138
|
+
if (state.blend !== void 0) {
|
|
139
|
+
this.setState(gl.BLEND, state.blend);
|
|
140
|
+
state.blendFn && gl.blendFunc(state.blendFn[0], state.blendFn[1]);
|
|
141
|
+
state.blendEq !== void 0 && gl.blendEquation(state.blendEq);
|
|
141
142
|
}
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
143
|
+
if (state.stencil !== void 0) {
|
|
144
|
+
this.setState(gl.STENCIL_TEST, state.stencil);
|
|
145
|
+
state.stencilFn && gl.stencilFunc(
|
|
146
|
+
state.stencilFn[0],
|
|
147
|
+
state.stencilFn[1],
|
|
148
|
+
state.stencilFn[2]
|
|
149
|
+
);
|
|
150
|
+
state.stencilOp && gl.stencilOp(
|
|
151
|
+
state.stencilOp[0],
|
|
152
|
+
state.stencilOp[1],
|
|
153
|
+
state.stencilOp[2]
|
|
154
|
+
);
|
|
155
|
+
state.stencilMask !== void 0 && gl.stencilMask(state.stencilMask);
|
|
149
156
|
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
? shaderSourceFromAST(spec, "vs", version, opts)
|
|
157
|
-
: prepareShaderSource(spec, "vs", version);
|
|
158
|
-
const srcFS = isFunction(spec.fs)
|
|
159
|
-
? shaderSourceFromAST(spec, "fs", version, opts)
|
|
160
|
-
: prepareShaderSource(spec, "fs", version);
|
|
161
|
-
const logger = opts?.logger || LOGGER;
|
|
162
|
-
logger.debug(srcVS);
|
|
163
|
-
logger.debug(srcFS);
|
|
164
|
-
initShaderExtensions(gl, spec.ext);
|
|
165
|
-
const vs = compileShader(gl, gl.VERTEX_SHADER, srcVS);
|
|
166
|
-
const fs = compileShader(gl, gl.FRAGMENT_SHADER, srcFS);
|
|
167
|
-
const program = gl.createProgram() || error("error creating shader program");
|
|
168
|
-
gl.attachShader(program, vs);
|
|
169
|
-
gl.attachShader(program, fs);
|
|
170
|
-
gl.linkProgram(program);
|
|
171
|
-
if (gl.getProgramParameter(program, gl.LINK_STATUS)) {
|
|
172
|
-
const attribs = initAttributes(gl, program, spec.attribs);
|
|
173
|
-
const uniforms = initUniforms(gl, program, spec.uniforms);
|
|
174
|
-
gl.deleteShader(vs);
|
|
175
|
-
gl.deleteShader(fs);
|
|
176
|
-
return new Shader(gl, program, attribs, uniforms, spec.state);
|
|
157
|
+
}
|
|
158
|
+
setState(id, val) {
|
|
159
|
+
if (val) {
|
|
160
|
+
this.gl.enable(id);
|
|
161
|
+
} else {
|
|
162
|
+
this.gl.disable(id);
|
|
177
163
|
}
|
|
178
|
-
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
const defShader = (gl, spec, opts) => {
|
|
167
|
+
const version = isGL2Context(gl) ? GLSLVersion.GLES_300 : GLSLVersion.GLES_100;
|
|
168
|
+
const srcVS = isFunction(spec.vs) ? shaderSourceFromAST(spec, "vs", version, opts) : prepareShaderSource(spec, "vs", version);
|
|
169
|
+
const srcFS = isFunction(spec.fs) ? shaderSourceFromAST(spec, "fs", version, opts) : prepareShaderSource(spec, "fs", version);
|
|
170
|
+
const logger = opts?.logger || LOGGER;
|
|
171
|
+
logger.debug(srcVS);
|
|
172
|
+
logger.debug(srcFS);
|
|
173
|
+
initShaderExtensions(gl, spec.ext);
|
|
174
|
+
const vs = compileShader(gl, gl.VERTEX_SHADER, srcVS);
|
|
175
|
+
const fs = compileShader(gl, gl.FRAGMENT_SHADER, srcFS);
|
|
176
|
+
const program2 = gl.createProgram() || error("error creating shader program");
|
|
177
|
+
gl.attachShader(program2, vs);
|
|
178
|
+
gl.attachShader(program2, fs);
|
|
179
|
+
gl.linkProgram(program2);
|
|
180
|
+
if (gl.getProgramParameter(program2, gl.LINK_STATUS)) {
|
|
181
|
+
const attribs = initAttributes(gl, program2, spec.attribs);
|
|
182
|
+
const uniforms = initUniforms(gl, program2, spec.uniforms);
|
|
183
|
+
gl.deleteShader(vs);
|
|
184
|
+
gl.deleteShader(fs);
|
|
185
|
+
return new Shader(gl, program2, attribs, uniforms, spec.state);
|
|
186
|
+
}
|
|
187
|
+
throw new Error(`Error linking shader: ${gl.getProgramInfoLog(program2)}`);
|
|
179
188
|
};
|
|
180
189
|
const compileVars = (attribs, syntax, prefixes) => {
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
}
|
|
190
|
+
let decls = [];
|
|
191
|
+
for (let id in attribs) {
|
|
192
|
+
if (attribs.hasOwnProperty(id)) {
|
|
193
|
+
decls.push(syntax(id, attribs[id], prefixes));
|
|
186
194
|
}
|
|
187
|
-
|
|
188
|
-
|
|
195
|
+
}
|
|
196
|
+
decls.push("");
|
|
197
|
+
return decls.join("\n");
|
|
189
198
|
};
|
|
190
199
|
const compileExtensionPragma = (id, behavior, version) => {
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
? behavior
|
|
196
|
-
? "enable"
|
|
197
|
-
: "disable"
|
|
198
|
-
: behavior}\n`
|
|
199
|
-
: "";
|
|
200
|
+
const ext = GL_EXT_INFO[id];
|
|
201
|
+
const gl2 = version === GLSLVersion.GLES_300;
|
|
202
|
+
return ext && (!gl2 && ext.gl || gl2 && ext.gl2) ? `#extension ${ext && ext.alias || id} : ${isBoolean(behavior) ? behavior ? "enable" : "disable" : behavior}
|
|
203
|
+
` : "";
|
|
200
204
|
};
|
|
201
205
|
const initShaderExtensions = (gl, exts) => {
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
}
|
|
206
|
+
if (exts) {
|
|
207
|
+
for (let id in exts) {
|
|
208
|
+
const state = exts[id];
|
|
209
|
+
if (state === true || state === "require") {
|
|
210
|
+
getExtensions(gl, [id], state === "require");
|
|
211
|
+
}
|
|
209
212
|
}
|
|
213
|
+
}
|
|
210
214
|
};
|
|
211
215
|
const compilePrelude = (spec, version) => {
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
}
|
|
216
|
+
let prelude = spec.pre ? spec.replacePrelude ? spec.pre : spec.pre + "\n" + GLSL_HEADER : GLSL_HEADER;
|
|
217
|
+
if (spec.ext) {
|
|
218
|
+
for (let id in spec.ext) {
|
|
219
|
+
prelude += compileExtensionPragma(
|
|
220
|
+
id,
|
|
221
|
+
spec.ext[id],
|
|
222
|
+
version
|
|
223
|
+
);
|
|
221
224
|
}
|
|
222
|
-
|
|
225
|
+
}
|
|
226
|
+
return prelude;
|
|
223
227
|
};
|
|
224
228
|
const compileIODecls = (decl, src, dest) => {
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
: decl(a, id);
|
|
230
|
-
}
|
|
229
|
+
for (let id in src) {
|
|
230
|
+
const a = src[id];
|
|
231
|
+
dest[id] = isArray(a) ? decl(a[0], id, { loc: a[1] }) : decl(a, id);
|
|
232
|
+
}
|
|
231
233
|
};
|
|
232
234
|
const varyingOpts = (v) => {
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
/(u?int|[ui]vec[234])/.test(vtype) && (opts.smooth = "flat");
|
|
237
|
-
return [vtype, opts];
|
|
235
|
+
const [vtype, opts] = isArray(v) ? [v[0], { num: v[1] }] : [v, {}];
|
|
236
|
+
/(u?int|[ui]vec[234])/.test(vtype) && (opts.smooth = "flat");
|
|
237
|
+
return [vtype, opts];
|
|
238
238
|
};
|
|
239
239
|
const compileVaryingDecls = (spec, decl, acc) => {
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
240
|
+
for (let id in spec.varying) {
|
|
241
|
+
const [vtype, opts] = varyingOpts(spec.varying[id]);
|
|
242
|
+
acc[id] = decl(vtype, id, opts);
|
|
243
|
+
}
|
|
244
244
|
};
|
|
245
245
|
const compileUniformDecls = (spec, acc) => {
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
246
|
+
for (let id in spec.uniforms) {
|
|
247
|
+
const u = spec.uniforms[id];
|
|
248
|
+
acc[id] = isArray(u) ? uniform(
|
|
249
|
+
u[0],
|
|
250
|
+
id,
|
|
251
|
+
u[0].indexOf("[]") > 0 ? { num: u[1] } : void 0
|
|
252
|
+
) : uniform(u, id);
|
|
253
|
+
}
|
|
252
254
|
};
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
else {
|
|
278
|
-
unsupported(`GLSL ${version} doesn't support output vars`);
|
|
279
|
-
}
|
|
280
|
-
}
|
|
255
|
+
const shaderSourceFromAST = (spec, type, version, opts = {}) => {
|
|
256
|
+
let prelude = compilePrelude(spec, version);
|
|
257
|
+
const inputs = {};
|
|
258
|
+
const outputs = {};
|
|
259
|
+
const outputAliases = {};
|
|
260
|
+
const unis = {};
|
|
261
|
+
spec.uniforms && compileUniformDecls(spec, unis);
|
|
262
|
+
if (type === "vs") {
|
|
263
|
+
compileIODecls(input, spec.attribs, inputs);
|
|
264
|
+
spec.varying && compileVaryingDecls(spec, output, outputs);
|
|
265
|
+
} else {
|
|
266
|
+
spec.varying && compileVaryingDecls(spec, input, inputs);
|
|
267
|
+
const outs = spec.outputs || DEFAULT_OUTPUT;
|
|
268
|
+
if (version >= GLSLVersion.GLES_300) {
|
|
269
|
+
compileIODecls(output, outs, outputs);
|
|
270
|
+
} else {
|
|
271
|
+
for (let id in outs) {
|
|
272
|
+
const o = outs[id];
|
|
273
|
+
if (isArray(o) && o[0] === "vec4") {
|
|
274
|
+
prelude += `#define ${id} gl_FragData[${o[1]}]
|
|
275
|
+
`;
|
|
276
|
+
outputAliases[id] = sym("vec4", id);
|
|
277
|
+
} else {
|
|
278
|
+
unsupported(`GLSL ${version} doesn't support output vars`);
|
|
281
279
|
}
|
|
280
|
+
}
|
|
282
281
|
}
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
282
|
+
}
|
|
283
|
+
const target = targetGLSL({
|
|
284
|
+
type,
|
|
285
|
+
version,
|
|
286
|
+
prelude,
|
|
287
|
+
prec: opts.prec
|
|
288
|
+
});
|
|
289
|
+
return target(
|
|
290
|
+
program([
|
|
291
|
+
...vals(unis),
|
|
292
|
+
...vals(inputs),
|
|
293
|
+
...vals(outputs),
|
|
294
|
+
...spec[type](target, unis, inputs, {
|
|
295
|
+
...outputs,
|
|
296
|
+
...outputAliases
|
|
297
|
+
})
|
|
298
|
+
])
|
|
299
|
+
) + (spec.post ? "\n" + spec.post : "");
|
|
298
300
|
};
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
src += spec[type];
|
|
314
|
-
|
|
315
|
-
|
|
301
|
+
const prepareShaderSource = (spec, type, version) => {
|
|
302
|
+
const syntax = SYNTAX[version];
|
|
303
|
+
const prefixes = { ...NO_PREFIXES, ...spec.declPrefixes };
|
|
304
|
+
const isVS = type === "vs";
|
|
305
|
+
let src = "";
|
|
306
|
+
src += `#version ${version}
|
|
307
|
+
`;
|
|
308
|
+
src += compilePrelude(spec, version);
|
|
309
|
+
if (spec.generateDecls !== false) {
|
|
310
|
+
src += isVS ? compileVars(spec.attribs, syntax.attrib, prefixes) : compileVars(
|
|
311
|
+
spec.outputs || DEFAULT_OUTPUT,
|
|
312
|
+
syntax.output,
|
|
313
|
+
prefixes
|
|
314
|
+
);
|
|
315
|
+
src += compileVars(spec.varying, syntax.varying[type], prefixes);
|
|
316
|
+
src += compileVars(spec.uniforms, syntax.uniform, prefixes);
|
|
317
|
+
}
|
|
318
|
+
src += spec[type];
|
|
319
|
+
spec.post && (src += "\n" + spec.post);
|
|
320
|
+
return src;
|
|
316
321
|
};
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
322
|
+
const compileShader = (gl, type, src) => {
|
|
323
|
+
const shader = gl.createShader(type) || error("error creating shader");
|
|
324
|
+
gl.shaderSource(shader, src);
|
|
325
|
+
gl.compileShader(shader);
|
|
326
|
+
if (gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
|
|
327
|
+
return shader;
|
|
328
|
+
}
|
|
329
|
+
return parseAndThrowShaderError(gl, shader, src);
|
|
325
330
|
};
|
|
326
331
|
const parseAndThrowShaderError = (gl, shader, src) => {
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
return error(`Error compiling shader:\n${errors}`);
|
|
332
|
+
const lines = src.split("\n");
|
|
333
|
+
const log = gl.getShaderInfoLog(shader).split("\n");
|
|
334
|
+
const errors = log.map((line) => {
|
|
335
|
+
const matches = ERROR_REGEXP.exec(line);
|
|
336
|
+
const ln = matches ? matches[1] : null;
|
|
337
|
+
if (ln) {
|
|
338
|
+
return `line ${ln}: ${matches[2]}
|
|
339
|
+
${lines[parseInt(ln) - 1]}`;
|
|
340
|
+
}
|
|
341
|
+
}).filter(existsAndNotNull).join("\n");
|
|
342
|
+
return error(`Error compiling shader:
|
|
343
|
+
${errors}`);
|
|
340
344
|
};
|
|
341
345
|
const initAttributes = (gl, prog, attribs) => {
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
};
|
|
356
|
-
}
|
|
346
|
+
const res = {};
|
|
347
|
+
for (let id in attribs) {
|
|
348
|
+
const val = attribs[id];
|
|
349
|
+
const [type, loc] = isArray(val) ? val : [val, null];
|
|
350
|
+
const aid = id;
|
|
351
|
+
if (loc != null) {
|
|
352
|
+
gl.bindAttribLocation(prog, loc, aid);
|
|
353
|
+
res[id] = { type, loc };
|
|
354
|
+
} else {
|
|
355
|
+
res[id] = {
|
|
356
|
+
type,
|
|
357
|
+
loc: gl.getAttribLocation(prog, aid)
|
|
358
|
+
};
|
|
357
359
|
}
|
|
358
|
-
|
|
360
|
+
}
|
|
361
|
+
return res;
|
|
359
362
|
};
|
|
360
363
|
const initUniforms = (gl, prog, uniforms = {}) => {
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
type = val;
|
|
376
|
-
}
|
|
377
|
-
const loc = gl.getUniformLocation(prog, id);
|
|
378
|
-
if (loc != null) {
|
|
379
|
-
const setter = UNIFORM_SETTERS[type];
|
|
380
|
-
if (setter) {
|
|
381
|
-
res[id] = {
|
|
382
|
-
loc,
|
|
383
|
-
setter: setter(gl, loc, defaultVal),
|
|
384
|
-
defaultFn,
|
|
385
|
-
defaultVal,
|
|
386
|
-
type,
|
|
387
|
-
};
|
|
388
|
-
}
|
|
389
|
-
else {
|
|
390
|
-
error(`invalid uniform type: ${type}`);
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
else {
|
|
394
|
-
LOGGER.warn(`unknown uniform: ${id}`);
|
|
395
|
-
}
|
|
364
|
+
const res = {};
|
|
365
|
+
for (let id in uniforms) {
|
|
366
|
+
const val = uniforms[id];
|
|
367
|
+
let type;
|
|
368
|
+
let t1, t2, defaultVal, defaultFn;
|
|
369
|
+
if (isArray(val)) {
|
|
370
|
+
[type, t1, t2] = val;
|
|
371
|
+
defaultVal = type.indexOf("[]") < 0 ? t1 : t2;
|
|
372
|
+
if (isFunction(defaultVal)) {
|
|
373
|
+
defaultFn = defaultVal;
|
|
374
|
+
defaultVal = void 0;
|
|
375
|
+
}
|
|
376
|
+
} else {
|
|
377
|
+
type = val;
|
|
396
378
|
}
|
|
397
|
-
|
|
379
|
+
const loc = gl.getUniformLocation(prog, id);
|
|
380
|
+
if (loc != null) {
|
|
381
|
+
const setter = UNIFORM_SETTERS[type];
|
|
382
|
+
if (setter) {
|
|
383
|
+
res[id] = {
|
|
384
|
+
loc,
|
|
385
|
+
setter: setter(gl, loc, defaultVal),
|
|
386
|
+
defaultFn,
|
|
387
|
+
defaultVal,
|
|
388
|
+
type
|
|
389
|
+
};
|
|
390
|
+
} else {
|
|
391
|
+
error(`invalid uniform type: ${type}`);
|
|
392
|
+
}
|
|
393
|
+
} else {
|
|
394
|
+
LOGGER.warn(`unknown uniform: ${id}`);
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
return res;
|
|
398
|
+
};
|
|
399
|
+
export {
|
|
400
|
+
Shader,
|
|
401
|
+
compileShader,
|
|
402
|
+
defShader,
|
|
403
|
+
prepareShaderSource,
|
|
404
|
+
shaderSourceFromAST
|
|
398
405
|
};
|