Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Nogl implementation #2

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 21 additions & 30 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,35 +4,24 @@

![img](http://i.imgur.com/bROGMVq.png)

A helper module for unit testing shaders and comparing the result of `gl_FragColor` from a 1x1 WebGL canvas. See [glsl-hsl2rgb](https://github.com/Jam3/glsl-hsl2rgb) for a practical example.
A helper module for processing rectangular shaders and obtaining the reslut. Can be used for unit testing, audio processing etc. See [glsl-hsl2rgb](https://github.com/Jam3/glsl-hsl2rgb) or [audio-shader](https://github.com/audio-lab/audio-shader) for practical examples.

Example:
Example:

```js
var ShaderOutput = require('gl-shader-output')

//your shader, could be a simple glsl-shader-core object
var glslify = require('glslify')
var shader = glslify({
vertex: [
'attribute vec2 position;',
'void main() {',
'gl_Position = vec4(position, 1.0, 1.0);',
'}'
].join('\n')
fragment: [
'precision mediump float;',
'uniform float green;',
'void main() {',
'gl_FragColor = vec4(0.0, green, 0.0, 1.0);',
'}'
].join('\n')
})

//get a draw function for our test
var draw = ShaderOutput({
shader: shader
})
var draw = ShaderOutput(`
precision mediump float;
uniform float green;
void main() {
gl_FragColor = vec4(0.0, green, 0.0, 1.0);
}
`, {
width: 1,
height: 1
});

//returns the frag color as [R, G, B, A]
var color = draw()
Expand All @@ -46,19 +35,21 @@ var almostEqual = require('array-almost-equal')
almostEqual(color2, [0.0, 0.5, 0.0, 1.0], epsilon)
```

You can use this with tools like [smokestack](https://github.com/hughsk/smokestack) for test-driven GLSL development.
You can use this with tools like [smokestack](https://github.com/hughsk/smokestack) for test-driven GLSL development.

## Usage

[![NPM](https://nodei.co/npm/gl-shader-output.png)](https://www.npmjs.com/package/gl-shader-output)

#### `draw = ShaderOutput(opt)`
#### `draw = ShaderOutput(source?, options?)`

Takes the following options, and returns a `draw` function.
Takes a shader object/source and options object, and returns a `draw` function. Possible options:

- `shader` the shader (required), can be a function that accepts `gl` or an instance of gl-shader
- `gl` the gl state to re-use, expected to hold a 1x1 canvas (creates a new one if not specified)
- [webgl-context](https://www.npmjs.com/package/webgl-context) options such as `alpha` and `premultipliedAlpha`
- `shader` the shader, can be a source of fragment shader, a function that accepts `gl` or an instance of gl-shader. Same as passing shader as the only argument.
- `gl` the gl state to re-use, expected to hold a canvas (creates a new one if not specified, or uses nogl fallback if there is no webgl in environment). Set `null` to force nogl rendering.
- `width` the width of a gl context, if undefined
- `height` the height of a gl context, if undefined
- other [webgl-context](https://www.npmjs.com/package/webgl-context) options such as `alpha` and `premultipliedAlpha`

The draw function has the following signature:

Expand All @@ -72,4 +63,4 @@ The return value is the gl_FragColor RGBA of the canvas, in floats, such as `[0.

## License

MIT, see [LICENSE.md](http://github.com/Jam3/gl-shader-output/blob/master/LICENSE.md) for details.
MIT, see [LICENSE.md](http://github.com/Jam3/gl-shader-output/blob/master/LICENSE.md) for details.
170 changes: 136 additions & 34 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,41 +1,143 @@
var create = require('webgl-context')
var getPixels = require('canvas-pixels').get3d
var triangle = require('a-big-triangle')
var xtend = require('xtend')
var assign = require('xtend/mutable')

module.exports = function(opt) {
opt = xtend({
width: 1,
/**
* @module gl-shader-output
*/

var create = require('webgl-context');
var getPixels = require('canvas-pixels').get3d;
var xtend = require('xtend');
var assign = require('xtend/mutable');
var noGl = require('./nogl');
var Shader = require('gl-shader');
var glExt = require('webglew');
var Framebuffer = require('gl-fbo');


module.exports = function (shader, opt) {
//resolve incomplete args
if (!opt) {
//just options
if (typeof shader === 'object' && !shader.fragShader) {
opt = shader;
}
//just a shader object
else {
opt = {
shader: shader
};
}
}
else {
opt.shader = shader;
}

//take over passed shader object opts
if (opt.shader && opt.shader.fragShader) {
if (opt.gl === undefined) opt.gl = opt.shader.gl;
}

//extend default options
opt = xtend({
width: 1,
height: 1,
preserveDrawingBuffer: true
}, opt)

var gl = opt.gl || create(opt)
if (!opt.shader)
throw new Error('no shader supplied to gl-shader-output')

var shader = typeof opt.shader === 'function'
? opt.shader(gl)
: opt.shader

function process(uniforms) {
gl.clearColor(0, 0, 0, 0)
gl.clear(gl.COLOR_BUFFER_BIT)

shader.bind()
preserveDrawingBuffer: true,
shader: ''
}, opt);

//redefine shader
shader = opt.shader;

//try to obtain veritable gl
var gl = opt.gl === undefined ? create(opt) : opt.gl;

//if gl is null - use noGL version of renderer
if (!gl) return noGl(shader, opt);


//check WebGL extensions to support floats
var glExtensions = glExt(gl);
if ( !glExtensions.OES_texture_float ){
console.warn("Available webgl does not support OES_texture_float extension. Using noGL instead.");
return noGL(shader, opt);
}
if ( !glExtensions.OES_texture_float_linear ) {
console.warn("Available webgl does not support OES_texture_float_linear extension. Using noGL instead.");
return noGL(shader, opt);
}


//ensure shader is created
if (!shader) {
throw new Error('No shader supplied to gl-shader-output');
}
else if (typeof shader === 'function') {
shader = shader(gl);
}

//create gl-shader, if only fragment shader is passed
if (typeof shader === 'string') {
shader = Shader(gl, '\
attribute vec2 position;\
void main() {\
gl_Position = vec4(position, 1.0, 1.0);\
}\
' , shader);
}


//set gl context dims
gl.canvas.width = opt.width;
gl.canvas.height = opt.height;

//as far we process 2d rect
gl.disable(gl.DEPTH_TEST);
gl.disable(gl.BLEND);
gl.disable(gl.CULL_FACE);
gl.disable(gl.DITHER);
gl.disable(gl.POLYGON_OFFSET_FILL);
// gl.disable(gl.SAMPLE_ALPHA_COVERAGE);
// gl.disable(gl.SAMPLE_COVERAGE);
// gl.disable(gl.SCISSOR_TEST);
// gl.disable(gl.STENCIL_TEST);


//create rendering data
var buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1, -1, -1, 3, 3, -1]), gl.STATIC_DRAW);
shader.attributes.position.pointer();

//set framebuffer as a main target
var framebuffer = new Framebuffer(gl, [opt.width, opt.height], {
preferFloat: true,
// float: true,
depth: false,
color: 1
});
framebuffer.bind();

shader.bind();


function process (uniforms) {
var w = gl.drawingBufferWidth, h = gl.drawingBufferHeight;

gl.clearColor(0, 0, 0, 0);
gl.clear(gl.COLOR_BUFFER_BIT);

//if user specifies some uniforms
if (uniforms)
assign(shader.uniforms, uniforms)
if (uniforms) {
shader.bind();
assign(shader.uniforms, uniforms);
}

//full-screen quad
triangle(gl)
gl.drawArrays(gl.TRIANGLES, 0, 3);

var pixels = Array.prototype.slice.call(getPixels(gl))
return pixels.map(function(p) {
return p / 255
})
var result = new Float32Array(w * h * 4);
gl.readPixels(0, 0, w, h, gl.RGBA, gl.FLOAT, result);

return result;
}
return process
}

return process;
};
54 changes: 54 additions & 0 deletions nogl.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/**
* Nogl implementation
*
* @module gl-shader-output/nogl
*/
var GLSL = require('glsl-js');


function create (shader, options) {
//reset gl-shader object
if (shader && shader.fragShader) {
shader = shader._fref.src;
};

var width = options.width, height = options.height;

var compiler = new GLSL({
replaceUniform: shaderVar,
replaceAttribute: shaderVar,
replaceVarying: shaderVar
});

function shaderVar (name) {
return `__data.${name}`;
};

var source = compiler.compile(shader);

var process = new Function('__data', `
${source}

var result = [], gl_FragColor = [0, 0, 0, 0], gl_FragCoord = [0, 0, 0, 0];

for (var j = 0; j < ${height}; j++) {
for (var i = 0; i < ${width}; i++) {
main();
result.push(gl_FragColor[0]);
result.push(gl_FragColor[1]);
result.push(gl_FragColor[2]);
result.push(gl_FragColor[3]);
}
}

return result;
`);

function draw (uniforms) {
return process(uniforms);
}

return draw;
};

module.exports = create;
26 changes: 18 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,31 +1,41 @@
{
"name": "gl-shader-output",
"version": "1.0.2",
"description": "test a shader's gl_FragColor output on a 1x1 canvas",
"description": "Process fragment shader on an rectangular canvas",
"main": "index.js",
"license": "MIT",
"author": {
"name": "Matt DesLauriers",
"email": "[email protected]",
"url": "https://github.com/mattdesl"
},
"contributors": [
"Dmitry Ivanov <[email protected]>"
],
"dependencies": {
"a-big-triangle": "^1.0.0",
"canvas-pixels": "0.0.0",
"gl-fbo": "^2.0.5",
"gl-shader": "^4.2.0",
"glsl-js": "^2.1.1",
"webgl-context": "^2.1.1",
"webglew": "^1.0.5",
"xtend": "^4.0.0"
},
"devDependencies": {
"array-almost-equal": "^1.0.0",
"faucet": "0.0.1",
"glslify": "^1.6.0",
"glslify": "^2.0.0",
"smokestack": "^3.2.0",
"tap-closer": "^1.0.0",
"tape": "^3.4.0",
"test-fuzzy-array": "^1.0.1",
"wzrd": "^1.2.1"
"tst": "^1.3.1"
},
"browserify": {
"transform": [
"glslify"
]
},
"scripts": {
"dev": "wzrd test/test.js -- -t glslify",
"test:browser": "budo test/test.js",
"test:node": "node test/test.js",
"test": "browserify test/test.js -t glslify | tap-closer | smokestack | faucet"
},
"keywords": [
Expand Down
Loading