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

Simplified updating interface and caching improvements #12

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open
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
71 changes: 46 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,44 +8,68 @@ The core of [gl-shader](https://github.com/mikolalysenko/gl-shader), without the

## API

### `var shader = require("gl-shader-core")(gl, vertexSource, fragmentSource, uniforms, attributes)`
Constructs a packaged gl-shader object with shims for all of the uniforms and attributes in the program.
```javascript
var createShader = require('gl-shader-core')
```

### Constructor

There are two main usages for the constructor. First,

#### `var shader = createShader(vertexSource, fragmentSource[, uniforms, attributes])`

Constructs a wrapped shader object with shims for all of the uniforms and attributes in the program.

* `gl` is the webgl context in which the program will be created
* `vertexSource` is the source code for the vertex shader
* `fragmentSource` is the source code for the fragment shader
* `uniforms` is a list of all uniforms exported by the shader program
* `attributes` is a list of all attributes exported by the shader program
* `uniforms` is an (optional) list of all uniforms exported by the shader program
* `attributes` is an (optional) list of all attributes exported by the shader program

The uniform and attributes variables have output which is consistent with [glsl-extract](https://npmjs.org/package/glsl-extract).
The format of `uniforms` and `attributes` is consistent with `glslify`'s output

**Returns** A compiled shader object.

You can specify a default `location` number for each attribute, otherwise WebGL will bind it automatically.

## Methods
#### `var shader = createShader(gl, glslifyResult)`

Constructs a shader object from the output of `glslify`.

### `shader.bind()`
* `gl` is a WebGL context
* `glslify` is the output of `glslify`

**Returns** A wrapped shader object

### Methods

#### `shader.bind()`
Binds the shader for rendering

### `shader.dispose()`
#### `shader.update(vertSource, fragSource[, uniforms, attributes])`
Rebuilds the shader object with new vertex and fragment shaders (same behavior as constructor)

#### `shader.update(glslifyResult)`
Rebuilds the shader object with new vertex and fragment shaders (same behavior as constructor)

#### `shader.dispose()`
Deletes the shader program and associated resources.

## Properties
### Properties

### `gl`
#### `gl`
The WebGL context associated to the shader

### `handle`
A handle to the underlying WebGL program object
#### `program`
A reference to the underlying program object in the WebGL context

### `vertexShader`
A handle to the underlying WebGL fragment shader object
#### `vertShader`
A reference to the underlying vertex shader object

### `fragmentShader`
A handle to the underlying WebGL vertex shader object
#### `fragShader`
A reference to the underlying fragment shader object

## Uniforms
### Uniforms
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:

```javascript
Expand Down Expand Up @@ -81,11 +105,11 @@ Struct uniforms can also be accessed using the normal dot property syntax. For
shader.uniforms.light[0].color = [1, 0, 0, 1]
```

## Attributes
### Attributes

The basic idea behind the attribute interface is similar to that for uniforms, however because attributes can be either a constant value or get values from a vertex array they have a slightly more complicated interface. All of the attributes are stored in the `shader.attributes` property.

### `attrib = constant`
#### `attrib = constant`
For non-array attributes you can set the constant value to be broadcast across all vertices. For example, to set the vertex color of a shader to a constant you could do:

```javascript
Expand All @@ -107,9 +131,7 @@ Or you can read the currently bound location back by just accessing it:
console.log(attrib.location)
```

Internally, these methods just call [`gl.bindAttribLocation`](http://www.khronos.org/opengles/sdk/docs/man/xhtml/glBindAttribLocation.xml) and access the stored location.

**WARNING** Changing the attribute location requires recompiling the program. Do not dynamically modify this variable in your render loop.
**WARNING** Changing the attribute location requires recompiling the program. This recompilation is deferred until the next call to `.bind()`

### `attrib.pointer([type, normalized, stride, offset])`
A shortcut for `gl.vertexAttribPointer`/`gl.enableVertexAttribArray`. 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.
Expand All @@ -119,7 +141,7 @@ A shortcut for `gl.vertexAttribPointer`/`gl.enableVertexAttribArray`. See the [
* `stride` the byte offset between consecutive generic vertex attributes. (Default: `0`)
* `offset` offset of the first element of the array in bytes. (Default `0`)

## Reflection
### 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,

Expand All @@ -129,6 +151,5 @@ console.log(shader.types)

This reflects the uniform and attribute parameters that were passed to the shader constructor.


## Credits
(c) 2013 Mikola Lysenko. MIT License
(c) 2013-2014 Mikola Lysenko. MIT License
113 changes: 85 additions & 28 deletions lib/create-attributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,57 +2,95 @@

module.exports = createAttributeWrapper

//Shader attribute class
function ShaderAttribute(gl, program, location, dimension, name, constFunc, relink) {
this._gl = gl
this._program = program
this._location = location
function ShaderAttribute(
gl
, wrapper
, index
, locations
, dimension) {
this._gl = gl
this._wrapper = wrapper
this._index = index
this._locations = locations
this._dimension = dimension
this._name = name
this._constFunc = constFunc
this._relink = relink
}

var proto = ShaderAttribute.prototype

proto.pointer = function setAttribPointer(type, normalized, stride, offset) {
var gl = this._gl
gl.vertexAttribPointer(this._location, this._dimension, type||gl.FLOAT, !!normalized, stride||0, offset||0)
this._gl.enableVertexAttribArray(this._location)
proto.pointer = function setAttribPointer(
type
, normalized
, stride
, offset) {

var self = this
var gl = self._gl
var location = self._locations[self._index]

gl.vertexAttribPointer(
location
, self._dimension
, type || gl.FLOAT
, !!normalized
, stride || 0
, offset || 0)

this._gl.enableVertexAttribArray(location)
}

Object.defineProperty(proto, 'location', {
get: function() {
return this._location
return this._locations[this._index]
}
, set: function(v) {
if(v !== this._location) {
this._location = v
this._gl.bindAttribLocation(this._program, v, this._name)
this._gl.linkProgram(this._program)
this._relink()
if(v !== this._locations[this._index]) {
this._locations[this._index] = v
this._wrapper.program = null
}
}
})


//Adds a vector attribute to obj
function addVectorAttribute(gl, program, location, dimension, obj, name, doLink) {
function addVectorAttribute(
gl
, wrapper
, index
, locations
, dimension
, obj
, name) {

//Construct constant function
var constFuncArgs = [ 'gl', 'v' ]
var varNames = []
for(var i=0; i<dimension; ++i) {
constFuncArgs.push('x'+i)
varNames.push('x'+i)
}
constFuncArgs.push([
'if(x0.length===void 0){return gl.vertexAttrib', dimension, 'f(v,', varNames.join(), ')}else{return gl.vertexAttrib', dimension, 'fv(v,x0)}'
'if(x0.length===void 0){return gl.vertexAttrib'
, dimension, 'f(v,'
, varNames.join()
, ')}else{return gl.vertexAttrib'
, dimension
, 'fv(v,x0)}'
].join(''))
var constFunc = Function.apply(undefined, constFuncArgs)
var attr = new ShaderAttribute(gl, program, location, dimension, name, constFunc, doLink)
var constFunc = Function.apply(null, constFuncArgs)

//Create attribute wrapper
var attr = new ShaderAttribute(
gl
, wrapper
, index
, locations
, dimension)

//Create accessor
Object.defineProperty(obj, name, {
set: function(x) {
gl.disableVertexAttribArray(attr._location)
constFunc(gl, attr._location, x)
gl.disableVertexAttribArray(locations[index])
constFunc(gl, locations[index], x)
return x
}
, get: function() {
Expand All @@ -63,19 +101,31 @@ function addVectorAttribute(gl, program, location, dimension, obj, name, doLink)
}

//Create shims for attributes
function createAttributeWrapper(gl, program, attributes, doLink) {
function createAttributeWrapper(
gl
, wrapper
, attributes
, locations) {

var obj = {}
for(var i=0, n=attributes.length; i<n; ++i) {

var a = attributes[i]
var name = a.name
var type = a.type
var location = gl.getAttribLocation(program, name)

switch(type) {
case 'bool':
case 'int':
case 'float':
addVectorAttribute(gl, program, location, 1, obj, name, doLink)
addVectorAttribute(
gl
, wrapper
, i
, locations
, 1
, obj
, name)
break

default:
Expand All @@ -84,7 +134,14 @@ function createAttributeWrapper(gl, program, attributes, doLink) {
if(d < 2 || d > 4) {
throw new Error('gl-shader: Invalid data type for attribute ' + name + ': ' + type)
}
addVectorAttribute(gl, program, location, d, obj, name, doLink)
addVectorAttribute(
gl
, wrapper
, i
, locations
, d
, obj
, name)
} else {
throw new Error('gl-shader: Unknown data type for attribute ' + name + ': ' + type)
}
Expand Down
15 changes: 9 additions & 6 deletions lib/create-uniforms.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,15 @@ function identity(x) {
}

//Create shims for uniforms
function createUniformWrapper(gl, program, uniforms, locations) {
function createUniformWrapper(gl, wrapper, uniforms, locations) {

function makeGetter(index) {
var proc = new Function('gl', 'prog', 'locations',
'return function(){return gl.getUniform(prog,locations[' + index + '])}')
return proc(gl, program, locations)
var proc = new Function(
'gl'
, 'wrapper'
, 'locations'
, 'return function(){return gl.getUniform(wrapper.program,locations[' + index + '])}')
return proc(gl, wrapper, locations)
}

function makePropSetter(path, index, type) {
Expand Down Expand Up @@ -92,8 +95,8 @@ function createUniformWrapper(gl, program, uniforms, locations) {
}
}
code.push('return obj}')
var proc = new Function('gl', 'prog', 'locations', code.join('\n'))
return proc(gl, program, locations)
var proc = new Function('gl', 'locations', code.join('\n'))
return proc(gl, locations)
}

function defaultValue(type) {
Expand Down
Loading