refactored webGL renderer
This commit is contained in:
parent
530d889b0a
commit
d56d6df260
17 changed files with 9388 additions and 7944 deletions
21
Gruntfile.js
21
Gruntfile.js
|
@ -5,6 +5,8 @@ module.exports = function(grunt) {
|
|||
grunt.loadNpmTasks('grunt-contrib-uglify');
|
||||
grunt.loadNpmTasks('grunt-contrib-connect');
|
||||
grunt.loadNpmTasks('grunt-contrib-yuidoc');
|
||||
grunt.loadNpmTasks('grunt-contrib-watch');
|
||||
|
||||
grunt.loadTasks('tasks');
|
||||
|
||||
var srcFiles = [
|
||||
|
@ -33,11 +35,13 @@ module.exports = function(grunt) {
|
|||
'<%= dirs.src %>/renderers/webgl/PixiShader.js',
|
||||
'<%= dirs.src %>/renderers/webgl/StripShader.js',
|
||||
'<%= dirs.src %>/renderers/webgl/PrimitiveShader.js',
|
||||
'<%= dirs.src %>/renderers/webgl/WebGLGraphics.js',
|
||||
'<%= dirs.src %>/renderers/webgl/utils/WebGLGraphics.js',
|
||||
'<%= dirs.src %>/renderers/webgl/WebGLRenderer.js',
|
||||
'<%= dirs.src %>/renderers/webgl/utils/WebGLMaskManager.js',
|
||||
'<%= dirs.src %>/renderers/webgl/utils/WebGLSpriteBatch.js',
|
||||
'<%= dirs.src %>/renderers/webgl/WebGLBatch.js',
|
||||
'<%= dirs.src %>/renderers/webgl/WebGLRenderGroup.js',
|
||||
'<%= dirs.src %>/renderers/webgl/WebGLFilterManager.js',
|
||||
'<%= dirs.src %>/renderers/webgl/utils/WebGLFilterManager.js',
|
||||
'<%= dirs.src %>/renderers/canvas/CanvasRenderer.js',
|
||||
'<%= dirs.src %>/renderers/canvas/CanvasGraphics.js',
|
||||
'<%= dirs.src %>/primitives/Graphics.js',
|
||||
|
@ -168,6 +172,15 @@ module.exports = function(grunt) {
|
|||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
scripts: {
|
||||
files: ['<%= dirs.src %>/**/*.js'],
|
||||
tasks: ['concat'],
|
||||
options: {
|
||||
spawn: false,
|
||||
}
|
||||
}
|
||||
},
|
||||
karma: {
|
||||
unit: {
|
||||
configFile: 'test/karma.conf.js',
|
||||
|
@ -186,4 +199,8 @@ module.exports = function(grunt) {
|
|||
|
||||
grunt.registerTask('docs', ['yuidoc']);
|
||||
grunt.registerTask('travis', ['build', 'test']);
|
||||
|
||||
grunt.registerTask('default', ['build', 'test']);
|
||||
|
||||
grunt.registerTask('debug-watch', ['concat', 'watch']);
|
||||
};
|
||||
|
|
16585
bin/pixi.dev.js
16585
bin/pixi.dev.js
File diff suppressed because it is too large
Load diff
|
@ -48,6 +48,7 @@
|
|||
// just for fun, lets rotate mr rabbit a little
|
||||
bunny.rotation += 0.1;
|
||||
|
||||
// console.log(stage.getBounds().width);
|
||||
// render the stage
|
||||
renderer.render(stage);
|
||||
}
|
||||
|
|
|
@ -70,9 +70,9 @@
|
|||
graphics.drawRect(50, 250, 100, 100);
|
||||
|
||||
// draw a circle
|
||||
graphics.lineStyle(0);
|
||||
graphics.beginFill(0xFFFF0B, 0.5);
|
||||
graphics.drawCircle(470, 200,100);
|
||||
/// graphics.lineStyle(0);
|
||||
// graphics.beginFill(0xFFFF0B, 0.5);
|
||||
// graphics.drawCircle(470, 200,100);
|
||||
|
||||
graphics.lineStyle(20, 0x33FF00);
|
||||
graphics.moveTo(30,30);
|
||||
|
@ -100,7 +100,7 @@
|
|||
|
||||
function animate() {
|
||||
|
||||
thing.clear();
|
||||
/* thing.clear();
|
||||
|
||||
count += 0.1;
|
||||
|
||||
|
@ -114,7 +114,7 @@
|
|||
thing.lineTo(-120 + Math.cos(count)* 20, 100 + Math.sin(count)* 20);
|
||||
thing.lineTo(-120 + Math.sin(count) * 20, -100 + Math.cos(count)* 20);
|
||||
|
||||
thing.rotation = count * 0.1;
|
||||
thing.rotation = count * 0.1;*/
|
||||
renderer.render(stage);
|
||||
requestAnimFrame( animate );
|
||||
}
|
||||
|
|
|
@ -353,7 +353,8 @@ Object.defineProperty(PIXI.DisplayObject.prototype, 'filters', {
|
|||
passes.push(filterPasses[j]);
|
||||
}
|
||||
}
|
||||
|
||||
this._filterBlock = value.start;
|
||||
|
||||
value.start.filterPasses = passes;
|
||||
}
|
||||
else
|
||||
|
@ -580,6 +581,17 @@ PIXI.DisplayObject.prototype.getBounds = function()
|
|||
return PIXI.EmptyRectangle;
|
||||
}
|
||||
|
||||
|
||||
PIXI.DisplayObject.prototype._renderWebGL = function(renderSession)
|
||||
{
|
||||
// OVERWRITE
|
||||
}
|
||||
|
||||
PIXI.DisplayObject.prototype._renderCanvas = function(renderSession)
|
||||
{
|
||||
// OVERWRITE
|
||||
}
|
||||
|
||||
PIXI.EmptyRectangle = new PIXI.Rectangle(0,0,0,0);
|
||||
|
||||
PIXI.visibleCount = 0;
|
|
@ -374,7 +374,7 @@ PIXI.DisplayObjectContainer.prototype.getBounds = function()
|
|||
maxX = maxX > childMaxX ? maxX : childMaxX;
|
||||
maxY = maxY > childMaxY ? maxY : childMaxY;
|
||||
}
|
||||
|
||||
|
||||
var bounds = this._bounds;
|
||||
|
||||
bounds.x = minX;
|
||||
|
@ -385,3 +385,57 @@ PIXI.DisplayObjectContainer.prototype.getBounds = function()
|
|||
return bounds;
|
||||
}
|
||||
|
||||
|
||||
PIXI.DisplayObjectContainer.prototype._renderWebGL = function(renderSession)
|
||||
{
|
||||
if(this.visible === false || this.alpha === 0)return;
|
||||
|
||||
if(this.mask || this.filters)
|
||||
{
|
||||
if(this.mask)
|
||||
{
|
||||
renderSession.spriteBatch.stop();
|
||||
renderSession.maskManager.pushMask(this.mask, renderSession.projection);
|
||||
renderSession.spriteBatch.start();
|
||||
}
|
||||
|
||||
if(this.filters)
|
||||
{
|
||||
renderSession.spriteBatch.flush();
|
||||
renderSession.filterManager.pushFilter(this._filterBlock);
|
||||
}
|
||||
|
||||
// simple render children!
|
||||
for(var i=0,j=this.children.length; i<j; i++)
|
||||
{
|
||||
var child = this.children[i];
|
||||
child._renderWebGL(renderSession);
|
||||
}
|
||||
|
||||
renderSession.spriteBatch.stop();
|
||||
|
||||
if(this.filters)renderSession.filterManager.popFilter();
|
||||
if(this.mask)renderSession.maskManager.popMask(renderSession.projection);
|
||||
|
||||
renderSession.spriteBatch.start();
|
||||
}
|
||||
else
|
||||
{
|
||||
// simple render children!
|
||||
for(var i=0,j=this.children.length; i<j; i++)
|
||||
{
|
||||
var child = this.children[i];
|
||||
child._renderWebGL(renderSession);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PIXI.DisplayObjectContainer.prototype._renderCanvas = function(renderSession)
|
||||
{
|
||||
// OVERWRITE
|
||||
for(var i=0,j=this.children.length; i<j; i++)
|
||||
{
|
||||
var child = this.children[i];
|
||||
child._renderCanvas(renderSession);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -151,8 +151,6 @@ PIXI.Sprite.prototype.setTexture = function(texture)
|
|||
*/
|
||||
PIXI.Sprite.prototype.onTextureUpdate = function()
|
||||
{
|
||||
//this.texture.removeEventListener( 'update', this.onTextureUpdateBind );
|
||||
|
||||
// so if _width is 0 then width was not set..
|
||||
if(this._width)this.scale.x = this._width / this.texture.frame.width;
|
||||
if(this._height)this.scale.y = this._height / this.texture.frame.height;
|
||||
|
@ -229,6 +227,68 @@ PIXI.Sprite.prototype.getBounds = function()
|
|||
return bounds;
|
||||
}
|
||||
|
||||
|
||||
PIXI.Sprite.prototype._renderWebGL = function(renderSession)
|
||||
{
|
||||
if(this.visible === false || this.alpha === 0)return;
|
||||
|
||||
if(this.mask || this.filters)
|
||||
{
|
||||
if(this.mask)
|
||||
{
|
||||
renderSession.spriteBatch.stop();
|
||||
renderSession.maskManager.pushMask(this.mask, renderSession.projection);
|
||||
renderSession.spriteBatch.start();
|
||||
}
|
||||
|
||||
if(this.filters)
|
||||
{
|
||||
renderSession.spriteBatch.flush();
|
||||
renderSession.filterManager.pushFilter(this._filterBlock);
|
||||
}
|
||||
|
||||
renderSession.spriteBatch.render(this);
|
||||
|
||||
// simple render children!
|
||||
for(var i=0,j=this.children.length; i<j; i++)
|
||||
{
|
||||
var child = this.children[i];
|
||||
child._renderWebGL(renderSession);
|
||||
}
|
||||
|
||||
renderSession.spriteBatch.stop();
|
||||
|
||||
if(this.filters)renderSession.filterManager.popFilter();
|
||||
if(this.mask)renderSession.maskManager.popMask(renderSession.projection);
|
||||
|
||||
renderSession.spriteBatch.start();
|
||||
}
|
||||
else
|
||||
{
|
||||
renderSession.spriteBatch.render(this);
|
||||
|
||||
// simple render children!
|
||||
for(var i=0,j=this.children.length; i<j; i++)
|
||||
{
|
||||
var child = this.children[i];
|
||||
child._renderWebGL(renderSession);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//TODO check culling
|
||||
}
|
||||
|
||||
PIXI.Sprite.prototype._renderCanvas = function(renderSession)
|
||||
{
|
||||
// OVERWRITE
|
||||
for(var i=0,j=this.children.length; i<j; i++)
|
||||
{
|
||||
var child = this.children[i];
|
||||
child._renderCanvas(renderSession);
|
||||
}
|
||||
}
|
||||
|
||||
// some helper functions..
|
||||
|
||||
/**
|
||||
|
|
|
@ -102,7 +102,6 @@ PIXI.Stage.prototype.updateTransform = function()
|
|||
this.interactionManager.dirty = true;
|
||||
}
|
||||
|
||||
|
||||
if(this.interactive)this.interactionManager.update();
|
||||
};
|
||||
|
||||
|
|
|
@ -14,32 +14,13 @@
|
|||
*/
|
||||
PIXI.TilingSprite = function(texture, width, height)
|
||||
{
|
||||
PIXI.DisplayObjectContainer.call( this );
|
||||
PIXI.Sprite.call( this, texture);
|
||||
|
||||
/**
|
||||
* The texture that the sprite is using
|
||||
*
|
||||
* @property texture
|
||||
* @type Texture
|
||||
*/
|
||||
this.texture = texture;
|
||||
|
||||
/**
|
||||
* The width of the tiling sprite
|
||||
*
|
||||
* @property width
|
||||
* @type Number
|
||||
*/
|
||||
this.width = width;
|
||||
|
||||
/**
|
||||
* The height of the tiling sprite
|
||||
*
|
||||
* @property height
|
||||
* @type Number
|
||||
*/
|
||||
this.height = height;
|
||||
this.width = width || 100;
|
||||
this.height = height || 100;
|
||||
|
||||
texture.baseTexture._powerOf2 = true;
|
||||
|
||||
/**
|
||||
* The scaling of the image that is being tiled
|
||||
*
|
||||
|
@ -62,33 +43,90 @@ PIXI.TilingSprite = function(texture, width, height)
|
|||
};
|
||||
|
||||
// constructor
|
||||
PIXI.TilingSprite.prototype = Object.create( PIXI.DisplayObjectContainer.prototype );
|
||||
PIXI.TilingSprite.prototype = Object.create( PIXI.Sprite.prototype );
|
||||
PIXI.TilingSprite.prototype.constructor = PIXI.TilingSprite;
|
||||
|
||||
/**
|
||||
* Sets the texture of the tiling sprite
|
||||
*
|
||||
* @method setTexture
|
||||
* @param texture {Texture} The PIXI texture that is displayed by the sprite
|
||||
*/
|
||||
PIXI.TilingSprite.prototype.setTexture = function(texture)
|
||||
{
|
||||
//TODO SET THE TEXTURES
|
||||
//TODO VISIBILITY
|
||||
|
||||
// stop current texture
|
||||
this.texture = texture;
|
||||
this.updateFrame = true;
|
||||
};
|
||||
|
||||
/**
|
||||
* When the texture is updated, this event will fire to update the frame
|
||||
* The width of the sprite, setting this will actually modify the scale to acheive the value set
|
||||
*
|
||||
* @method onTextureUpdate
|
||||
* @param event
|
||||
* @private
|
||||
* @property width
|
||||
* @type Number
|
||||
*/
|
||||
PIXI.TilingSprite.prototype.onTextureUpdate = function()
|
||||
Object.defineProperty(PIXI.TilingSprite.prototype, 'width', {
|
||||
get: function() {
|
||||
return this._width
|
||||
},
|
||||
set: function(value) {
|
||||
|
||||
this._width = value;
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* The height of the TilingSprite, setting this will actually modify the scale to acheive the value set
|
||||
*
|
||||
* @property height
|
||||
* @type Number
|
||||
*/
|
||||
Object.defineProperty(PIXI.TilingSprite.prototype, 'height', {
|
||||
get: function() {
|
||||
return this._height
|
||||
},
|
||||
set: function(value) {
|
||||
this._height = value;
|
||||
}
|
||||
});
|
||||
|
||||
PIXI.TilingSprite.prototype._renderWebGL = function(renderSession)
|
||||
{
|
||||
this.updateFrame = true;
|
||||
};
|
||||
if(this.visible === false || this.alpha === 0)return;
|
||||
|
||||
if(this.mask || this.filters)
|
||||
{
|
||||
if(this.mask)
|
||||
{
|
||||
renderSession.spriteBatch.stop();
|
||||
renderSession.maskManager.pushMask(this.mask, renderSession.projection);
|
||||
renderSession.spriteBatch.start();
|
||||
}
|
||||
|
||||
if(this.filters)
|
||||
{
|
||||
renderSession.spriteBatch.flush();
|
||||
renderSession.filterManager.pushFilter(this._filterBlock);
|
||||
}
|
||||
|
||||
renderSession.spriteBatch.renderTilingSprite(this);
|
||||
|
||||
// simple render children!
|
||||
for(var i=0,j=this.children.length; i<j; i++)
|
||||
{
|
||||
var child = this.children[i];
|
||||
child._renderWebGL(renderSession);
|
||||
}
|
||||
|
||||
renderSession.spriteBatch.stop();
|
||||
|
||||
if(this.filters)renderSession.filterManager.popFilter();
|
||||
if(this.mask)renderSession.maskManager.popMask(renderSession.projection);
|
||||
|
||||
renderSession.spriteBatch.start();
|
||||
}
|
||||
else
|
||||
{
|
||||
renderSession.spriteBatch.renderTilingSprite(this);
|
||||
|
||||
// simple render children!
|
||||
for(var i=0,j=this.children.length; i<j; i++)
|
||||
{
|
||||
var child = this.children[i];
|
||||
child._renderWebGL(renderSession);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PIXI.TilingSprite.prototype._renderCanvas = function(renderSession)
|
||||
{
|
||||
|
||||
}
|
||||
|
|
|
@ -130,6 +130,7 @@ PIXI.Graphics.prototype.lineTo = function(x, y)
|
|||
*/
|
||||
PIXI.Graphics.prototype.beginFill = function(color, alpha)
|
||||
{
|
||||
|
||||
this.filling = true;
|
||||
this.fillColor = color || 0;
|
||||
this.fillAlpha = (arguments.length < 2) ? 1 : alpha;
|
||||
|
@ -177,6 +178,7 @@ PIXI.Graphics.prototype.drawRect = function( x, y, width, height )
|
|||
*/
|
||||
PIXI.Graphics.prototype.drawCircle = function( x, y, radius)
|
||||
{
|
||||
|
||||
if (!this.currentPath.points.length) this.graphicsData.pop();
|
||||
|
||||
this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha,
|
||||
|
@ -198,6 +200,7 @@ PIXI.Graphics.prototype.drawCircle = function( x, y, radius)
|
|||
*/
|
||||
PIXI.Graphics.prototype.drawEllipse = function( x, y, width, height)
|
||||
{
|
||||
|
||||
if (!this.currentPath.points.length) this.graphicsData.pop();
|
||||
|
||||
this.currentPath = {lineWidth:this.lineWidth, lineColor:this.lineColor, lineAlpha:this.lineAlpha,
|
||||
|
@ -226,6 +229,20 @@ PIXI.Graphics.prototype.clear = function()
|
|||
};
|
||||
|
||||
|
||||
PIXI.Graphics.prototype._renderWebGL = function(renderSession)
|
||||
{
|
||||
renderSession.spriteBatch.stop();
|
||||
|
||||
PIXI.WebGLGraphics.renderGraphics(this, renderSession.projection);
|
||||
|
||||
renderSession.spriteBatch.start();
|
||||
}
|
||||
|
||||
PIXI.DisplayObject.prototype._renderCanvas = function(renderSession)
|
||||
{
|
||||
// OVERWRITE
|
||||
}
|
||||
|
||||
PIXI.Graphics.prototype.getBounds = function()
|
||||
{
|
||||
if(!this.bounds)this.updateBounds();
|
||||
|
|
|
@ -8,6 +8,8 @@ PIXI._defaultFrame = new PIXI.Rectangle(0,0,1,1);
|
|||
// only one at the moment :/
|
||||
PIXI.gl = null;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* the WebGLRenderer is draws the stage and all its content onto a webGL enabled canvas. This renderer
|
||||
* should be used for browsers support webGL. This Render works by automatically managing webGLBatchs.
|
||||
|
@ -96,6 +98,15 @@ PIXI.WebGLRenderer = function(width, height, view, transparent, antialias)
|
|||
|
||||
this.stageRenderGroup = new PIXI.WebGLRenderGroup(this.gl, this.transparent);
|
||||
// this.stageRenderGroup. = this.transparent
|
||||
|
||||
this.spriteBatch = new PIXI.WebGLSpriteBatch(gl)//this.gl, PIXI.WebGLRenderer.batchSize);
|
||||
this.maskManager = new PIXI.WebGLMaskManager(gl);
|
||||
this.filterManager = new PIXI.WebGLFilterManager(this.transparent);
|
||||
|
||||
this.renderSession = {};
|
||||
this.renderSession.maskManager = this.maskManager;
|
||||
this.renderSession.filterManager = this.filterManager;
|
||||
this.renderSession.spriteBatch = this.spriteBatch;
|
||||
};
|
||||
|
||||
// constructor
|
||||
|
@ -158,6 +169,22 @@ PIXI.WebGLRenderer.prototype.render = function(stage)
|
|||
// update any textures
|
||||
PIXI.WebGLRenderer.updateTextures();
|
||||
|
||||
// after rendering lets confirm all frames that have been uodated..
|
||||
if(PIXI.Texture.frameUpdates.length > 0)
|
||||
{
|
||||
for (var i=0; i < PIXI.Texture.frameUpdates.length; i++)
|
||||
{
|
||||
var texture = PIXI.Texture.frameUpdates[i];
|
||||
texture.updateFrame = false;
|
||||
|
||||
// now set the uvs. Figured that the uv data sits with a texture rather than a sprite.
|
||||
// so uv data is stored on the texture itself
|
||||
texture._updateWebGLuvs();
|
||||
}
|
||||
|
||||
PIXI.Texture.frameUpdates = [];
|
||||
}
|
||||
|
||||
// update the scene graph
|
||||
PIXI.visibleCount++;
|
||||
stage.updateTransform();
|
||||
|
@ -180,7 +207,21 @@ PIXI.WebGLRenderer.prototype.render = function(stage)
|
|||
PIXI.projection.x = this.width/2;
|
||||
PIXI.projection.y = -this.height/2;
|
||||
|
||||
this.stageRenderGroup.render(PIXI.projection);
|
||||
// reset the render session data..
|
||||
this.renderSession.drawCount = 0;
|
||||
this.renderSession.projection = PIXI.projection;
|
||||
//console.log(this.renderSession)
|
||||
// start using the sprite batch
|
||||
this.spriteBatch.begin(this.renderSession);
|
||||
|
||||
this.filterManager.begin(PIXI.projection, null);
|
||||
|
||||
stage._renderWebGL(this.renderSession);
|
||||
this.spriteBatch.end();
|
||||
|
||||
// this.stage.render();
|
||||
|
||||
// this.stageRenderGroup.render(PIXI.projection);
|
||||
|
||||
// interaction
|
||||
// run interaction!
|
||||
|
@ -194,16 +235,7 @@ PIXI.WebGLRenderer.prototype.render = function(stage)
|
|||
}
|
||||
}
|
||||
|
||||
// after rendering lets confirm all frames that have been uodated..
|
||||
if(PIXI.Texture.frameUpdates.length > 0)
|
||||
{
|
||||
for (var i=0; i < PIXI.Texture.frameUpdates.length; i++)
|
||||
{
|
||||
PIXI.Texture.frameUpdates[i].updateFrame = false;
|
||||
}
|
||||
|
||||
PIXI.Texture.frameUpdates = [];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -110,7 +110,7 @@ PIXI.WebGLGraphics.updateGraphics = function(graphics)
|
|||
{
|
||||
PIXI.WebGLGraphics.buildRectangle(data, graphics._webGL);
|
||||
}
|
||||
else if(data.type === PIXI.Graphics.CIRC || data.type === PIXI.Graphics.ELIP);
|
||||
else if(data.type === PIXI.Graphics.CIRC || data.type === PIXI.Graphics.ELIP)
|
||||
{
|
||||
PIXI.WebGLGraphics.buildCircle(data, graphics._webGL);
|
||||
}
|
58
src/pixi/renderers/webgl/utils/WebGLMaskManager.js
Normal file
58
src/pixi/renderers/webgl/utils/WebGLMaskManager.js
Normal file
|
@ -0,0 +1,58 @@
|
|||
/**
|
||||
* @author Matt DesLauriers <mattdesl> https://github.com/mattdesl/
|
||||
*
|
||||
* Heavily inspired by LibGDX's WebGLMaskManager:
|
||||
* https://github.com/libgdx/libgdx/blob/master/gdx/src/com/badlogic/gdx/graphics/g2d/WebGLMaskManager.java
|
||||
*/
|
||||
|
||||
PIXI.WebGLMaskManager = function(gl)
|
||||
{
|
||||
this.gl = gl;
|
||||
this.maskStack = [];
|
||||
this.maskPosition = 0;
|
||||
}
|
||||
|
||||
PIXI.WebGLMaskManager.prototype.pushMask = function(maskData, projection)
|
||||
{
|
||||
var gl = this.gl;
|
||||
|
||||
if(this.maskStack.length === 0)
|
||||
{
|
||||
gl.enable(gl.STENCIL_TEST);
|
||||
gl.stencilFunc(gl.ALWAYS,1,1);
|
||||
}
|
||||
|
||||
this.maskStack.push(maskData);
|
||||
|
||||
gl.colorMask(false, false, false, false);
|
||||
gl.stencilOp(gl.KEEP,gl.KEEP,gl.INCR);
|
||||
|
||||
PIXI.WebGLGraphics.renderGraphics(maskData, projection);
|
||||
|
||||
gl.colorMask(true, true, true, true);
|
||||
gl.stencilFunc(gl.NOTEQUAL,0, this.maskStack.length);
|
||||
gl.stencilOp(gl.KEEP,gl.KEEP,gl.KEEP);
|
||||
}
|
||||
|
||||
PIXI.WebGLMaskManager.prototype.popMask = function(projection)
|
||||
{
|
||||
var gl = this.gl;
|
||||
|
||||
var maskData = this.maskStack.pop();
|
||||
|
||||
if(maskData)
|
||||
{
|
||||
gl.colorMask(false, false, false, false);
|
||||
|
||||
//gl.stencilFunc(gl.ALWAYS,1,1);
|
||||
gl.stencilOp(gl.KEEP,gl.KEEP,gl.DECR);
|
||||
|
||||
PIXI.WebGLGraphics.renderGraphics(maskData, projection);
|
||||
|
||||
gl.colorMask(true, true, true, true);
|
||||
gl.stencilFunc(gl.NOTEQUAL,0,this.maskStack.length);
|
||||
gl.stencilOp(gl.KEEP,gl.KEEP,gl.KEEP);
|
||||
}
|
||||
|
||||
if(this.maskStack.length === 0)gl.disable(gl.STENCIL_TEST);
|
||||
}
|
261
src/pixi/renderers/webgl/utils/WebGLSpriteBatch.js
Normal file
261
src/pixi/renderers/webgl/utils/WebGLSpriteBatch.js
Normal file
|
@ -0,0 +1,261 @@
|
|||
/**
|
||||
* @author Matt DesLauriers <mattdesl> https://github.com/mattdesl/
|
||||
*
|
||||
* Heavily inspired by LibGDX's WebGLSpriteBatch:
|
||||
* https://github.com/libgdx/libgdx/blob/master/gdx/src/com/badlogic/gdx/graphics/g2d/WebGLSpriteBatch.java
|
||||
*/
|
||||
|
||||
PIXI.WebGLSpriteBatch = function(gl)
|
||||
{
|
||||
this.gl = gl;
|
||||
|
||||
// create a couple of buffers
|
||||
this.vertexBuffer = gl.createBuffer();
|
||||
this.indexBuffer = gl.createBuffer();
|
||||
|
||||
|
||||
this.size = 2000;
|
||||
// 65535 is max index, so 65535 / 6 = 10922.
|
||||
|
||||
//the total number of floats in our batch
|
||||
var numVerts = this.size * 4 * 5;
|
||||
//the total number of indices in our batch
|
||||
var numIndices = this.size * 6;
|
||||
|
||||
//TODO: use properties here
|
||||
//current blend mode.. changing it flushes the batch
|
||||
this.blendMode = PIXI.blendModes.NORMAL;
|
||||
|
||||
//vertex data
|
||||
this.vertices = new Float32Array(numVerts);
|
||||
//index data
|
||||
this.indices = new Uint16Array(numIndices);
|
||||
|
||||
this.lastIndexCount = 0;
|
||||
|
||||
for (var i=0, j=0; i < numIndices; i += 6, j += 4)
|
||||
{
|
||||
this.indices[i + 0] = j + 0;
|
||||
this.indices[i + 1] = j + 1;
|
||||
this.indices[i + 2] = j + 2;
|
||||
this.indices[i + 3] = j + 0;
|
||||
this.indices[i + 4] = j + 2;
|
||||
this.indices[i + 5] = j + 3;
|
||||
};
|
||||
|
||||
//upload the index data
|
||||
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);
|
||||
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this.indices, gl.STATIC_DRAW);
|
||||
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
|
||||
gl.bufferData(gl.ARRAY_BUFFER, this.vertices, gl.DYNAMIC_DRAW);
|
||||
|
||||
this.drawing = false;
|
||||
this.currentBatchSize = 0;
|
||||
this.currentBaseTexture;
|
||||
}
|
||||
|
||||
PIXI.WebGLSpriteBatch.prototype.begin = function(renderSession)
|
||||
{
|
||||
this.renderSession = renderSession;
|
||||
|
||||
var gl = this.gl;
|
||||
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
|
||||
|
||||
var stride = 5 * 4;
|
||||
|
||||
var projection = renderSession.projection;
|
||||
|
||||
gl.uniform2f(PIXI.defaultShader.projectionVector, projection.x, projection.y);
|
||||
|
||||
|
||||
gl.vertexAttribPointer(PIXI.defaultShader.aVertexPosition, 2, gl.FLOAT, false, stride, 0);
|
||||
gl.vertexAttribPointer(PIXI.defaultShader.aTextureCoord, 2, gl.FLOAT, false, stride, 2 * 4);
|
||||
gl.vertexAttribPointer(PIXI.defaultShader.colorAttribute, 1, gl.FLOAT, false, stride, 4 * 4);
|
||||
|
||||
gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
|
||||
}
|
||||
|
||||
PIXI.WebGLSpriteBatch.prototype.end = function()
|
||||
{
|
||||
this.flush();
|
||||
}
|
||||
|
||||
|
||||
PIXI.WebGLSpriteBatch.prototype.render = function(sprite)
|
||||
{
|
||||
if(sprite.texture.baseTexture !== this.currentBaseTexture || this.currentBatchSize >= this.size)
|
||||
{
|
||||
this.flush();
|
||||
this.currentBaseTexture = sprite.texture.baseTexture;
|
||||
}
|
||||
|
||||
// get the uvs for the texture
|
||||
var uvs = sprite.texture._uvs;
|
||||
// if the uvs have not updated then no point rendering just yet!
|
||||
if(!uvs)return;
|
||||
|
||||
// get the sprites current alpha
|
||||
var alpha = sprite.alpha;
|
||||
|
||||
|
||||
var verticies = this.vertices;
|
||||
|
||||
width = sprite.texture.frame.width;
|
||||
height = sprite.texture.frame.height;
|
||||
|
||||
// TODO trim??
|
||||
var aX = sprite.anchor.x; // - sprite.texture.trim.x
|
||||
var aY = sprite.anchor.y; //- sprite.texture.trim.y
|
||||
var w0 = width * (1-aX);
|
||||
var w1 = width * -aX;
|
||||
|
||||
var h0 = height * (1-aY);
|
||||
var h1 = height * -aY;
|
||||
|
||||
var index = this.currentBatchSize * 4 * 5;
|
||||
|
||||
worldTransform = sprite.worldTransform;
|
||||
|
||||
var a = worldTransform[0];
|
||||
var b = worldTransform[3];
|
||||
var c = worldTransform[1];
|
||||
var d = worldTransform[4];
|
||||
var tx = worldTransform[2];
|
||||
var ty = worldTransform[5];
|
||||
|
||||
// xy
|
||||
verticies[index++] = a * w1 + c * h1 + tx;
|
||||
verticies[index++] = d * h1 + b * w1 + ty;
|
||||
// uv
|
||||
verticies[index++] = uvs[0];
|
||||
verticies[index++] = uvs[1];
|
||||
// color
|
||||
verticies[index++] = alpha;
|
||||
|
||||
// xy
|
||||
verticies[index++] = a * w0 + c * h1 + tx;
|
||||
verticies[index++] = d * h1 + b * w0 + ty;
|
||||
// uv
|
||||
verticies[index++] = uvs[2];
|
||||
verticies[index++] = uvs[3];
|
||||
// color
|
||||
verticies[index++] = alpha;
|
||||
|
||||
// xy
|
||||
verticies[index++] = a * w0 + c * h0 + tx;
|
||||
verticies[index++] = d * h0 + b * w0 + ty;
|
||||
// uv
|
||||
verticies[index++] = uvs[4];
|
||||
verticies[index++] = uvs[5];
|
||||
// color
|
||||
verticies[index++] = alpha;
|
||||
|
||||
// xy
|
||||
verticies[index++] = a * w1 + c * h0 + tx;
|
||||
verticies[index++] = d * h0 + b * w1 + ty;
|
||||
// uv
|
||||
verticies[index++] = uvs[6];
|
||||
verticies[index++] = uvs[7];
|
||||
// color
|
||||
verticies[index++] = alpha;
|
||||
|
||||
// increment the batchs
|
||||
this.currentBatchSize++;
|
||||
}
|
||||
|
||||
PIXI.WebGLSpriteBatch.prototype.renderTilingSprite = function(tilingSprite)
|
||||
{
|
||||
var texture = tilingSprite.texture;
|
||||
|
||||
// set the textures uvs temporarily
|
||||
// TODO create a seperate texture so that we can tile part of a texture
|
||||
var tempUvs = texture._uvs;
|
||||
|
||||
if(!tilingSprite._uvs)tilingSprite._uvs = new Float32Array(8);
|
||||
|
||||
var uvs = tilingSprite._uvs;
|
||||
|
||||
var offsetX = tilingSprite.tilePosition.x/texture.baseTexture.width;
|
||||
var offsetY = tilingSprite.tilePosition.y/texture.baseTexture.height;
|
||||
|
||||
var scaleX = (tilingSprite.width / texture.baseTexture.width) / tilingSprite.tileScale.x;
|
||||
var scaleY = (tilingSprite.height / texture.baseTexture.height) / tilingSprite.tileScale.y;
|
||||
|
||||
uvs[0] = 0 - offsetX;
|
||||
uvs[1] = 0 - offsetY;
|
||||
|
||||
uvs[2] = (1 * scaleX) - offsetX;
|
||||
uvs[3] = 0 - offsetY;
|
||||
|
||||
uvs[4] = (1 * scaleX) - offsetX;
|
||||
uvs[5] = (1 * scaleY) - offsetY;
|
||||
|
||||
uvs[6] = 0 - offsetX;
|
||||
uvs[7] = (1 *scaleY) - offsetY;
|
||||
|
||||
texture._uvs = uvs;
|
||||
|
||||
this.render(tilingSprite);
|
||||
|
||||
tilingSprite.texture._uvs = tempUvs;
|
||||
}
|
||||
|
||||
PIXI.WebGLSpriteBatch.prototype.flush = function()
|
||||
{
|
||||
// first draw
|
||||
|
||||
if (this.currentBatchSize===0)return;
|
||||
|
||||
var gl = this.gl;
|
||||
|
||||
//setup our vertex attributes & binds textures
|
||||
gl.activeTexture(gl.TEXTURE0);
|
||||
gl.bindTexture(gl.TEXTURE_2D, this.currentBaseTexture._glTexture);
|
||||
|
||||
// bind the index
|
||||
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.indexBuffer);
|
||||
//bind our vertex buffer
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
|
||||
|
||||
// Only update a region of the buffer. On my computer
|
||||
// this is faster (especially if you are not filling the entire batch)
|
||||
// but it could do with more testing. In theory it SHOULD be faster
|
||||
// since bufferData allocates memory, whereas this should not.
|
||||
var view = this.vertices.subarray(0, this.currentBatchSize * 4 * 5);
|
||||
gl.bufferSubData(gl.ARRAY_BUFFER, 0, view);
|
||||
|
||||
gl.drawElements(gl.TRIANGLES, this.currentBatchSize * 6, gl.UNSIGNED_SHORT, 0);
|
||||
|
||||
// then reset!
|
||||
this.currentBatchSize = 0;
|
||||
|
||||
this.renderSession.drawCount++;
|
||||
}
|
||||
|
||||
PIXI.WebGLSpriteBatch.prototype.stop = function()
|
||||
{
|
||||
this.flush();
|
||||
}
|
||||
|
||||
PIXI.WebGLSpriteBatch.prototype.start = function()
|
||||
{
|
||||
var gl = this.gl;
|
||||
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
|
||||
|
||||
var stride = 5 * 4;
|
||||
|
||||
var projection = this.renderSession.projection;
|
||||
|
||||
gl.uniform2f(PIXI.defaultShader.projectionVector, projection.x, projection.y);
|
||||
|
||||
gl.vertexAttribPointer(PIXI.defaultShader.aVertexPosition, 2, gl.FLOAT, false, stride, 0);
|
||||
gl.vertexAttribPointer(PIXI.defaultShader.aTextureCoord, 2, gl.FLOAT, false, stride, 2 * 4);
|
||||
gl.vertexAttribPointer(PIXI.defaultShader.colorAttribute, 1, gl.FLOAT, false, stride, 4 * 4);
|
||||
|
||||
gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
|
||||
}
|
||||
|
||||
|
|
@ -93,8 +93,17 @@ PIXI.RenderTexture.prototype.initWebGL = function()
|
|||
// create a projection matrix..
|
||||
this.projection = new PIXI.Point(this.width/2 , -this.height/2);
|
||||
|
||||
|
||||
|
||||
// set the correct render function..
|
||||
this.render = this.renderWebGL;
|
||||
|
||||
this.spriteBatch = new PIXI.WebGLSpriteBatch(gl);
|
||||
|
||||
this.renderSession = {};
|
||||
this.renderSession.spriteBatch = this.spriteBatch;
|
||||
|
||||
PIXI.Texture.frameUpdates.push(this);
|
||||
};
|
||||
|
||||
|
||||
|
@ -187,25 +196,12 @@ PIXI.RenderTexture.prototype.renderWebGL = function(displayObject, position, cle
|
|||
children[i].updateTransform();
|
||||
}
|
||||
|
||||
var renderGroup = displayObject.__renderGroup;
|
||||
this.renderSession.drawCount = 0;
|
||||
this.renderSession.projection = this.projection;
|
||||
|
||||
if(renderGroup)
|
||||
{
|
||||
if(displayObject === renderGroup.root)
|
||||
{
|
||||
renderGroup.render(this.projection, this.glFramebuffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
renderGroup.renderSpecific(displayObject, this.projection, this.glFramebuffer);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!this.renderGroup)this.renderGroup = new PIXI.WebGLRenderGroup(gl);
|
||||
this.renderGroup.setRenderable(displayObject);
|
||||
this.renderGroup.render(this.projection, this.glFramebuffer);
|
||||
}
|
||||
this.spriteBatch.begin(this.renderSession);
|
||||
displayObject._renderWebGL( this.renderSession);
|
||||
this.spriteBatch.end();
|
||||
|
||||
displayObject.worldTransform = originalWorldTransform;
|
||||
};
|
||||
|
|
|
@ -83,9 +83,8 @@ PIXI.Texture.prototype.onBaseTextureLoaded = function()
|
|||
baseTexture.removeEventListener( 'loaded', this.onLoaded );
|
||||
|
||||
if(this.noFrame)this.frame = new PIXI.Rectangle(0,0, baseTexture.width, baseTexture.height);
|
||||
this.noFrame = false;
|
||||
this.width = this.frame.width;
|
||||
this.height = this.frame.height;
|
||||
|
||||
this.setFrame(this.frame);
|
||||
|
||||
this.scope.dispatchEvent( { type: 'update', content: this } );
|
||||
};
|
||||
|
@ -124,6 +123,27 @@ PIXI.Texture.prototype.setFrame = function(frame)
|
|||
//this.dispatchEvent( { type: 'update', content: this } );
|
||||
};
|
||||
|
||||
PIXI.Texture.prototype._updateWebGLuvs = function()
|
||||
{
|
||||
if(!this._uvs)this._uvs = new Float32Array(8)
|
||||
|
||||
var frame = this.frame;
|
||||
var tw = this.baseTexture.width;
|
||||
var th = this.baseTexture.height;
|
||||
|
||||
this._uvs[0] = frame.x / tw;
|
||||
this._uvs[1] = frame.y / th;
|
||||
|
||||
this._uvs[2] = (frame.x + frame.width) / tw;
|
||||
this._uvs[3] = frame.y / th;
|
||||
|
||||
this._uvs[4] = (frame.x + frame.width) / tw;
|
||||
this._uvs[5] = (frame.y + frame.height) / th;
|
||||
|
||||
this._uvs[6] = frame.x / tw;
|
||||
this._uvs[7] = (frame.y + frame.height) / th;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function that returns a texture based on an image url
|
||||
* If the image is not in the texture cache it will be created and loaded
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue