Skip to content

Commit

Permalink
feat(webgl): update GLSL syntax impls, migrate Shader.fromSpec()
Browse files Browse the repository at this point in the history
- add support for WebGL extensions in shader spec
- support array types for varying vars
- move Shader.fromSpec() to shader()
  • Loading branch information
postspectacular committed Apr 6, 2019
1 parent 648ed52 commit 02f94d7
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 49 deletions.
37 changes: 19 additions & 18 deletions packages/webgl/src/glsl/syntax.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,10 @@ export const SYNTAX: Record<GLSLVersion, GLSLSyntax> = {
attrib: (id, type, pre) =>
`attribute ${GLSL[isArray(type) ? type[0] : type]} ${pre.a}${id};`,
varying: {
vs: (id, type, pre) => `varying ${GLSL[type]} ${pre.v}${id};`,
fs: (id, type, pre) => `varying ${GLSL[type]} ${pre.v}${id};`
},
uniform: (id, u, pre) => {
const type = isArray(u) ? u[0] : u;
return `uniform ${GLSL[type]}${
type >= GLSL.bool_array ? `[${u[1]}]` : ""
} ${pre.u}${id};`;
vs: (id, type, pre) => arrayDecl("varying", type, pre.v + id),
fs: (id, type, pre) => arrayDecl("varying", type, pre.v + id)
},
uniform: (id, u, pre) => arrayDecl("uniform", <any>u, pre.u + id),
output: () => ""
},
/**
Expand All @@ -50,20 +45,15 @@ export const SYNTAX: Record<GLSLVersion, GLSLSyntax> = {
number: 300,
attrib: (id, type, pre) =>
isArray(type)
? `layout(location=${type[1]}) in ${GLSL[type[0]]} a_${
? `layout(location=${type[1]}) in ${GLSL[type[0]]} ${
pre.a
}${id};`
: `in ${GLSL[type]} ${id};`,
: `in ${GLSL[type]} ${pre.a}${id};`,
varying: {
vs: (id, type, pre) => `out ${GLSL[type]} v_${pre.v}${id};`,
fs: (id, type, pre) => `in ${GLSL[type]} v_${pre.v}${id};`
},
uniform: (id, u, pre) => {
const type = isArray(u) ? u[0] : u;
return `uniform ${GLSL[type]}${
type >= GLSL.bool_array ? `[${u[1]}]` : ""
} u_${pre.u}${id};`;
vs: (id, type, pre) => arrayDecl("out", type, pre.v + id),
fs: (id, type, pre) => arrayDecl("in", type, pre.v + id)
},
uniform: (id, u, pre) => arrayDecl("uniform", <any>u, pre.u + id),
output: (id, type, pre) =>
isArray(type)
? `layout(location=${type[1]}) out ${GLSL[type[0]]} ${
Expand All @@ -73,6 +63,17 @@ export const SYNTAX: Record<GLSLVersion, GLSLSyntax> = {
}
};

const arrayDecl = (
qualifier: string,
decl: GLSL | [GLSL, number],
id: string
) => {
const type = isArray(decl) ? decl[0] : decl;
return type >= GLSL.bool_array
? `${qualifier} ${GLSL[type].replace("_array", "")} ${id}[${decl[1]}];`
: `${qualifier} ${GLSL[type]} ${id};`;
};

/**
* GLSL preprocessor macro for conditional execution based on `__VERSION__`.
*
Expand Down
74 changes: 43 additions & 31 deletions packages/webgl/src/shader.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
import { Fn3, IObjectOf, Tuple } from "@thi.ng/api";
import { existsAndNotNull, isArray, isFunction } from "@thi.ng/checks";
import {
existsAndNotNull,
isArray,
isBoolean,
isFunction
} from "@thi.ng/checks";
import {
GLSL,
GLSLDeclPrefixes,
GLSLExtensionBehavior,
GLSLVersion,
IShader,
ModelAttributeSpecs,
Expand All @@ -20,41 +26,14 @@ import {
import { error } from "./error";
import { GLSL_HEADER, PREFIXES, SYNTAX } from "./glsl/syntax";
import { UNIFORM_SETTERS } from "./uniforms";
import { isGL2Context } from "./utils";

// [SRC_ALPHA, ONE_MINUS_SRC_ALPHA];
export const DEFAULT_BLEND: Tuple<GLenum, 2> = [0x302, 0x303];

const ERROR_REGEXP = /ERROR: \d+:(\d+): (.*)/;

export class Shader implements IShader {
static fromSpec(gl: WebGLRenderingContext, spec: ShaderSpec) {
const srcVS = prepareShaderSource(spec, "vs");
const srcFS = prepareShaderSource(spec, "fs");
console.log(srcVS);
console.log(srcFS);
const vs = compileShader(gl, gl.VERTEX_SHADER, srcVS);
const fs = compileShader(gl, gl.FRAGMENT_SHADER, srcFS);
const program = gl.createProgram();
gl.attachShader(program, vs);
gl.attachShader(program, fs);
gl.linkProgram(program);
if (gl.getProgramParameter(program, gl.LINK_STATUS)) {
const attribs = initAttributes(
gl,
program,
spec.attribs,
spec.version
);
const uniforms = initUniforms(gl, program, spec.uniforms);
gl.deleteShader(vs);
gl.deleteShader(fs);
return new Shader(gl, program, attribs, uniforms, spec.state);
}
throw new Error(
`Error linking shader: ${gl.getProgramInfoLog(program)}`
);
}

gl: WebGLRenderingContext;
program: WebGLProgram;
attribs: IObjectOf<ShaderAttrib>;
Expand Down Expand Up @@ -191,8 +170,31 @@ export class Shader implements IShader {
}
}

export const shader = (gl: WebGLRenderingContext, spec: ShaderSpec) =>
Shader.fromSpec(gl, spec);
export const shader = (gl: WebGLRenderingContext, spec: ShaderSpec) => {
if (!spec.version) {
spec.version = isGL2Context(gl)
? GLSLVersion.GLES_300
: GLSLVersion.GLES_100;
}
const srcVS = prepareShaderSource(spec, "vs");
const srcFS = prepareShaderSource(spec, "fs");
console.log(srcVS);
console.log(srcFS);
const vs = compileShader(gl, gl.VERTEX_SHADER, srcVS);
const fs = compileShader(gl, gl.FRAGMENT_SHADER, srcFS);
const program = gl.createProgram();
gl.attachShader(program, vs);
gl.attachShader(program, fs);
gl.linkProgram(program);
if (gl.getProgramParameter(program, gl.LINK_STATUS)) {
const attribs = initAttributes(gl, program, spec.attribs, spec.version);
const uniforms = initUniforms(gl, program, spec.uniforms);
gl.deleteShader(vs);
gl.deleteShader(fs);
return new Shader(gl, program, attribs, uniforms, spec.state);
}
throw new Error(`Error linking shader: ${gl.getProgramInfoLog(program)}`);
};

const compileVars = (
attribs: any,
Expand All @@ -209,6 +211,11 @@ const compileVars = (
return decls.join("\n");
};

const compileExtensionPragma = (id: string, behavior: GLSLExtensionBehavior) =>
`#extension ${id} : ${
isBoolean(behavior) ? (behavior ? "enable" : "disable") : behavior
}\n`;

export const prepareShaderSource = (spec: ShaderSpec, type: ShaderType) => {
const syntax = SYNTAX[spec.version || GLSLVersion.GLES_100];
const prefixes = { ...PREFIXES, ...spec.declPrefixes };
Expand All @@ -220,6 +227,11 @@ export const prepareShaderSource = (spec: ShaderSpec, type: ShaderType) => {
? spec.pre
: spec.pre + "\n" + GLSL_HEADER
: GLSL_HEADER;
if (spec.ext) {
for (let id in spec.ext) {
src += compileExtensionPragma(id, spec.ext[id]);
}
}
if (spec.generateDecls !== false) {
src += isVS
? compileVars(spec.attribs, syntax.attrib, prefixes)
Expand Down

0 comments on commit 02f94d7

Please sign in to comment.