Comparing version 0.0.6 to 1.0.0
245
index.js
"use strict" | ||
var glslExports = require("glsl-exports") | ||
var uniq = require("uniq") | ||
var extract = require("glsl-extract") | ||
var createShader = require("gl-shader-core") | ||
var through = require("through") | ||
function Shader(gl, prog, uniforms, attributes) { | ||
this.gl = gl | ||
this.program = prog | ||
this.uniforms = uniforms | ||
this.attributes = attributes | ||
} | ||
module.exports = compileShader | ||
Shader.prototype.bind = function() { | ||
this.gl.useProgram(this.program) | ||
} | ||
function kvPairs(obj) { | ||
return Object.keys(obj).map(function(x) { return [x, obj[x]] }) | ||
} | ||
function makeVectorUniform(gl, prog, location, obj, type, d, name) { | ||
if(d > 1) { | ||
type += "v" | ||
//This is a horrible hack to make streams run synchronously | ||
function getExports(source) { | ||
var exports | ||
var stream = through() | ||
var nextTick = process.nextTick | ||
var stack = [] | ||
process.nextTick = function(f) { | ||
stack.push(f) | ||
} | ||
var setter = new Function("gl", "prog", "v", "gl.uniform" + d + type + "(gl.getUniformLocation(prog,'"+name+"'), v)") | ||
var getter = new Function("gl", "prog", "return gl.getUniform(prog, gl.getUniformLocation(prog,'"+name+"'))") | ||
Object.defineProperty(obj, name, { | ||
set: setter.bind(undefined, gl, prog), | ||
get: getter.bind(undefined, gl, prog), | ||
enumerable: true | ||
}) | ||
} | ||
function makeMatrixUniform(gl, prog, location, obj, d, name) { | ||
var setter = new Function("gl", "prog", "v", "gl.uniformMatrix" + d + "fv(gl.getUniformLocation(prog,'"+name+"'), false, v)") | ||
var getter = new Function("gl", "prog", "return gl.getUniform(prog, gl.getUniformLocation(prog,'"+name+"'))") | ||
Object.defineProperty(obj, name, { | ||
set: setter.bind(undefined, gl, prog), | ||
get: getter.bind(undefined, gl, prog), | ||
enumerable: true | ||
}) | ||
} | ||
function makeVectorAttrib(gl, prog, location, obj, d, name) { | ||
var out = {} | ||
out.pointer = function attribPointer(type, normalized, stride, offset) { | ||
gl.vertexAttribPointer(location, d, type||gl.FLOAT, normalized?gl.TRUE:gl.FALSE, stride||0, offset||0) | ||
} | ||
out.enable = function enableAttrib() { | ||
gl.enableVertexAttribArray(location) | ||
} | ||
out.disable = function disableAttrib() { | ||
gl.disableVertexAttribArray(location) | ||
} | ||
Object.defineProperty(out, "location", { | ||
get: function() { | ||
return location | ||
}, | ||
set: function(v) { | ||
if(v !== location) { | ||
location = v | ||
gl.bindAttribLocation(prog, v, name) | ||
gl.linkProgram(prog) | ||
} | ||
return v | ||
extract(stream)(function onExtractComplete(err, info) { | ||
if(err) { | ||
throw err | ||
} | ||
exports = info | ||
}) | ||
var constFuncArgs = [ "gl", "v" ] | ||
var var_names = [] | ||
for(var i=0; i<d; ++i) { | ||
constFuncArgs.push("x"+i) | ||
var_names.push("x"+i) | ||
} | ||
constFuncArgs.push([ | ||
"if(x0.length === undefined) {", | ||
"return gl.vertexAttrib"+d+"f(v," + var_names.join(",") + ")", | ||
"} else {", | ||
"return gl.vertexAttrib" + d + "fv(v,x0)", | ||
"}" | ||
].join("\n")) | ||
var constFunc = Function.apply(undefined, constFuncArgs) | ||
out.set = function setAttrib(x, y, z, w) { | ||
return constFunc(gl, location, x, y, z, w) | ||
} | ||
Object.defineProperty(obj, name, { | ||
set: function(x) { | ||
out.isArray = false | ||
constFunc(gl, location, x) | ||
return x | ||
}, | ||
get: function() { | ||
return out | ||
}, | ||
enumerable: true | ||
}) | ||
} | ||
function makeShader(gl, vert_source, frag_source) { | ||
var vert_shader = gl.createShader(gl.VERTEX_SHADER) | ||
gl.shaderSource(vert_shader, vert_source) | ||
gl.compileShader(vert_shader) | ||
if(!gl.getShaderParameter(vert_shader, gl.COMPILE_STATUS)) { | ||
throw new Error("Error compiling vertex shader: " + gl.getShaderInfoLog(vert_shader)) | ||
} | ||
var frag_shader = gl.createShader(gl.FRAGMENT_SHADER) | ||
gl.shaderSource(frag_shader, frag_source) | ||
gl.compileShader(frag_shader) | ||
if(!gl.getShaderParameter(frag_shader, gl.COMPILE_STATUS)) { | ||
throw new Error("Error compiling fragment shader: " + gl.getShaderInfoLog(frag_shader)) | ||
} | ||
var program = gl.createProgram() | ||
gl.attachShader(program, frag_shader) | ||
gl.attachShader(program, vert_shader) | ||
gl.linkProgram(program) | ||
if(!gl.getProgramParameter(program, gl.LINK_STATUS)) { | ||
throw new Error("Error linking shader program: " + gl.getProgramInfoLog (program)) | ||
} | ||
var frag_exports = glslExports(frag_source) | ||
var vert_exports = glslExports(vert_source) | ||
//Bind uniforms | ||
var uniforms = uniq( | ||
kvPairs(frag_exports.uniforms) | ||
.concat(kvPairs(vert_exports.uniforms)), | ||
function compare(a,b) { | ||
return a[0] < b[0] ? -1 : (a[0] === b[0] ? 0 : 1) | ||
}) | ||
var uniform_fields = {} | ||
for(var i=0; i<uniforms.length; ++i) { | ||
var u = uniforms[i] | ||
var name = u[0] | ||
var type = u[1] | ||
var x = gl.getUniformLocation(program, name) | ||
if(!x) { | ||
Object.defineProperty(uniform_fields, name, { | ||
get: function() { }, | ||
set: function() { } | ||
}) | ||
continue | ||
stream.end(new Buffer(source, "utf-8")) | ||
for(var i=0; i<stack.length; ++i) { | ||
var f = stack[i] | ||
try { | ||
f() | ||
} catch(e) { | ||
console.error(e) | ||
} | ||
switch(type) { | ||
case "bool": | ||
case "int": | ||
case "sampler2D": | ||
case "samplerCube": | ||
makeVectorUniform(gl, program, x, uniform_fields, "i", 1, name) | ||
break | ||
case "float": | ||
makeVectorUniform(gl, program, x, uniform_fields, "f", 1, name) | ||
break | ||
default: | ||
if(type.indexOf("vec") >= 0) { | ||
var d = type.charCodeAt(type.length-1) - 48 | ||
if(d < 2 || d > 4) { | ||
throw new Error("Invalid data type") | ||
} | ||
switch(type.charAt(0)) { | ||
case "b": | ||
case "i": | ||
makeVectorUniform(gl, program, x, uniform_fields, "i", d, name) | ||
break | ||
case "v": | ||
makeVectorUniform(gl, program, x, uniform_fields, "f", d, name) | ||
break | ||
default: | ||
throw new Error("Unrecognized data type") | ||
} | ||
} else if(type.charAt(0) === "m") { | ||
var d = type.charCodeAt(type.length-1) - 48 | ||
if(d < 2 || d > 4) { | ||
throw new Error("Invalid data type") | ||
} | ||
makeMatrixUniform(gl, program, x, uniform_fields, d, name) | ||
} else { | ||
throw new Error("Invalid data type") | ||
} | ||
break | ||
} | ||
} | ||
//Bind attributes | ||
var attributes = kvPairs(vert_exports.attributes) | ||
var attribute_fields = {} | ||
for(var i=0; i<attributes.length; ++i) { | ||
var u = attributes[i] | ||
var name = u[0] | ||
var type = u[1] | ||
var x = gl.getAttribLocation(program, name) | ||
switch(type) { | ||
case "bool": | ||
case "int": | ||
case "float": | ||
makeVectorAttrib(gl, program, x, attribute_fields, 1, name) | ||
break | ||
default: | ||
if(type.indexOf("vec") >= 0) { | ||
var d = type.charCodeAt(type.length-1) - 48 | ||
if(d < 2 || d > 4) { | ||
throw new Error("Invalid data type") | ||
} | ||
makeVectorAttrib(gl, program, x, attribute_fields, d, name) | ||
} else { | ||
throw new Error("Invalid data type") | ||
} | ||
break | ||
} | ||
} | ||
return new Shader(gl, program, uniform_fields, attribute_fields) | ||
process.nextTick = nextTick | ||
return exports | ||
} | ||
module.exports = makeShader | ||
//Run glsl-extract on the shader source, and compile the result | ||
function compileShader(gl, vertexSource, fragmentSource) { | ||
var vertexExports = getExports(vertexSource) | ||
var fragmentExports = getExports(fragmentSource) | ||
var uniforms = uniq(vertexExports.uniforms.concat(fragmentExports.uniforms)) | ||
var attributes = vertexExports.attributes | ||
return createShader(gl, vertexSource, fragmentSource, uniforms, attributes) | ||
} |
{ | ||
"name": "gl-shader", | ||
"version": "0.0.6", | ||
"version": "1.0.0", | ||
"description": "WebGL shader wrapper", | ||
@@ -11,3 +11,5 @@ "main": "index.js", | ||
"uniq": "~0.0.2", | ||
"glsl-exports": "~0.0.0" | ||
"gl-shader-core": "~0.0.0", | ||
"glsl-extract": "~0.0.2", | ||
"through": "~2.3.4" | ||
}, | ||
@@ -18,3 +20,4 @@ "devDependencies": { | ||
"scripts": { | ||
"test": "echo \"Error: no test specified\" && exit 1" | ||
"test": "echo \"Error: no test specified\" && exit 1", | ||
"start": "beefy --open example/example.js" | ||
}, | ||
@@ -21,0 +24,0 @@ "repository": { |
@@ -5,4 +5,2 @@ gl-shader | ||
**WORK IN PROGRESS** | ||
# Example | ||
@@ -100,3 +98,3 @@ | ||
## Uniforms | ||
The uniforms for the shader program are parsed at compile time using [glsl-exports](https://github.com/mikolalysenko/glsl-exports) and packaged up as properties in the `shader.uniforms` object. For example, to update a scalar uniform you can just assign to it: | ||
The uniforms for the shader program are packaged up as properties in the `shader.uniforms` object. For example, to update a scalar uniform you can just assign to it: | ||
@@ -130,2 +128,8 @@ ```javascript | ||
Struct uniforms can also be accessed using the normal dot property syntax. For example, | ||
```javascript | ||
shader.uniforms.light[0].color = [1, 0, 0, 1] | ||
``` | ||
## Attributes | ||
@@ -166,2 +170,4 @@ | ||
**WARNING** Changing the attribute location requires recompiling the program. Do not dynamically modify this variable in your render loop. | ||
### `attrib.pointer([type, normalized, stride, offset])` | ||
@@ -190,3 +196,11 @@ A shortcut for `gl.vertexAttribPointer`. See the [OpenGL man page for details on how this works](http://www.khronos.org/opengles/sdk/docs/man/xhtml/glVertexAttribPointer.xml). The main difference here is that the WebGL context, size and index are known and so these parameters are bound. | ||
## Reflection | ||
Finally, the library supports some reflection capabilities. The set of all uniforms and data types are stored in the "type" property of the shader object, | ||
```javascript | ||
console.log(shader.types) | ||
``` | ||
## Credits | ||
(c) 2013 Mikola Lysenko. MIT License | ||
(c) 2013 Mikola Lysenko. MIT License |
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
Uses eval
Supply chain riskPackage uses dynamic code execution (e.g., eval()), which is a dangerous practice. This can prevent the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
2
201
1
9392
4
40
+ Addedgl-shader-core@~0.0.0
+ Addedglsl-extract@~0.0.2
+ Addedthrough@~2.3.4
+ Addedcore-util-is@1.0.3(transitive)
+ Addedcssauron@1.4.0(transitive)
+ Addedcssauron-glsl@0.0.0(transitive)
+ Addeddup@0.0.0(transitive)
+ Addedgl-shader-core@0.0.3(transitive)
+ Addedglsl-deparser@0.0.2(transitive)
+ Addedglsl-extract@0.0.2(transitive)
+ Addedglsl-parser@0.0.5(transitive)
+ Addedglsl-tokenizer@0.0.8(transitive)
+ Addedinherits@2.0.4(transitive)
+ Addedisarray@0.0.1(transitive)
+ Addedreadable-stream@1.0.34(transitive)
+ Addedstring_decoder@0.10.31(transitive)
+ Addedutf8-stream@0.0.0(transitive)
- Removedglsl-exports@~0.0.0
- Removedglsl-exports@0.0.0(transitive)
- Removedglsl-parser@0.0.9(transitive)
- Removedglsl-tokenizer@0.0.9(transitive)