Skip to content

Instantly share code, notes, and snippets.

@postspectacular
Last active June 14, 2019 02:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save postspectacular/43f3424aa9716fde1b84bfef70081e02 to your computer and use it in GitHub Desktop.
Save postspectacular/43f3424aa9716fde1b84bfef70081e02 to your computer and use it in GitHub Desktop.
@thi.ng/shader-ast WIP codegen example w/ multiple output targets (GLSL & JS)
// // // //
// ///// // //// // //// ///// //// ///// //////
// // ///// // ///// // // // // ////// // // //
// //// // // ///// // // ////// // ///// //// //
// // // // // // // // // // // // // //
// ///// // // ///// ///// //// // ///// ///// ///
//
// Head over to thi.ng/shader-ast for more details
const ast = require("@thi.ng/shader-ast");
const v = require("@thi.ng/vectors");
// define function using AST DSL
// (looks more verbose due to `ast.` prefixes)
// every node carries type information (both at runtime & authoring time)
// the latter provides realtime feedback about type mismatches
// e.g. the built-in `dot` function returns a float, which too is
// the return value of the entire `phong` function.
// when `defn` executes the function body is also checked for correct
// return types...
const phong = ast.defn(
"f32", "phong",
[["vec3", "ldir"], ["vec3", "edir"], ["vec3", "n"]],
(ld, ed, n) => [
ast.ret(ast.dot(ast.reflect(ast.neg(ld), n), ed))
]);
// resulting AST
// [Function: $] {
// tag: 'fn',
// type: 'f32',
// id: 'phong',
// args: [
// { tag: 'arg', type: 'vec3', id: 'ldir', q: 'in' },
// { tag: 'arg', type: 'vec3', id: 'edir', q: 'in' },
// { tag: 'arg', type: 'vec3', id: 'n', q: 'in' }
// ],
// scope: { tag: 'scope', type: 'void', body: [ [Object] ], global: false }
// }
// note `phong` is a callable JS function
// when called it returns a function-call AST node.
// in TypeScript the arguments are type checked
// see api.ts & ast.ts for details
phong(ast.vec3(1,-1,0),ast.vec3(0,-1,0),ast.vec3(0,1,0))
// {
// tag: 'call',
// type: 'f32',
// id: 'phong',
// args: [
// { tag: 'lit', type: 'vec3', val: [Array] },
// { tag: 'lit', type: 'vec3', val: [Array] },
// { tag: 'lit', type: 'vec3', val: [Array] }
// ]
// }
// emit function as GLSL
const gl = ast.targetGLSL();
console.log(gl(phong));
// float phong(in vec3 ldir, in vec3 edir, in vec3 n) {
// return dot(reflect(-ldir, n), edir);
// }
// emit as JS
// for JS all built-in fns are delegated to an environment object
// provided by the user
const js = ast.targetJS();
console.log(js(phong))
// /**
// * @param ldir vec3
// * @param edir vec3
// * @param n vec3
// */
// function phong(ldir, edir, n) {
// return env.vec3_dot(env.vec3_reflect(env.vec3_sub1(ldir), n), edir);
// };
// now compile as actual JS function
const compile = new Function("env", js(phong) + "\nreturn phong");
// then instantiate with given test environment
// here the env is used to delegate built-in fns to @thi.ng/vectors
const phong2 = compile({
vec3_dot: v.dot3,
vec3_reflect: (a,b) => v.reflect([], a, b),
vec3_sub1: (a) => v.neg([], a)
});
phong2([1,-1,0], [0,-1,0], [0,1,0]);
// 1
// tada :)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment