import * as core from '../../core';
import glCore from 'pixi-gl-core';
const byteSizeMap = { 5126: 4, 5123: 2, 5121: 1 };
/**
* WebGL renderer plugin for tiling sprites
*
* @class
* @memberof PIXI
* @extends PIXI.ObjectRenderer
*/
export default class MeshRenderer extends core.ObjectRenderer
{
/**
* constructor for renderer
*
* @param {WebGLRenderer} renderer The renderer this tiling awesomeness works for.
*/
constructor(renderer)
{
super(renderer);
this.shader = null;
}
/**
* Sets up the renderer context and necessary buffers.
*
* @private
*/
onContextChange()
{
this.gl = this.renderer.gl;
this.CONTEXT_UID = this.renderer.CONTEXT_UID;
}
/**
* renders mesh
* @private
* @param {PIXI.mesh.RawMesh} mesh mesh instance
*/
render(mesh)
{
// bind the shader..
const glShader = this.renderer.shaderManager.bindShader(mesh.shader, true);
// set the shader props..
if (glShader.uniformData.translationMatrix)
{
// the transform!
glShader.uniforms.translationMatrix = mesh.transform.worldTransform.toArray(true);
}
// set unifomrs..
this.renderer.shaderManager.setUniforms(mesh.shader.uniforms);
// sync uniforms..
this.renderer.state.setState(mesh.state);
// bind the geometry...
this.bindGeometry(mesh.geometry, glShader);
// then render it
mesh.geometry.glVertexArrayObjects[this.CONTEXT_UID].draw(mesh.drawMode, mesh.size, mesh.start);
}
draw(mesh)
{
mesh.geometry.glVertexArrayObjects[this.CONTEXT_UID].draw(mesh.drawMode, mesh.size, mesh.start);
}
/**
* Binds geometry so that is can be drawn. Creating a Vao if required
* @private
* @param {PIXI.mesh.Geometry} geometry instance of geometry to bind
* @param {PIXI.glCore.glShader} glShader shader that the geometry will be renderered with.
*/
bindGeometry(geometry, glShader)
{
const vao = geometry.glVertexArrayObjects[this.CONTEXT_UID] || this.initGeometryVao(geometry, glShader);
this.renderer.bindVao(vao);
// TODO - optimise later!
// don't need to loop through if nothing changed!
// maybe look to add an 'autoupdate' to geometry?
for (let i = 0; i < geometry.buffers.length; i++)
{
const buffer = geometry.buffers[i];
const glBuffer = buffer._glBuffers[this.CONTEXT_UID];
if (buffer._updateID !== glBuffer._updateID)
{
glBuffer._updateID = buffer._updateID;
// TODO - partial upload??
glBuffer.upload(buffer.data, 0);
}
}
}
/**
* Creates a Vao with the same structure as the geometry and stores it on the geometry.
* @private
* @param {PIXI.mesh.Geometry} geometry instance of geometry to to generate Vao for
* @param {PIXI.glCore.glShader} glShader shader that the geometry will be renderered with.
* @return {PIXI.glCore.VertexArrayObject} Returns a fresh vao.
*/
initGeometryVao(geometry, glShader)
{
const gl = this.gl;
this.renderer.bindVao(null);
const vao = this.renderer.createVao();
const buffers = geometry.buffers;
const attributes = geometry.attributes;
// first update - and create the buffers!
for (let i = 0; i < buffers.length; i++)
{
const buffer = buffers[i];
if (!buffer._glBuffers[this.CONTEXT_UID])
{
if (buffer.index)
{
buffer._glBuffers[this.CONTEXT_UID] = glCore.GLBuffer.createIndexBuffer(gl, buffer.data);
}
else
{
buffer._glBuffers[this.CONTEXT_UID] = glCore.GLBuffer.createVertexBuffer(gl, buffer.data, buffer.static ? gl.STATIC_DRAW : gl.DYNAMIC_DRAW );
}
}
}
if (geometry.indexBuffer)
{
// first update the index buffer if we have one..
vao.addIndex(geometry.indexBuffer._glBuffers[this.CONTEXT_UID]);
}
const tempStride = {};
const tempStart = {};
for (const j in buffers)
{
tempStride[j] = 0;
tempStart[j] = 0;
}
for (const j in attributes)
{
tempStride[attributes[j].buffer] += glShader.attributes[j].size * byteSizeMap[attributes[j].type];
}
for (const j in attributes)
{
if (tempStride[attributes[j].buffer] === glShader.attributes[j].size * byteSizeMap[attributes[j].type])
{
tempStride[attributes[j].buffer] = 0;
}
}
// next update the attributes buffer..
for (const j in attributes)
{
const attribute = attributes[j];
const buffer = buffers[attribute.buffer];
const glBuffer = buffer._glBuffers[this.CONTEXT_UID];
// need to know the shader as it means we can be lazy and let pixi do the work for us..
// stride, start, type?
vao.addAttribute(glBuffer,
glShader.attributes[j],
attribute.type || 5126, // (5126 = FLOAT)
attribute.normalized,
tempStride[attribute.buffer],
tempStart[attribute.buffer]);
tempStart[attribute.buffer] += glShader.attributes[j].size * byteSizeMap[attribute.type];
}
geometry.glVertexArrayObjects[this.CONTEXT_UID] = vao;
return vao;
}
}
core.WebGLRenderer.registerPlugin('mesh', MeshRenderer);