// state object//
var setVertexAttribArrays = require( './setVertexAttribArrays' );
/**
* Helper class to work with WebGL VertexArrayObjects (vaos)
* Only works if WebGL extensions are enabled (they usually are)
*
* @class
* @memberof PIXI.glCore
* @param gl {WebGLRenderingContext} The current WebGL rendering context
*/
function VertexArrayObject(gl, state)
{
this.nativeVaoExtension = null;
if(!VertexArrayObject.FORCE_NATIVE)
{
this.nativeVaoExtension = gl.getExtension('OES_vertex_array_object') ||
gl.getExtension('MOZ_OES_vertex_array_object') ||
gl.getExtension('WEBKIT_OES_vertex_array_object');
}
this.nativeState = state;
if(this.nativeVaoExtension)
{
this.nativeVao = this.nativeVaoExtension.createVertexArrayOES();
var maxAttribs = gl.getParameter(gl.MAX_VERTEX_ATTRIBS);
// VAO - overwrite the state..
this.nativeState = {
tempAttribState: new Array(maxAttribs),
attribState: new Array(maxAttribs)
};
}
/**
* The current WebGL rendering context
*
* @member {WebGLRenderingContext}
*/
this.gl = gl;
/**
* An array of attributes
*
* @member {Array}
*/
this.attributes = [];
/**
* @member {PIXI.glCore.GLBuffer}
*/
this.indexBuffer = null;
/**
* A boolean flag
*
* @member {Boolean}
*/
this.dirty = false;
}
VertexArrayObject.prototype.constructor = VertexArrayObject;
module.exports = VertexArrayObject;
/**
* Some devices behave a bit funny when using the newer extensions (im looking at you ipad 2!)
* If you find on older devices that things have gone a bit weird then set this to true.
*/
/**
* Lets the VAO know if you should use the WebGL extension or the native methods.
* Some devices behave a bit funny when using the newer extensions (im looking at you ipad 2!)
* If you find on older devices that things have gone a bit weird then set this to true.
* @static
* @property {Boolean} FORCE_NATIVE
*/
VertexArrayObject.FORCE_NATIVE = false;
/**
* Binds the buffer
*/
VertexArrayObject.prototype.bind = function()
{
if(this.nativeVao)
{
this.nativeVaoExtension.bindVertexArrayOES(this.nativeVao);
if(this.dirty)
{
this.dirty = false;
this.activate();
return this;
}
if (this.indexBuffer)
{
this.indexBuffer.bind();
}
}
else
{
this.activate();
}
return this;
};
/**
* Unbinds the buffer
*/
VertexArrayObject.prototype.unbind = function()
{
if(this.nativeVao)
{
this.nativeVaoExtension.bindVertexArrayOES(null);
}
return this;
};
/**
* Uses this vao
*/
VertexArrayObject.prototype.activate = function()
{
var gl = this.gl;
var lastBuffer = null;
for (var i = 0; i < this.attributes.length; i++)
{
var attrib = this.attributes[i];
if(lastBuffer !== attrib.buffer)
{
attrib.buffer.bind();
lastBuffer = attrib.buffer;
}
gl.vertexAttribPointer(attrib.attribute.location,
attrib.attribute.size,
attrib.type || gl.FLOAT,
attrib.normalized || false,
attrib.stride || 0,
attrib.start || 0);
}
setVertexAttribArrays(gl, this.attributes, this.nativeState);
if(this.indexBuffer)
{
this.indexBuffer.bind();
}
return this;
};
/**
*
* @param buffer {PIXI.gl.GLBuffer}
* @param attribute {*}
* @param type {String}
* @param normalized {Boolean}
* @param stride {Number}
* @param start {Number}
*/
VertexArrayObject.prototype.addAttribute = function(buffer, attribute, type, normalized, stride, start)
{
this.attributes.push({
buffer: buffer,
attribute: attribute,
location: attribute.location,
type: type || this.gl.FLOAT,
normalized: normalized || false,
stride: stride || 0,
start: start || 0
});
this.dirty = true;
return this;
};
/**
*
* @param buffer {PIXI.gl.GLBuffer}
*/
VertexArrayObject.prototype.addIndex = function(buffer/*, options*/)
{
this.indexBuffer = buffer;
this.dirty = true;
return this;
};
/**
* Unbinds this vao and disables it
*/
VertexArrayObject.prototype.clear = function()
{
// var gl = this.gl;
// TODO - should this function unbind after clear?
// for now, no but lets see what happens in the real world!
if(this.nativeVao)
{
this.nativeVaoExtension.bindVertexArrayOES(this.nativeVao);
}
this.attributes.length = 0;
this.indexBuffer = null;
return this;
};
/**
* @param type {Number}
* @param size {Number}
* @param start {Number}
*/
VertexArrayObject.prototype.draw = function(type, size, start)
{
var gl = this.gl;
if(this.indexBuffer)
{
gl.drawElements(type, size || this.indexBuffer.data.length, gl.UNSIGNED_SHORT, (start || 0) * 2 );
}
else
{
// TODO need a better way to calculate size..
gl.drawArrays(type, start, size || this.getSize());
}
return this;
};
/**
* Destroy this vao
*/
VertexArrayObject.prototype.destroy = function()
{
// lose references
this.gl = null;
this.indexBuffer = null;
this.attributes = null;
this.nativeState = null;
if(this.nativeVao)
{
this.nativeVaoExtension.deleteVertexArrayOES(this.nativeVao);
}
this.nativeVaoExtension = null;
this.nativeVao = null;
};
VertexArrayObject.prototype.getSize = function()
{
var attrib = this.attributes[0];
return attrib.buffer.data.length / (( attrib.stride/4 ) || attrib.attribute.size);
};