Comparing version 1.6.0 to 2.0.0
@@ -1,8 +0,7 @@ | ||
module.exports = noop | ||
function noop() { | ||
module.exports = function() { | ||
throw new Error( | ||
'You should bundle your code ' + | ||
'using `glslify` as a transform.' | ||
"It appears that you're using glslify in browserify without " | ||
+ "its transform applied. Make sure that you've set up glslify as a source transform: " | ||
+ "https://github.com/substack/node-browserify#browserifytransform" | ||
) | ||
} |
261
index.js
@@ -0,192 +1,131 @@ | ||
var glslifyBundle = require('glslify-bundle') | ||
var staticModule = require('static-module') | ||
var glslifyDeps = require('glslify-deps') | ||
var glslResolve = require('glsl-resolve') | ||
var through = require('through2') | ||
var nodeResolve = require('resolve') | ||
var path = require('path') | ||
var fs = require('fs') | ||
module.exports = transform | ||
module.exports.bundle = bundle | ||
var glslify = require('glslify-stream') | ||
, deparser = require('glsl-deparser') | ||
, replace = require('replace-method') | ||
, concat = require('concat-stream') | ||
, evaluate = require('static-eval') | ||
, extract = require('glsl-extract') | ||
, emit = require('emit-function') | ||
, through = require('through') | ||
, resolve = require('resolve') | ||
, esprima = require('esprima') | ||
, sleuth = require('sleuth') | ||
, from = require('new-from') | ||
, path = require('path') | ||
function transform(jsFilename) { | ||
if (path.extname(jsFilename) === '.json') return through() | ||
var usageRegex = /['"]glslify['"]/ | ||
function transform(filename) { | ||
var stream = through(write, end) | ||
, accum = [] | ||
, len = 0 | ||
return stream | ||
function write(buf) { | ||
accum[accum.length] = buf | ||
len += buf.length | ||
} | ||
function end() { | ||
var buf = Buffer.concat(accum).toString('utf8') | ||
// break out early if it doesn't look like | ||
// we're going to find any shaders here, | ||
// parsing and transforming the AST is expensive! | ||
if(!usageRegex.test(buf)) { | ||
return bail(buf) | ||
// static-module is responsible for replacing any | ||
// calls to glslify in your JavaScript with a string | ||
// of our choosing – in this case, our bundled glslify | ||
// shader source. | ||
var sm = staticModule({ | ||
glslify: streamBundle | ||
}, { | ||
vars: { | ||
__dirname: path.dirname(jsFilename), | ||
__filename: jsFilename, | ||
require: { | ||
resolve: nodeResolve | ||
} | ||
} | ||
}) | ||
var ast = esprima.parse(buf) | ||
, name = glslifyname(ast) | ||
, src = replace(ast) | ||
, loading = 0 | ||
, map = {} | ||
, id = 0 | ||
return sm | ||
// bail early if glslify isn't required at all | ||
if(!name) { | ||
return bail(buf) | ||
} | ||
function streamBundle(filename, opts) { | ||
var stream = through() | ||
src.replace([name], function(node) { | ||
var fragment | ||
, current | ||
, vertex | ||
, config | ||
opts = opts || {} | ||
opts.basedir = opts.basedir || path.dirname(jsFilename) | ||
current = ++id | ||
bundle(filename, opts, function(err, source) { | ||
if (err) return stream.emit('error', err) | ||
if(!node.arguments.length) { | ||
return | ||
} | ||
stream.push(JSON.stringify(source)) | ||
stream.push(null) | ||
}) | ||
var cwd = path.dirname(filename) | ||
config = evaluate(node.arguments[0], { | ||
__filename: filename | ||
, __dirname: cwd | ||
}) | ||
return stream | ||
} | ||
} | ||
if(typeof config !== 'object') { | ||
return | ||
} | ||
function bundle(filename, opts, done) { | ||
opts = opts || {} | ||
var sourceOnly = !!config.sourceOnly | ||
var frag = config.fragment || config.frag | ||
var vert = config.vertex || config.vert | ||
var inline = !!config.inline | ||
var defaultBase = opts.inline | ||
? process.cwd() | ||
: path.dirname(filename) | ||
var streamOpts = { | ||
input: inline | ||
, transform: config.transform | ||
} | ||
var base = path.resolve(opts.basedir || defaultBase) | ||
var posts = [] | ||
var depper = glslifyDeps({ | ||
cwd: base | ||
}) | ||
++loading | ||
var vert_stream = glslify( | ||
inline ? filename : path.resolve(cwd, vert) | ||
, streamOpts) | ||
// Extract and add our local transforms. | ||
var transforms = opts.transform || [] | ||
var frag_stream = glslify( | ||
inline ? filename : path.resolve(cwd, frag) | ||
, streamOpts) | ||
transforms = Array.isArray(transforms) ? transforms : [transforms] | ||
transforms.forEach(function(transform) { | ||
transform = Array.isArray(transform) ? transform : [transform] | ||
if(inline) { | ||
from([vert]).pipe(vert_stream) | ||
from([frag]).pipe(frag_stream) | ||
} | ||
var name = transform[0] | ||
var opts = transform[1] || {} | ||
vert_stream | ||
.on('file', emit(stream, 'file')) | ||
.on('error', emit(stream, 'error')) | ||
.pipe(deparser()) | ||
.pipe(concat(onvertex)) | ||
if (opts.post) { | ||
posts.push({ name: name, opts: opts }) | ||
} else { | ||
depper.transform(name, opts) | ||
} | ||
}) | ||
frag_stream | ||
.on('file', emit(stream, 'file')) | ||
.on('error', emit(stream, 'error')) | ||
.pipe(deparser()) | ||
.pipe(concat(onfragment)) | ||
if (opts.inline) { | ||
depper.inline(filename | ||
, base | ||
, addedDep) | ||
} else { | ||
filename = glslResolve.sync(filename, { | ||
basedir: base | ||
}) | ||
return { | ||
type: 'CallExpression' | ||
, callee: { | ||
type: 'CallExpression' | ||
, callee: { | ||
type: 'Identifier' | ||
, name: 'require' | ||
} | ||
, arguments: [ | ||
{type: 'Literal', value: sourceOnly ? 'glslify/simple-adapter.js' : 'glslify/adapter.js'} | ||
] | ||
} | ||
, arguments: [ | ||
{type: 'Identifier', name: '__glslify_' + current + '_vert'} | ||
, {type: 'Identifier', name: '__glslify_' + current + '_frag'} | ||
, {type: 'Identifier', name: '__glslify_' + current + '_unis'} | ||
, {type: 'Identifier', name: '__glslify_' + current + '_attrs'} | ||
] | ||
} | ||
depper.add(filename, addedDep) | ||
} | ||
function onvertex(data) { | ||
vertex = data | ||
vertex && fragment && done() | ||
} | ||
// Builds a dependency tree starting from the | ||
// given `filename` using glslify-deps. | ||
function addedDep(err, tree) { | ||
if (err) return done(err) | ||
function onfragment(data) { | ||
fragment = data | ||
vertex && fragment && done() | ||
} | ||
try { | ||
// Turn that dependency tree into a GLSL string, | ||
// stringified for use in our JavaScript. | ||
var source = glslifyBundle(tree) | ||
} catch(e) { | ||
return done(e) | ||
} | ||
function done() { | ||
extract(vertex + '\n' + fragment)(function(err, info) { | ||
if(err) { | ||
return stream.emit('error', err) | ||
} | ||
// Finally, this applies our --post transforms | ||
next() | ||
function next() { | ||
var tr = posts.shift() | ||
if (!tr) return postDone() | ||
--loading | ||
var target = nodeResolve.sync(tr.name, { | ||
basedir: path.dirname(filename) | ||
}) | ||
map[current] = [vertex, fragment, info.uniforms, info.attributes] | ||
var transform = require(target) | ||
if(!loading) { | ||
finish() | ||
} | ||
}) | ||
} | ||
}) | ||
if(!loading) { | ||
finish() | ||
} | ||
function finish() { | ||
var code = src.code() | ||
, unmap | ||
unmap = {vert: 0, frag: 1, unis: 2, attrs: 3} | ||
code = code.replace(/__glslify_(\d+)_(vert|frag|unis|attrs)/g, function(all, num, type) { | ||
return JSON.stringify(map[num][unmap[type]]) | ||
transform(null, source, { | ||
post: true | ||
}, function(err, data) { | ||
if (err) throw err | ||
if (data) source = data | ||
next() | ||
}) | ||
stream.queue(code) | ||
stream.queue(null) | ||
} | ||
function bail(code) { | ||
stream.queue(code) | ||
stream.queue(null) | ||
function postDone() { | ||
done(null, source) | ||
} | ||
} | ||
} | ||
function glslifyname(ast) { | ||
var required = sleuth(ast) | ||
var name | ||
Object.keys(required).some(function(key) { | ||
return name = (required[key] === 'glslify' ? key : null) | ||
}) | ||
return name | ||
} |
{ | ||
"name": "glslify", | ||
"version": "1.6.0", | ||
"description": "command line glsl module system builder", | ||
"version": "2.0.0", | ||
"description": "A node.js-style module system for GLSL!", | ||
"main": "index.js", | ||
"bin": { | ||
"glslify": "bin.js" | ||
}, | ||
"license": "MIT", | ||
"scripts": { | ||
"test": "node test/index.js" | ||
"test": "node test | tap-spec" | ||
}, | ||
"bin": { | ||
"glslify": "./bin/glslify" | ||
"authors": [ | ||
"Hugh Kennedy <hughskennedy@gmail.com> (http://hughsk.io/)", | ||
"Mikola Lysenko <mikolalysenko@gmail.com> (http://0fps.net)", | ||
"Chris Dickinson <chris@neversaw.us> (http://neversaw.us)" | ||
], | ||
"dependencies": { | ||
"bl": "^0.9.4", | ||
"glsl-resolve": "0.0.1", | ||
"glslify-bundle": "^2.0.1", | ||
"glslify-deps": "^1.2.0", | ||
"minimist": "^1.1.0", | ||
"resolve": "^1.1.5", | ||
"static-module": "^1.1.2", | ||
"through2": "^0.6.3" | ||
}, | ||
"devDependencies": { | ||
"browserify": "^8.1.3", | ||
"from2": "^1.3.0", | ||
"glsl-easings": "^1.0.0", | ||
"glsl-noise": "0.0.0", | ||
"glslify-hex": "^2.0.1", | ||
"shell-quote": "^1.4.2", | ||
"tap-spec": "^2.2.1", | ||
"tape": "^3.5.0" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "git://github.com/gl-modules/glslify.git" | ||
"url": "git://github.com/stackgl/glslify.git" | ||
}, | ||
"keywords": [ | ||
"ecosystem:stackgl", | ||
"browserify-transform", | ||
"glslify", | ||
@@ -21,34 +49,13 @@ "glsl", | ||
"system", | ||
"cli" | ||
"cli", | ||
"shader", | ||
"webgl" | ||
], | ||
"authors": [ | ||
"Hugh Kennedy <hughskennedy@gmail.com> (http://hughsk.io/)", | ||
"Mikola Lysenko <mikolalysenko@gmail.com> (http://0fps.net)", | ||
"Chris Dickinson <chris@neversaw.us> (http://neversaw.us)" | ||
], | ||
"license": "MIT", | ||
"preferGlobal": "true", | ||
"dependencies": { | ||
"concat-stream": "^1.4.1", | ||
"cssauron": "0.0.2", | ||
"cssauron-glsl": "0.0.0", | ||
"emit-function": "0.0.2", | ||
"esprima": "^1.0.4", | ||
"gl-shader-core": "^2.0.0", | ||
"glsl-deparser": "0.0.2", | ||
"glsl-extract": "0.0.2", | ||
"glsl-min-stream": "0.0.2", | ||
"glslify-stream": "^0.4.0", | ||
"new-from": "^0.0.3", | ||
"nopt": "^2.0.0", | ||
"replace-method": "0.0.0", | ||
"resolve": "^0.6.1", | ||
"shortest": "0.0.0", | ||
"sleuth": "0.0.0", | ||
"static-eval": "^0.2.2", | ||
"through": "^2.3.4" | ||
}, | ||
"browser": { | ||
"index.js": "browser.js" | ||
}, | ||
"homepage": "https://github.com/stackgl/glslify", | ||
"bugs": { | ||
"url": "https://github.com/stackgl/glslify/issues" | ||
} | ||
} |
503
README.md
# glslify | ||
a module system for GLSL and a transform enabling easy access to GLSL Shaders in JavaScript. | ||
[![stable](http://badges.github.io/stability-badges/dist/stable.svg)](http://github.com/badges/stability-badges) | ||
## As a Browserify transform: | ||
A node.js-style module system for GLSL! | ||
```bash | ||
$ npm install --save glslify | ||
$ browserify entry.js -t glslify > bundle.js | ||
This module contains glslify's command-line interface (CLI) and | ||
[browserify](http://browserify.org/) transform. It forms one of the core | ||
components of the [stack.gl](http://stack.gl/) ecosystem, allowing you to | ||
install GLSL modules from [npm](http://npmjs.com) and use them in your | ||
shaders. This makes it trivial to piece together different effects and | ||
techniques from the community, including but certainly not limited to | ||
[fog](https://github.com/hughsk/glsl-fog), | ||
[noise](https://github.com/hughsk/glsl-noise), | ||
[film grain](https://github.com/mattdesl/glsl-film-grain), | ||
[raymarching helpers](https://github.com/stackgl/glsl-smooth-min), | ||
[easing functions](https://github.com/stackgl/glsl-easings) and | ||
[lighting models](https://github.com/stackgl/glsl-specular-cook-torrance). | ||
A full list can be found on the [stack.gl packages list](http://stack.gl/packages) | ||
under the "Shader Components" category. | ||
Because glslify just outputs a single shader file as a string, it's easy to use | ||
it with any WebGL framework of your choosing, | ||
provided they accept custom shaders. Integration is planned for | ||
[three.js](http://threejs.org/), [webpack](http://webpack.github.io/) and | ||
[pex](http://vorg.github.io/pex/), with more on the way! | ||
[Open an issue](https://github.com/stackgl/glslify/issues/new) here if you'd like to | ||
discuss integrating glslify with your platform of choice. | ||
## Installation | ||
[![NPM](https://nodei.co/npm/glslify.png)](https://nodei.co/npm/glslify/) | ||
To install the command-line interface, install glslify globally like | ||
so: | ||
``` bash | ||
npm install -g glslify | ||
``` | ||
glslify will find and replace all instances of `glslify({vertex: path, fragment: path})` | ||
with a function that takes a webgl context and returns a [shader instance](http://npm.im/gl-shader-core). | ||
To install glslify for use as a browserify transform, you should | ||
install it locally instead: | ||
Recommended usage: | ||
``` bash | ||
npm install glslify | ||
``` | ||
```javascript | ||
var glslify = require('glslify') // requiring `glslify` is safe in this context. | ||
// if the program is run without the transform, | ||
// it'll output a helpful error message. | ||
var shell = require('gl-now')() | ||
## Getting Started | ||
var createShader = glslify({ | ||
vertex: './vertex.glsl' | ||
, fragment: './fragment.glsl' | ||
}) | ||
### CLI | ||
var program | ||
The CLI can take a file as its first argument, and output to a file | ||
using the `-o` flag: | ||
shell.on('gl-init', function() { | ||
program = createShader(shell.gl) | ||
}) | ||
``` bash | ||
glslify index.glsl -o output.glsl | ||
``` | ||
As part of the transform, the program will be analyzed for its **uniforms** and **attributes**, | ||
so once you have a `program` instance, the following will work: | ||
It can also read input from stdin and output to stdout: | ||
```javascript | ||
``` bash | ||
cat index.glsl | glslify > output.glsl | ||
``` | ||
// given a glsl program containing: | ||
// | ||
// uniform vec2 color; | ||
// uniform mat4 view; | ||
### Browserify Transform | ||
program.bind() | ||
program.uniforms.color = [0.5, 1.0] | ||
program.uniforms.view = [ | ||
1, 0, 0, 0 | ||
, 0, 1, 0, 0 | ||
, 0, 0, 1, 0 | ||
, 0, 0, 0, 1 | ||
] | ||
If using browserify from the command-line, simply pass glslify | ||
in as a transform using the `-t`/`--transform` flag: | ||
``` bash | ||
browserify -t glslify index.js -o bundle.js | ||
``` | ||
The following options may be passed into glslify's transformed constructor: | ||
Alternatively, you may include glslify as a `browserify.transform` | ||
in your `package.json` file: | ||
* `fragment`: the fragment shader to use. | ||
* `vertex`: the vertex shader to use. | ||
* `inline`: instead of loading the vertex/fragment shaders from a file path, | ||
use the string values of these options directly to generate the shaders. | ||
* `transform`: a string or array of strings naming browserify-transform stream | ||
modules you would like to use to transform these shaders. | ||
``` json | ||
{ | ||
"name": "my-app", | ||
"dependencies": { | ||
"glslify": "^2.0.0" | ||
}, | ||
"browserify": { | ||
"transform": ["glslify"] | ||
} | ||
} | ||
``` | ||
## As a GLSL module system: | ||
When writing your app, you should be able to require and call | ||
glslify like so: | ||
glslify can be run as a standalone command as well: | ||
``` javascript | ||
// index.js | ||
var glslify = require('glslify') | ||
var src = glslify(__dirname + '/shader.glsl') | ||
```bash | ||
$ glslify my-module.glsl > output.glsl | ||
console.log(src) | ||
``` | ||
glslify allows you to write GLSL modules that export a local function, variable, or type, | ||
and `require` those modules to bring that export into another module. | ||
Your glslify calls will be replaced with bundled GLSL strings | ||
at build time automatically for you! | ||
Lookups work like node's `require` -- that is, it'll work relatively to the file first, | ||
and then work from the file's directory on up to the root directory looking for a package | ||
in `node_modules/`. | ||
``` javascript | ||
// index.js | ||
var src = "#define GLSLIFY 1\n\nprecision mediump float; ..." | ||
## example files | ||
console.log(src) | ||
``` | ||
| [`main.glsl`](#mainglsl) | [`file1.glsl`](#file1glsl) | [`file2.glsl`](#file2glsl) | | ||
|---------------------------|-----------------------------|-----------------------------| | ||
### Inline mode | ||
### main.glsl | ||
By passing the `inline` option as true, you can write your | ||
shader inline instead of requiring it to be in a separate | ||
file: | ||
[back to file list](#example-files) | ||
``` javascript | ||
var glslify = require('glslify') | ||
```c | ||
// main.glsl | ||
precision highp float; | ||
uniform float time; | ||
uniform vec2 mouse; | ||
uniform vec2 resolution; | ||
var src = glslify(` | ||
precision mediump float; | ||
// require a function from another file! | ||
#pragma glslify: program_one = require(./file1) | ||
void main() { | ||
gl_FragColor = vec4(1.0); | ||
} | ||
`, { inline: true }) | ||
``` | ||
// require a function from another file, and replace | ||
// `local_value` in that file with `resolution.x` from | ||
// this scope. | ||
#pragma glslify: program_two = require(./file2, local_value=resolution.x) | ||
## Usage | ||
int modulo(float x, float y) { | ||
return int(x - y * floor(x / y)); | ||
} | ||
### Installing a GLSL Module | ||
void main(void) { | ||
ivec2 m = ivec2(modulo(gl_FragCoord.x, 2.), modulo(gl_FragCoord.y, 2.)); | ||
Much like plain JavaScript modules, GLSL modules are stored on npm. | ||
The main difference is that GLSL modules contain an `index.glsl` file | ||
instead of an `index.js`. Generally, these modules start with `glsl-` | ||
in their name. | ||
if(m.x == 0 || m.y == 0) { | ||
program_one(); | ||
} else { | ||
program_two(); | ||
} | ||
To install [glsl-noise](https://github.com/hughsk/glsl-noise) in | ||
your current directory: | ||
``` bash | ||
npm install glsl-noise | ||
``` | ||
This will download glsl-noise and any of its dependencies, placing | ||
them in a `node_modules` directory for glslify to use. | ||
### Importing a GLSL Module | ||
You can import a module using the following `#pragma` syntax: | ||
``` glsl | ||
#pragma glslify: noise = require(glsl-noise/simplex/2d) | ||
void main() { | ||
float brightness = noise(gl_FragCoord.xy); | ||
gl_FragColor = vec4(vec3(brightness), 1.); | ||
} | ||
``` | ||
Shader dependencies are resolved using the same algorithm | ||
as node, so the above will load `./node_modules/simplex/2d.glsl` | ||
from the shader's directory. | ||
### file1.glsl | ||
The above example would result in the following output: | ||
[back to file list](#example-files) | ||
``` glsl | ||
#define GLSLIFY 1 | ||
```c | ||
// file1.glsl | ||
void main(void) { | ||
gl_FragColor = vec4(1., 0., 0., 1.); | ||
// | ||
// Description : Array and textureless GLSL 2D simplex noise function. | ||
// Author : Ian McEwan, Ashima Arts. | ||
// Maintainer : ijm | ||
// Lastmod : 20110822 (ijm) | ||
// License : Copyright (C) 2011 Ashima Arts. All rights reserved. | ||
// Distributed under the MIT License. See LICENSE file. | ||
// https://github.com/ashima/webgl-noise | ||
// | ||
vec3 mod289_1_0(vec3 x) { | ||
return x - floor(x * (1.0 / 289.0)) * 289.0; | ||
} | ||
#pragma glslify: export(main) | ||
``` | ||
vec2 mod289_1_0(vec2 x) { | ||
return x - floor(x * (1.0 / 289.0)) * 289.0; | ||
} | ||
### file2.glsl | ||
vec3 permute_1_1(vec3 x) { | ||
return mod289_1_0(((x*34.0)+1.0)*x); | ||
} | ||
[back to file list](#example-files) | ||
float snoise_1_2(vec2 v) | ||
{ | ||
const vec4 C = vec4(0.211324865405187, // (3.0-sqrt(3.0))/6.0 | ||
0.366025403784439, // 0.5*(sqrt(3.0)-1.0) | ||
-0.577350269189626, // -1.0 + 2.0 * C.x | ||
0.024390243902439); // 1.0 / 41.0 | ||
// First corner | ||
vec2 i = floor(v + dot(v, C.yy) ); | ||
vec2 x0 = v - i + dot(i, C.xx); | ||
```c | ||
// file2.glsl | ||
// Other corners | ||
vec2 i1; | ||
//i1.x = step( x0.y, x0.x ); // x0.x > x0.y ? 1.0 : 0.0 | ||
//i1.y = 1.0 - i1.x; | ||
i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0); | ||
// x0 = x0 - 0.0 + 0.0 * C.xx ; | ||
// x1 = x0 - i1 + 1.0 * C.xx ; | ||
// x2 = x0 - 1.0 + 2.0 * C.xx ; | ||
vec4 x12 = x0.xyxy + C.xxzz; | ||
x12.xy -= i1; | ||
uniform float local_value; | ||
// Permutations | ||
i = mod289_1_0(i); // Avoid truncation effects in permutation | ||
vec3 p = permute_1_1( permute_1_1( i.y + vec3(0.0, i1.y, 1.0 )) | ||
+ i.x + vec3(0.0, i1.x, 1.0 )); | ||
void main(void) { | ||
gl_FragColor = vec4(0., 0., local_value, 1.); | ||
vec3 m = max(0.5 - vec3(dot(x0,x0), dot(x12.xy,x12.xy), dot(x12.zw,x12.zw)), 0.0); | ||
m = m*m ; | ||
m = m*m ; | ||
// Gradients: 41 points uniformly over a line, mapped onto a diamond. | ||
// The ring size 17*17 = 289 is close to a multiple of 41 (41*7 = 287) | ||
vec3 x = 2.0 * fract(p * C.www) - 1.0; | ||
vec3 h = abs(x) - 0.5; | ||
vec3 ox = floor(x + 0.5); | ||
vec3 a0 = x - ox; | ||
// Normalise gradients implicitly by scaling m | ||
// Approximation of: m *= inversesqrt( a0*a0 + h*h ); | ||
m *= 1.79284291400159 - 0.85373472095314 * ( a0*a0 + h*h ); | ||
// Compute final noise value at P | ||
vec3 g; | ||
g.x = a0.x * x0.x + h.x * x0.y; | ||
g.yz = a0.yz * x12.xz + h.yz * x12.yw; | ||
return 130.0 * dot(m, g); | ||
} | ||
#pragma glslify: export(main) | ||
void main() { | ||
float brightness = snoise_1_2(gl_FragCoord.xy); | ||
gl_FragColor = vec4(vec3(brightness), 1.); | ||
} | ||
``` | ||
# GLSL API | ||
GLSLify works by mangling top-level identities in non-root modules. | ||
### Exporting a GLSL Module | ||
Exported variables will be aliased on requirement. | ||
You can export a token from a module using the `glslify: export` | ||
pragma, like so: | ||
### \#pragma glslify: VARIABLE = require(MODULE[, NAME=EXPR]) | ||
``` glsl | ||
float myFunction(vec3 normal) { | ||
return dot(vec3(0, 1, 0), normal); | ||
} | ||
Import a module and assign it the name `VARIABLE` in the local program. | ||
#pragma glslify: export(myFunction) | ||
``` | ||
`MODULE` may be located within `node_modules/` or relative to the current file. | ||
This means that when you import this module file elsewhere, you'll | ||
get `myFunction` in return: | ||
**Quotes are not allowed.** | ||
``` glsl | ||
#pragma glslify: topDot = require(./my-function.glsl) | ||
If the target module defines `attribute`, `varying`, or `uniform` global variables, | ||
you may map those to a local definition or expression: | ||
topDot(vec3(0, 1, 0)); // 1 | ||
``` | ||
```c | ||
If you check the output shader source, you'll notice that variables | ||
have been renamed to avoid conflicts between multiple shader files. | ||
attribute vec4 position; | ||
#pragma glslify: x = require(./takes_vec2, module_variable=position.xy) | ||
You're not limited to exporting functions either: you should be able | ||
to export any GLSL token, such as a struct for reuse between your | ||
modules: | ||
``` glsl | ||
struct Light { | ||
vec3 position; | ||
vec3 color; | ||
}; | ||
#pragma glslify: export(Light) | ||
``` | ||
If a mapping is not defined, those requirements are forwarded on to the module requiring | ||
the current module -- if no mappings are found for a definition, an error is raised. | ||
## Source Transforms | ||
### \#pragma glslify: export(NAME) | ||
Source transforms are a feature inspired by browserify, allowing you to | ||
modify your GLSL source at build time on a per-package basis. This is | ||
useful both for transpilation (e.g. converting from or to | ||
[HLSL](http://en.wikipedia.org/wiki/High-Level_Shading_Language)) or for | ||
making incremental improvements to GLSL syntax. (e.g. you can use | ||
[glslify-hex](https://github.com/hughsk/glslify-hex) to include CSS-style | ||
hex strings for colors in place of `vec3`s). | ||
Exports a local name from the current module. If the current module is the root, this is | ||
a no-op. There may be only one exported `NAME` per module. The `NAME` may represent a | ||
type, function, or variable. | ||
There are three kinds of source transform: | ||
* **Local transforms**, the default. These are applied per-file, and only | ||
applied to a single package. If you're defining it via the CLI using `-t` | ||
it'll only apply itself to files outside of `node_modules`, but you | ||
can include it in `package.json` too: these will be applied only to that | ||
package without interfering with any of the package's parents or children. | ||
* **Global transforms** are applied after local transforms to every file, | ||
regardless of whether or not it's a dependency. | ||
* **Post transforms** are applied to the entire output file once it's been | ||
bundled. Generally, you want to reserve this for very specific use cases | ||
such as whole-shader optimisation. | ||
# With ThreeJS | ||
There are a number of ways to use a transform. Start by | ||
installing it in your project: | ||
You can use the `sourceOnly` option to integrate glslfiy with ThreeJS and other WebGL frameworks. This will return an object with `vertex` and `fragment` shader source, which you can then compile yourself. | ||
``` bash | ||
npm install --save glslify-hex | ||
``` | ||
In ThreeJS it might look like this: | ||
The preferred way to enable a transform is through your project's | ||
`package.json` file's `glslify.transform` property, like so: | ||
```js | ||
var myShader = glslify({ | ||
vertex: './vertex.glsl', | ||
fragment: './fragment.glsl', | ||
sourceOnly: true | ||
}); | ||
``` json | ||
{ | ||
"name": "my-project", | ||
"dependencies": { | ||
"glslify-hex": "^2.0.0", | ||
"glslify": "^2.0.0" | ||
}, | ||
"glslify": { | ||
"transform": ["glslify-hex"] | ||
} | ||
} | ||
``` | ||
//optionally do something with our uniforms/attribs | ||
console.log( myShader.uniforms, myShader.attributes ); | ||
You may also include arguments to your transform as you would | ||
with browserify: | ||
//setup custom ThreeJS material... | ||
var mat = new THREE.ShaderMaterial({ | ||
vertexShader: myShader.vertex, | ||
fragmentShader: myShader.fragment | ||
uniforms: { | ||
// setup your uniforms.. | ||
} | ||
}); | ||
``` json | ||
{ | ||
"name": "my-project", | ||
"dependencies": { | ||
"glslify-hex": "^2.0.0", | ||
"glslify": "^2.0.0" | ||
}, | ||
"glslify": { | ||
"transform": [ | ||
["glslify-hex", { | ||
"option-1": true, | ||
"option-2": 42 | ||
}] | ||
] | ||
} | ||
} | ||
``` | ||
Note that this method is only available for local transforms. | ||
You may also specify transforms via the CLI: | ||
``` bash | ||
glslify -t 'local-transform' -g 'global-transform' -p 'post-transform' | ||
``` | ||
# License | ||
Or when using the browserify transform by including them as | ||
options like so: | ||
MIT | ||
``` javascript | ||
var glslify = require('glslify') | ||
glslify(__dirname + '/shader.glsl', { | ||
transform: [ | ||
["glslify-hex", { | ||
"option-1": true, | ||
"option-2": 42 | ||
}], | ||
["global-transform", { global: true }], | ||
["post-transform", { post: true }] | ||
] | ||
}) | ||
``` | ||
## Migrating from glslify@1 to glslify@2 | ||
There are two important changes to note: | ||
* [gl-shader](http://github.com/stackgl/gl-shader) is no longer bundled in with | ||
glslify's browserify transform. | ||
* glslify now accepts files individually, rather than frag/vert pairings. | ||
The following: | ||
``` javascript | ||
var glslify = require('glslify') | ||
var shader = glslify({ | ||
frag: './shader.frag', | ||
vert: './shader.vert' | ||
})(gl) | ||
``` | ||
Should now be created like so: | ||
``` javascript | ||
var glShader = require('gl-shader') | ||
var glslify = require('glslify') | ||
var shader = glShader(gl, | ||
glslify('./shader.frag'), | ||
glslify('./shader.vert') | ||
) | ||
``` | ||
## Module API | ||
You can use glslify from Node using `glslify.bundle`. The operation is | ||
performed asynchronously, but otherwise it shares the same API as | ||
glslify's browserify transform. | ||
### `glslify.bundle(file, opts, done)` | ||
Takes a `file` and calls `done(err, source)` with the finished shader | ||
when complete. Options include: | ||
* `inline`: if set to true, you can pass the GLSL source directly in | ||
place of the `file` argument. | ||
* `transform`: an array of transforms to apply to the shader. | ||
* `basedir`: the directory from which to resolve modules from in your | ||
first shader. Defaults to the first file's directory, or `process.cwd()` | ||
if inline mode is enabled. | ||
## Further Reading | ||
* [Modular and Versioned GLSL](http://mattdesl.svbtle.com/glslify) by [@mattdesl](http://mattdesl.svbtle.com/). | ||
* [Module Best Practices](https://github.com/mattdesl/module-best-practices) by [@mattdesl](http://mattdesl.svbtle.com/). | ||
* [Art of Node](https://github.com/maxogden/art-of-node) by [@maxogden](http://github.com/maxogden). | ||
* [Browserify Handbook](https://github.com/substack/browserify-handbook) by [@substack](http://substack.net). | ||
* The upcoming [WebGL Insights](http://www.crcpress.com/product/isbn/9781498716079) will include a chapter introducing glslify in detail. | ||
## Contributing | ||
See [stackgl/contributing](https://github.com/stackgl/contributing) for details. | ||
## License | ||
MIT. See [LICENSE.md](http://github.com/stackgl/glslify/blob/master/LICENSE.md) for details. |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Debug access
Supply chain riskUses debug, reflection and dynamic code execution features.
Found 1 instance in 1 package
No bug tracker
MaintenancePackage does not have a linked bug tracker in package.json.
Found 1 instance in 1 package
No website
QualityPackage does not have a website.
Found 1 instance in 1 package
20723
8
1
0
448
8
7
194
4
1
+ Addedbl@^0.9.4
+ Addedglsl-resolve@0.0.1
+ Addedglslify-bundle@^2.0.1
+ Addedglslify-deps@^1.2.0
+ Addedminimist@^1.1.0
+ Addedstatic-module@^1.1.2
+ Addedthrough2@^0.6.3
+ Added@choojs/findup@0.2.1(transitive)
+ Addedacorn@7.4.1(transitive)
+ Addedbl@0.9.5(transitive)
+ Addedcommander@2.20.3(transitive)
+ Addedduplexer2@0.0.2(transitive)
+ Addedescodegen@1.3.3(transitive)
+ Addedesprima@1.1.1(transitive)
+ Addedestraverse@1.5.1(transitive)
+ Addedesutils@1.0.0(transitive)
+ Addedevents@3.3.0(transitive)
+ Addedfalafel@2.2.5(transitive)
+ Addedfunction-bind@1.1.2(transitive)
+ Addedglsl-inject-defines@1.0.3(transitive)
+ Addedglsl-token-assignments@2.0.2(transitive)
+ Addedglsl-token-defines@1.0.0(transitive)
+ Addedglsl-token-depth@1.1.2(transitive)
+ Addedglsl-token-descope@1.0.2(transitive)
+ Addedglsl-token-inject-block@1.1.0(transitive)
+ Addedglsl-token-properties@1.0.1(transitive)
+ Addedglsl-token-scope@1.1.2(transitive)
+ Addedglsl-token-string@1.0.1(transitive)
+ Addedglsl-tokenizer@2.1.5(transitive)
+ Addedglslify-bundle@2.0.4(transitive)
+ Addedglslify-deps@1.3.2(transitive)
+ Addedgraceful-fs@4.2.11(transitive)
+ Addedhas@1.0.4(transitive)
+ Addedhasown@2.0.2(transitive)
+ Addedis-core-module@2.15.1(transitive)
+ Addedisarray@2.0.5(transitive)
+ Addedmap-limit@0.0.1(transitive)
+ Addedminimist@0.0.81.2.8(transitive)
+ Addedobject-inspect@0.4.0(transitive)
+ Addedobject-keys@0.4.0(transitive)
+ Addedonce@1.3.3(transitive)
+ Addedpath-parse@1.0.7(transitive)
+ Addedquote-stream@0.0.0(transitive)
+ Addedresolve@1.22.8(transitive)
+ Addedshallow-copy@0.0.1(transitive)
+ Addedsource-map@0.1.43(transitive)
+ Addedstatic-module@1.5.0(transitive)
+ Addedsupports-preserve-symlinks-flag@1.0.0(transitive)
+ Addedthrough2@0.4.20.6.5(transitive)
+ Addedwrappy@1.0.2(transitive)
+ Addedxtend@2.1.24.0.2(transitive)
- Removedconcat-stream@^1.4.1
- Removedcssauron@0.0.2
- Removedcssauron-glsl@0.0.0
- Removedemit-function@0.0.2
- Removedesprima@^1.0.4
- Removedgl-shader-core@^2.0.0
- Removedglsl-deparser@0.0.2
- Removedglsl-extract@0.0.2
- Removedglsl-min-stream@0.0.2
- Removedglslify-stream@^0.4.0
- Removednew-from@^0.0.3
- Removednopt@^2.0.0
- Removedreplace-method@0.0.0
- Removedshortest@0.0.0
- Removedsleuth@0.0.0
- Removedstatic-eval@^0.2.2
- Removedthrough@^2.3.4
- Removedabbrev@1.1.1(transitive)
- Removedast-types@0.3.38(transitive)
- Removedastw@0.1.0(transitive)
- Removedcls@0.1.5(transitive)
- Removedcommondir@0.0.1(transitive)
- Removedcssauron@0.0.2(transitive)
- Removedcssauron-glsl@0.0.0(transitive)
- Removeddup@1.0.0(transitive)
- Removedduplexer@0.0.4(transitive)
- Removedemit-function@0.0.2(transitive)
- Removedesprima@1.2.5(transitive)
- Removedgl-shader-core@2.2.0(transitive)
- Removedglsl-deparser@0.0.2(transitive)
- Removedglsl-extract@0.0.2(transitive)
- Removedglsl-min-stream@0.0.2(transitive)
- Removedglsl-parser@0.0.51.0.1(transitive)
- Removedglsl-tokenizer@0.0.81.1.1(transitive)
- Removedglslify-stream@0.4.1(transitive)
- Removedis-require@0.0.0(transitive)
- Removednew-from@0.0.3(transitive)
- Removednopt@2.2.1(transitive)
- Removedprivate@0.1.8(transitive)
- Removedrecast@0.5.27(transitive)
- Removedreplace-method@0.0.0(transitive)
- Removedresolve@0.5.1(transitive)
- Removedshortest@0.0.0(transitive)
- Removedsleuth@0.0.0(transitive)
- Removedsource-map@0.1.32(transitive)
- Removedstatic-eval@0.1.1(transitive)
- Removedstream-combiner@0.0.2(transitive)
- Removedthrough@1.1.22.3.42.3.8(transitive)
- Removedutf8-stream@0.0.0(transitive)
- Removedwrap-stream@0.0.0(transitive)
Updatedresolve@^1.1.5