2014-02-28 09:30:53 +00:00
/ * *
* @ author Mat Groves http : //matgroves.com/ @Doormat23
* /
( function ( ) {
var root = this ;
/ * *
* @ author Mat Groves http : //matgroves.com/ @Doormat23
* /
/ * *
* @ module PIXI
* /
var PIXI = PIXI || { } ;
2014-04-01 02:02:36 +00:00
/ *
*
2014-02-28 09:30:53 +00:00
* This file contains a lot of pixi consts which are used across the rendering engine
* @ class Consts
* /
PIXI . WEBGL _RENDERER = 0 ;
PIXI . CANVAS _RENDERER = 1 ;
// useful for testing against if your lib is using pixi.
2014-04-01 02:02:36 +00:00
PIXI . VERSION = "v1.5.2" ;
2014-02-28 09:30:53 +00:00
// the various blend modes supported by pixi
PIXI . blendModes = {
NORMAL : 0 ,
ADD : 1 ,
MULTIPLY : 2 ,
SCREEN : 3 ,
OVERLAY : 4 ,
DARKEN : 5 ,
LIGHTEN : 6 ,
COLOR _DODGE : 7 ,
COLOR _BURN : 8 ,
HARD _LIGHT : 9 ,
SOFT _LIGHT : 10 ,
DIFFERENCE : 11 ,
EXCLUSION : 12 ,
HUE : 13 ,
SATURATION : 14 ,
COLOR : 15 ,
LUMINOSITY : 16
} ;
// the scale modes
PIXI . scaleModes = {
DEFAULT : 0 ,
LINEAR : 0 ,
NEAREST : 1
} ;
2014-04-01 02:02:36 +00:00
// interaction frequency
2014-02-28 09:30:53 +00:00
PIXI . INTERACTION _FREQUENCY = 30 ;
PIXI . AUTO _PREVENT _DEFAULT = true ;
PIXI . RAD _TO _DEG = 180 / Math . PI ;
PIXI . DEG _TO _RAD = Math . PI / 180 ;
/ * *
* @ author Mat Groves http : //matgroves.com/ @Doormat23
* /
/ * *
* The Point object represents a location in a two - dimensional coordinate system , where x represents the horizontal axis and y represents the vertical axis .
*
* @ class Point
* @ constructor
* @ param x { Number } position of the point on the x axis
* @ param y { Number } position of the point on the y axis
* /
PIXI . Point = function ( x , y )
{
/ * *
* @ property x
* @ type Number
* @ default 0
* /
this . x = x || 0 ;
/ * *
* @ property y
* @ type Number
* @ default 0
* /
this . y = y || 0 ;
} ;
/ * *
* Creates a clone of this point
*
* @ method clone
* @ return { Point } a copy of the point
* /
PIXI . Point . prototype . clone = function ( )
{
return new PIXI . Point ( this . x , this . y ) ;
} ;
// constructor
PIXI . Point . prototype . constructor = PIXI . Point ;
PIXI . Point . prototype . set = function ( x , y )
{
this . x = x || 0 ;
this . y = y || ( ( y !== 0 ) ? this . x : 0 ) ;
} ;
/ * *
* @ author Mat Groves http : //matgroves.com/
* /
/ * *
* the Rectangle object is an area defined by its position , as indicated by its top - left corner point ( x , y ) and by its width and its height .
*
* @ class Rectangle
* @ constructor
* @ param x { Number } The X coord of the upper - left corner of the rectangle
* @ param y { Number } The Y coord of the upper - left corner of the rectangle
* @ param width { Number } The overall width of this rectangle
* @ param height { Number } The overall height of this rectangle
* /
PIXI . Rectangle = function ( x , y , width , height )
{
/ * *
* @ property x
* @ type Number
* @ default 0
* /
this . x = x || 0 ;
/ * *
* @ property y
* @ type Number
* @ default 0
* /
this . y = y || 0 ;
/ * *
* @ property width
* @ type Number
* @ default 0
* /
this . width = width || 0 ;
/ * *
* @ property height
* @ type Number
* @ default 0
* /
this . height = height || 0 ;
} ;
/ * *
* Creates a clone of this Rectangle
*
* @ method clone
* @ return { Rectangle } a copy of the rectangle
* /
PIXI . Rectangle . prototype . clone = function ( )
{
return new PIXI . Rectangle ( this . x , this . y , this . width , this . height ) ;
} ;
/ * *
* Checks whether the x and y coordinates passed to this function are contained within this Rectangle
*
* @ method contains
* @ param x { Number } The X coordinate of the point to test
* @ param y { Number } The Y coordinate of the point to test
* @ return { Boolean } Whether the x / y coords are within this Rectangle
* /
PIXI . Rectangle . prototype . contains = function ( x , y )
{
if ( this . width <= 0 || this . height <= 0 )
return false ;
var x1 = this . x ;
if ( x >= x1 && x <= x1 + this . width )
{
var y1 = this . y ;
if ( y >= y1 && y <= y1 + this . height )
{
return true ;
}
}
return false ;
} ;
// constructor
PIXI . Rectangle . prototype . constructor = PIXI . Rectangle ;
PIXI . EmptyRectangle = new PIXI . Rectangle ( 0 , 0 , 0 , 0 ) ;
/ * *
* @ author Adrien Brault < adrien . brault @ gmail . com >
* /
/ * *
* @ class Polygon
* @ constructor
* @ param points * { Array < Point > | Array < Number > | Point ... | Number ... } This can be an array of Points that form the polygon ,
* a flat array of numbers that will be interpreted as [ x , y , x , y , ... ] , or the arguments passed can be
* all the points of the polygon e . g . ` new PIXI.Polygon(new PIXI.Point(), new PIXI.Point(), ...) ` , or the
* arguments passed can be flat x , y values e . g . ` new PIXI.Polygon(x,y, x,y, x,y, ...) ` where ` x ` and ` y ` are
* Numbers .
* /
PIXI . Polygon = function ( points )
{
//if points isn't an array, use arguments as the array
if ( ! ( points instanceof Array ) )
points = Array . prototype . slice . call ( arguments ) ;
//if this is a flat array of numbers, convert it to points
if ( typeof points [ 0 ] === 'number' ) {
var p = [ ] ;
for ( var i = 0 , il = points . length ; i < il ; i += 2 ) {
p . push (
new PIXI . Point ( points [ i ] , points [ i + 1 ] )
) ;
}
points = p ;
}
this . points = points ;
} ;
/ * *
* Creates a clone of this polygon
*
* @ method clone
* @ return { Polygon } a copy of the polygon
* /
PIXI . Polygon . prototype . clone = function ( )
{
var points = [ ] ;
for ( var i = 0 ; i < this . points . length ; i ++ ) {
points . push ( this . points [ i ] . clone ( ) ) ;
}
return new PIXI . Polygon ( points ) ;
} ;
/ * *
* Checks whether the x and y coordinates passed to this function are contained within this polygon
*
* @ method contains
* @ param x { Number } The X coordinate of the point to test
* @ param y { Number } The Y coordinate of the point to test
* @ return { Boolean } Whether the x / y coordinates are within this polygon
* /
PIXI . Polygon . prototype . contains = function ( x , y )
{
var inside = false ;
// use some raycasting to test hits
// https://github.com/substack/point-in-polygon/blob/master/index.js
for ( var i = 0 , j = this . points . length - 1 ; i < this . points . length ; j = i ++ ) {
var xi = this . points [ i ] . x , yi = this . points [ i ] . y ,
xj = this . points [ j ] . x , yj = this . points [ j ] . y ,
intersect = ( ( yi > y ) !== ( yj > y ) ) && ( x < ( xj - xi ) * ( y - yi ) / ( yj - yi ) + xi ) ;
if ( intersect ) inside = ! inside ;
}
return inside ;
} ;
// constructor
PIXI . Polygon . prototype . constructor = PIXI . Polygon ;
/ * *
* @ author Chad Engler < chad @ pantherdev . com >
* /
/ * *
* The Circle object can be used to specify a hit area for displayObjects
*
* @ class Circle
* @ constructor
* @ param x { Number } The X coordinate of the upper - left corner of the framing rectangle of this circle
* @ param y { Number } The Y coordinate of the upper - left corner of the framing rectangle of this circle
* @ param radius { Number } The radius of the circle
* /
PIXI . Circle = function ( x , y , radius )
{
/ * *
* @ property x
* @ type Number
* @ default 0
* /
this . x = x || 0 ;
/ * *
* @ property y
* @ type Number
* @ default 0
* /
this . y = y || 0 ;
/ * *
* @ property radius
* @ type Number
* @ default 0
* /
this . radius = radius || 0 ;
} ;
/ * *
* Creates a clone of this Circle instance
*
* @ method clone
* @ return { Circle } a copy of the polygon
* /
PIXI . Circle . prototype . clone = function ( )
{
return new PIXI . Circle ( this . x , this . y , this . radius ) ;
} ;
/ * *
* Checks whether the x , and y coordinates passed to this function are contained within this circle
*
* @ method contains
* @ param x { Number } The X coordinate of the point to test
* @ param y { Number } The Y coordinate of the point to test
* @ return { Boolean } Whether the x / y coordinates are within this polygon
* /
PIXI . Circle . prototype . contains = function ( x , y )
{
if ( this . radius <= 0 )
return false ;
var dx = ( this . x - x ) ,
dy = ( this . y - y ) ,
r2 = this . radius * this . radius ;
dx *= dx ;
dy *= dy ;
return ( dx + dy <= r2 ) ;
} ;
// constructor
PIXI . Circle . prototype . constructor = PIXI . Circle ;
/ * *
* @ author Chad Engler < chad @ pantherdev . com >
* /
/ * *
* The Ellipse object can be used to specify a hit area for displayObjects
*
* @ class Ellipse
* @ constructor
* @ param x { Number } The X coordinate of the upper - left corner of the framing rectangle of this ellipse
* @ param y { Number } The Y coordinate of the upper - left corner of the framing rectangle of this ellipse
* @ param width { Number } The overall width of this ellipse
* @ param height { Number } The overall height of this ellipse
* /
PIXI . Ellipse = function ( x , y , width , height )
{
/ * *
* @ property x
* @ type Number
* @ default 0
* /
this . x = x || 0 ;
/ * *
* @ property y
* @ type Number
* @ default 0
* /
this . y = y || 0 ;
/ * *
* @ property width
* @ type Number
* @ default 0
* /
this . width = width || 0 ;
/ * *
* @ property height
* @ type Number
* @ default 0
* /
this . height = height || 0 ;
} ;
/ * *
* Creates a clone of this Ellipse instance
*
* @ method clone
* @ return { Ellipse } a copy of the ellipse
* /
PIXI . Ellipse . prototype . clone = function ( )
{
return new PIXI . Ellipse ( this . x , this . y , this . width , this . height ) ;
} ;
/ * *
* Checks whether the x and y coordinates passed to this function are contained within this ellipse
*
* @ method contains
* @ param x { Number } The X coordinate of the point to test
* @ param y { Number } The Y coordinate of the point to test
* @ return { Boolean } Whether the x / y coords are within this ellipse
* /
PIXI . Ellipse . prototype . contains = function ( x , y )
{
if ( this . width <= 0 || this . height <= 0 )
return false ;
//normalize the coords to an ellipse with center 0,0
var normx = ( ( x - this . x ) / this . width ) ,
normy = ( ( y - this . y ) / this . height ) ;
normx *= normx ;
normy *= normy ;
return ( normx + normy <= 1 ) ;
} ;
/ * *
* Returns the framing rectangle of the ellipse as a PIXI . Rectangle object
*
* @ method getBounds
* @ return { Rectangle } the framing rectangle
* /
PIXI . Ellipse . prototype . getBounds = function ( )
{
return new PIXI . Rectangle ( this . x , this . y , this . width , this . height ) ;
} ;
// constructor
PIXI . Ellipse . prototype . constructor = PIXI . Ellipse ;
/ * *
* @ author Mat Groves http : //matgroves.com/ @Doormat23
* /
PIXI . determineMatrixArrayType = function ( ) {
return ( typeof Float32Array !== 'undefined' ) ? Float32Array : Array ;
} ;
/ *
* @ class Matrix2
* The Matrix2 class will choose the best type of array to use between
* a regular javascript Array and a Float32Array if the latter is available
*
* /
PIXI . Matrix2 = PIXI . determineMatrixArrayType ( ) ;
/ *
* @ class Matrix
2014-04-01 02:02:36 +00:00
* The Matrix class is now an object , which makes it a lot faster ,
* here is a representation of it :
2014-02-28 09:30:53 +00:00
* | a | b | tx |
* | c | c | ty |
* | 0 | 0 | 1 |
*
* /
PIXI . Matrix = function ( )
{
this . a = 1 ;
this . b = 0 ;
this . c = 0 ;
this . d = 1 ;
this . tx = 0 ;
this . ty = 0 ;
} ;
/ * *
* Creates a pixi matrix object based on the array given as a parameter
*
* @ method fromArray
* @ param array { Array } The array that the matrix will be filled with
* /
PIXI . Matrix . prototype . fromArray = function ( array )
{
this . a = array [ 0 ] ;
this . b = array [ 1 ] ;
this . c = array [ 3 ] ;
this . d = array [ 4 ] ;
this . tx = array [ 2 ] ;
this . ty = array [ 5 ] ;
} ;
/ * *
* Creates an array from the current Matrix object
*
* @ method toArray
* @ param transpose { Boolean } Whether we need to transpose the matrix or not
* @ return array { Array } the newly created array which contains the matrix
* /
PIXI . Matrix . prototype . toArray = function ( transpose )
{
if ( ! this . array ) this . array = new Float32Array ( 9 ) ;
var array = this . array ;
if ( transpose )
{
this . array [ 0 ] = this . a ;
this . array [ 1 ] = this . c ;
this . array [ 2 ] = 0 ;
this . array [ 3 ] = this . b ;
this . array [ 4 ] = this . d ;
this . array [ 5 ] = 0 ;
this . array [ 6 ] = this . tx ;
this . array [ 7 ] = this . ty ;
this . array [ 8 ] = 1 ;
}
else
{
this . array [ 0 ] = this . a ;
this . array [ 1 ] = this . b ;
this . array [ 2 ] = this . tx ;
this . array [ 3 ] = this . c ;
this . array [ 4 ] = this . d ;
this . array [ 5 ] = this . ty ;
this . array [ 6 ] = 0 ;
this . array [ 7 ] = 0 ;
this . array [ 8 ] = 1 ;
}
return array ; //[this.a, this.b, this.tx, this.c, this.d, this.ty, 0, 0, 1];
} ;
PIXI . identityMatrix = new PIXI . Matrix ( ) ;
/ * *
* @ author Mat Groves http : //matgroves.com/ @Doormat23
* /
/ * *
* The base class for all objects that are rendered on the screen .
*
* @ class DisplayObject
* @ constructor
* /
PIXI . DisplayObject = function ( )
{
/ * *
* The coordinate of the object relative to the local coordinates of the parent .
*
* @ property position
* @ type Point
* /
this . position = new PIXI . Point ( ) ;
/ * *
* The scale factor of the object .
*
* @ property scale
* @ type Point
* /
this . scale = new PIXI . Point ( 1 , 1 ) ; //{x:1, y:1};
/ * *
* The pivot point of the displayObject that it rotates around
*
* @ property pivot
* @ type Point
* /
this . pivot = new PIXI . Point ( 0 , 0 ) ;
/ * *
* The rotation of the object in radians .
*
* @ property rotation
* @ type Number
* /
this . rotation = 0 ;
/ * *
* The opacity of the object .
*
* @ property alpha
* @ type Number
* /
this . alpha = 1 ;
/ * *
* The visibility of the object .
*
* @ property visible
* @ type Boolean
* /
this . visible = true ;
/ * *
* This is the defined area that will pick up mouse / touch events . It is null by default .
* Setting it is a neat way of optimising the hitTest function that the interactionManager will use ( as it will not need to hit test all the children )
*
* @ property hitArea
* @ type Rectangle | Circle | Ellipse | Polygon
* /
this . hitArea = null ;
/ * *
* This is used to indicate if the displayObject should display a mouse hand cursor on rollover
*
* @ property buttonMode
* @ type Boolean
* /
this . buttonMode = false ;
/ * *
* Can this object be rendered
*
* @ property renderable
* @ type Boolean
* /
this . renderable = false ;
/ * *
* [ read - only ] The display object container that contains this display object .
*
* @ property parent
* @ type DisplayObjectContainer
* @ readOnly
* /
this . parent = null ;
/ * *
* [ read - only ] The stage the display object is connected to , or undefined if it is not connected to the stage .
*
* @ property stage
* @ type Stage
* @ readOnly
* /
this . stage = null ;
/ * *
* [ read - only ] The multiplied alpha of the displayObject
*
* @ property worldAlpha
* @ type Number
* @ readOnly
* /
this . worldAlpha = 1 ;
/ * *
* [ read - only ] Whether or not the object is interactive , do not toggle directly ! use the ` interactive ` property
*
* @ property _interactive
* @ type Boolean
* @ readOnly
* @ private
* /
this . _interactive = false ;
/ * *
* This is the cursor that will be used when the mouse is over this object . To enable this the element must have interaction = true and buttonMode = true
2014-04-01 02:02:36 +00:00
*
2014-02-28 09:30:53 +00:00
* @ property defaultCursor
* @ type String
*
* /
this . defaultCursor = 'pointer' ;
/ * *
* [ read - only ] Current transform of the object based on world ( parent ) factors
*
* @ property worldTransform
* @ type Mat3
* @ readOnly
* @ private
* /
this . worldTransform = new PIXI . Matrix ( ) ;
/ * *
* [ NYI ] Unknown
*
* @ property color
* @ type Array < >
* @ private
* /
this . color = [ ] ;
/ * *
* [ NYI ] Holds whether or not this object is dynamic , for rendering optimization
*
* @ property dynamic
* @ type Boolean
* @ private
* /
this . dynamic = true ;
// cached sin rotation and cos rotation
this . _sr = 0 ;
this . _cr = 1 ;
/ * *
2014-04-01 02:02:36 +00:00
* The area the filter is applied to like the hitArea this is used as more of an optimisation
* rather than figuring out the dimensions of the displayObject each frame you can set this rectangle
2014-02-28 09:30:53 +00:00
*
* @ property filterArea
* @ type Rectangle
* /
2014-04-01 02:02:36 +00:00
this . filterArea = null ; //new PIXI.Rectangle(0,0,1,1);
2014-02-28 09:30:53 +00:00
/ * *
* The original , cached bounds of the object
*
* @ property _bounds
* @ type Rectangle
* @ private
* /
this . _bounds = new PIXI . Rectangle ( 0 , 0 , 1 , 1 ) ;
/ * *
* The most up - to - date bounds of the object
*
* @ property _currentBounds
* @ type Rectangle
* @ private
* /
this . _currentBounds = null ;
/ * *
* The original , cached mask of the object
*
* @ property _currentBounds
* @ type Rectangle
* @ private
* /
this . _mask = null ;
this . _cacheAsBitmap = false ;
this . _cacheIsDirty = false ;
/ *
* MOUSE Callbacks
* /
/ * *
* A callback that is used when the users clicks on the displayObject with their mouse
* @ method click
* @ param interactionData { InteractionData }
* /
/ * *
* A callback that is used when the user clicks the mouse down over the sprite
* @ method mousedown
* @ param interactionData { InteractionData }
* /
/ * *
* A callback that is used when the user releases the mouse that was over the displayObject
* for this callback to be fired the mouse must have been pressed down over the displayObject
* @ method mouseup
* @ param interactionData { InteractionData }
* /
/ * *
* A callback that is used when the user releases the mouse that was over the displayObject but is no longer over the displayObject
* for this callback to be fired , The touch must have started over the displayObject
* @ method mouseupoutside
* @ param interactionData { InteractionData }
* /
/ * *
* A callback that is used when the users mouse rolls over the displayObject
* @ method mouseover
* @ param interactionData { InteractionData }
* /
/ * *
* A callback that is used when the users mouse leaves the displayObject
* @ method mouseout
* @ param interactionData { InteractionData }
* /
/ *
* TOUCH Callbacks
* /
/ * *
* A callback that is used when the users taps on the sprite with their finger
* basically a touch version of click
* @ method tap
* @ param interactionData { InteractionData }
* /
/ * *
* A callback that is used when the user touches over the displayObject
* @ method touchstart
* @ param interactionData { InteractionData }
* /
/ * *
* A callback that is used when the user releases a touch over the displayObject
* @ method touchend
* @ param interactionData { InteractionData }
* /
/ * *
* A callback that is used when the user releases the touch that was over the displayObject
* for this callback to be fired , The touch must have started over the sprite
* @ method touchendoutside
* @ param interactionData { InteractionData }
* /
} ;
// constructor
PIXI . DisplayObject . prototype . constructor = PIXI . DisplayObject ;
/ * *
* [ Deprecated ] Indicates if the sprite will have touch and mouse interactivity . It is false by default
* Instead of using this function you can now simply set the interactive property to true or false
*
* @ method setInteractive
* @ param interactive { Boolean }
* @ deprecated Simply set the ` interactive ` property directly
* /
PIXI . DisplayObject . prototype . setInteractive = function ( interactive )
{
this . interactive = interactive ;
} ;
/ * *
* Indicates if the sprite will have touch and mouse interactivity . It is false by default
*
* @ property interactive
* @ type Boolean
* @ default false
* /
Object . defineProperty ( PIXI . DisplayObject . prototype , 'interactive' , {
get : function ( ) {
return this . _interactive ;
} ,
set : function ( value ) {
this . _interactive = value ;
// TODO more to be done here..
// need to sort out a re-crawl!
if ( this . stage ) this . stage . dirty = true ;
}
} ) ;
/ * *
* [ read - only ] Indicates if the sprite is globaly visible .
*
* @ property worldVisible
* @ type Boolean
* /
Object . defineProperty ( PIXI . DisplayObject . prototype , 'worldVisible' , {
get : function ( ) {
var item = this ;
do
{
if ( ! item . visible ) return false ;
item = item . parent ;
}
while ( item ) ;
return true ;
}
} ) ;
/ * *
* Sets a mask for the displayObject . A mask is an object that limits the visibility of an object to the shape of the mask applied to it .
* In PIXI a regular mask must be a PIXI . Graphics object . This allows for much faster masking in canvas as it utilises shape clipping .
* To remove a mask , set this property to null .
*
* @ property mask
* @ type Graphics
* /
Object . defineProperty ( PIXI . DisplayObject . prototype , 'mask' , {
get : function ( ) {
return this . _mask ;
} ,
set : function ( value ) {
if ( this . _mask ) this . _mask . isMask = false ;
this . _mask = value ;
if ( this . _mask ) this . _mask . isMask = true ;
}
} ) ;
/ * *
* Sets the filters for the displayObject .
* * IMPORTANT : This is a webGL only feature and will be ignored by the canvas renderer .
* To remove filters simply set this property to 'null'
* @ property filters
* @ type Array An array of filters
* /
Object . defineProperty ( PIXI . DisplayObject . prototype , 'filters' , {
get : function ( ) {
return this . _filters ;
} ,
set : function ( value ) {
if ( value )
{
// now put all the passes in one place..
var passes = [ ] ;
for ( var i = 0 ; i < value . length ; i ++ )
{
var filterPasses = value [ i ] . passes ;
for ( var j = 0 ; j < filterPasses . length ; j ++ )
{
passes . push ( filterPasses [ j ] ) ;
}
}
// TODO change this as it is legacy
this . _filterBlock = { target : this , filterPasses : passes } ;
}
this . _filters = value ;
}
} ) ;
2014-04-01 02:02:36 +00:00
/ * *
* Set weather or not a the display objects is cached as a bitmap .
* This basically takes a snap shot of the display object as it is at that moment . It can provide a performance benefit for complex static displayObjects
* To remove filters simply set this property to 'null'
* @ property cacheAsBitmap
* @ type Boolean
* /
2014-02-28 09:30:53 +00:00
Object . defineProperty ( PIXI . DisplayObject . prototype , 'cacheAsBitmap' , {
get : function ( ) {
return this . _cacheAsBitmap ;
} ,
set : function ( value ) {
if ( this . _cacheAsBitmap === value ) return ;
if ( value )
{
//this._cacheIsDirty = true;
this . _generateCachedSprite ( ) ;
}
else
{
this . _destroyCachedSprite ( ) ;
}
this . _cacheAsBitmap = value ;
}
} ) ;
/ *
* Updates the object transform for rendering
*
* @ method updateTransform
* @ private
* /
PIXI . DisplayObject . prototype . updateTransform = function ( )
{
// TODO OPTIMIZE THIS!! with dirty
if ( this . rotation !== this . rotationCache )
{
this . rotationCache = this . rotation ;
this . _sr = Math . sin ( this . rotation ) ;
this . _cr = Math . cos ( this . rotation ) ;
}
// var localTransform = this.localTransform//.toArray();
var parentTransform = this . parent . worldTransform ; //.toArray();
var worldTransform = this . worldTransform ; //.toArray();
var px = this . pivot . x ;
var py = this . pivot . y ;
var a00 = this . _cr * this . scale . x ,
a01 = - this . _sr * this . scale . y ,
a10 = this . _sr * this . scale . x ,
a11 = this . _cr * this . scale . y ,
a02 = this . position . x - a00 * px - py * a01 ,
a12 = this . position . y - a11 * py - px * a10 ,
b00 = parentTransform . a , b01 = parentTransform . b ,
b10 = parentTransform . c , b11 = parentTransform . d ;
worldTransform . a = b00 * a00 + b01 * a10 ;
worldTransform . b = b00 * a01 + b01 * a11 ;
worldTransform . tx = b00 * a02 + b01 * a12 + parentTransform . tx ;
worldTransform . c = b10 * a00 + b11 * a10 ;
worldTransform . d = b10 * a01 + b11 * a11 ;
worldTransform . ty = b10 * a02 + b11 * a12 + parentTransform . ty ;
this . worldAlpha = this . alpha * this . parent . worldAlpha ;
} ;
/ * *
* Retrieves the bounds of the displayObject as a rectangle object
*
* @ method getBounds
* @ return { Rectangle } the rectangular bounding area
* /
PIXI . DisplayObject . prototype . getBounds = function ( matrix )
{
matrix = matrix ; //just to get passed js hinting (and preserve inheritance)
return PIXI . EmptyRectangle ;
} ;
/ * *
* Retrieves the local bounds of the displayObject as a rectangle object
*
* @ method getLocalBounds
* @ return { Rectangle } the rectangular bounding area
* /
PIXI . DisplayObject . prototype . getLocalBounds = function ( )
{
return this . getBounds ( PIXI . identityMatrix ) ; ///PIXI.EmptyRectangle();
} ;
/ * *
* Sets the object ' s stage reference , the stage this object is connected to
*
* @ method setStageReference
* @ param stage { Stage } the stage that the object will have as its current stage reference
* /
PIXI . DisplayObject . prototype . setStageReference = function ( stage )
{
this . stage = stage ;
if ( this . _interactive ) this . stage . dirty = true ;
} ;
PIXI . DisplayObject . prototype . generateTexture = function ( renderer )
{
var bounds = this . getLocalBounds ( ) ;
var renderTexture = new PIXI . RenderTexture ( bounds . width | 0 , bounds . height | 0 , renderer ) ;
renderTexture . render ( this ) ;
return renderTexture ;
} ;
PIXI . DisplayObject . prototype . updateCache = function ( )
{
this . _generateCachedSprite ( ) ;
} ;
PIXI . DisplayObject . prototype . _renderCachedSprite = function ( renderSession )
{
if ( renderSession . gl )
{
PIXI . Sprite . prototype . _renderWebGL . call ( this . _cachedSprite , renderSession ) ;
}
else
{
PIXI . Sprite . prototype . _renderCanvas . call ( this . _cachedSprite , renderSession ) ;
}
} ;
PIXI . DisplayObject . prototype . _generateCachedSprite = function ( ) //renderSession)
{
this . _cacheAsBitmap = false ;
var bounds = this . getLocalBounds ( ) ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
if ( ! this . _cachedSprite )
{
var renderTexture = new PIXI . RenderTexture ( bounds . width | 0 , bounds . height | 0 ) ; //, renderSession.renderer);
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
this . _cachedSprite = new PIXI . Sprite ( renderTexture ) ;
this . _cachedSprite . worldTransform = this . worldTransform ;
}
else
{
this . _cachedSprite . texture . resize ( bounds . width | 0 , bounds . height | 0 ) ;
}
//REMOVE filter!
var tempFilters = this . _filters ;
this . _filters = null ;
this . _cachedSprite . filters = tempFilters ;
this . _cachedSprite . texture . render ( this ) ;
this . _filters = tempFilters ;
this . _cacheAsBitmap = true ;
} ;
/ * *
* Renders the object using the WebGL renderer
*
* @ method _renderWebGL
2014-04-01 02:02:36 +00:00
* @ param renderSession { RenderSession }
2014-02-28 09:30:53 +00:00
* @ private
* /
PIXI . DisplayObject . prototype . _destroyCachedSprite = function ( )
{
if ( ! this . _cachedSprite ) return ;
this . _cachedSprite . texture . destroy ( true ) ;
// console.log("DESTROY")
// let the gc collect the unused sprite
// TODO could be object pooled!
this . _cachedSprite = null ;
} ;
PIXI . DisplayObject . prototype . _renderWebGL = function ( renderSession )
{
// OVERWRITE;
// this line is just here to pass jshinting :)
renderSession = renderSession ;
} ;
/ * *
* Renders the object using the Canvas renderer
*
* @ method _renderCanvas
2014-04-01 02:02:36 +00:00
* @ param renderSession { RenderSession }
2014-02-28 09:30:53 +00:00
* @ private
* /
PIXI . DisplayObject . prototype . _renderCanvas = function ( renderSession )
{
// OVERWRITE;
// this line is just here to pass jshinting :)
renderSession = renderSession ;
} ;
/ * *
* The position of the displayObject on the x axis relative to the local coordinates of the parent .
*
* @ property x
* @ type Number
* /
Object . defineProperty ( PIXI . DisplayObject . prototype , 'x' , {
get : function ( ) {
return this . position . x ;
} ,
set : function ( value ) {
this . position . x = value ;
}
} ) ;
/ * *
* The position of the displayObject on the y axis relative to the local coordinates of the parent .
*
* @ property y
* @ type Number
* /
Object . defineProperty ( PIXI . DisplayObject . prototype , 'y' , {
get : function ( ) {
return this . position . y ;
} ,
set : function ( value ) {
this . position . y = value ;
}
} ) ;
/ * *
* @ author Mat Groves http : //matgroves.com/ @Doormat23
* /
/ * *
* A DisplayObjectContainer represents a collection of display objects .
* It is the base class of all display objects that act as a container for other objects .
*
* @ class DisplayObjectContainer
* @ extends DisplayObject
* @ constructor
* /
PIXI . DisplayObjectContainer = function ( )
{
PIXI . DisplayObject . call ( this ) ;
/ * *
* [ read - only ] The array of children of this container .
*
* @ property children
* @ type Array < DisplayObject >
* @ readOnly
* /
this . children = [ ] ;
} ;
// constructor
PIXI . DisplayObjectContainer . prototype = Object . create ( PIXI . DisplayObject . prototype ) ;
PIXI . DisplayObjectContainer . prototype . constructor = PIXI . DisplayObjectContainer ;
/ * *
* The width of the displayObjectContainer , setting this will actually modify the scale to achieve the value set
*
* @ property width
* @ type Number
* /
/ *
Object . defineProperty ( PIXI . DisplayObjectContainer . prototype , 'width' , {
get : function ( ) {
return this . scale . x * this . getLocalBounds ( ) . width ;
} ,
set : function ( value ) {
this . scale . x = value / ( this . getLocalBounds ( ) . width / this . scale . x ) ;
this . _width = value ;
}
} ) ;
* /
/ * *
* The height of the displayObjectContainer , setting this will actually modify the scale to achieve the value set
*
* @ property height
* @ type Number
* /
/ *
Object . defineProperty ( PIXI . DisplayObjectContainer . prototype , 'height' , {
get : function ( ) {
return this . scale . y * this . getLocalBounds ( ) . height ;
} ,
set : function ( value ) {
this . scale . y = value / ( this . getLocalBounds ( ) . height / this . scale . y ) ;
this . _height = value ;
}
} ) ;
* /
/ * *
* Adds a child to the container .
*
* @ method addChild
* @ param child { DisplayObject } The DisplayObject to add to the container
* /
PIXI . DisplayObjectContainer . prototype . addChild = function ( child )
{
this . addChildAt ( child , this . children . length ) ;
} ;
/ * *
* Adds a child to the container at a specified index . If the index is out of bounds an error will be thrown
*
* @ method addChildAt
* @ param child { DisplayObject } The child to add
* @ param index { Number } The index to place the child in
* /
PIXI . DisplayObjectContainer . prototype . addChildAt = function ( child , index )
{
if ( index >= 0 && index <= this . children . length )
{
if ( child . parent )
{
child . parent . removeChild ( child ) ;
}
child . parent = this ;
this . children . splice ( index , 0 , child ) ;
if ( this . stage ) child . setStageReference ( this . stage ) ;
}
else
{
throw new Error ( child + ' The index ' + index + ' supplied is out of bounds ' + this . children . length ) ;
}
} ;
/ * *
* [ NYI ] Swaps the depth of 2 displayObjects
*
* @ method swapChildren
* @ param child { DisplayObject }
* @ param child2 { DisplayObject }
* @ private
* /
PIXI . DisplayObjectContainer . prototype . swapChildren = function ( child , child2 )
{
if ( child === child2 ) {
return ;
}
var index1 = this . children . indexOf ( child ) ;
var index2 = this . children . indexOf ( child2 ) ;
if ( index1 < 0 || index2 < 0 ) {
throw new Error ( 'swapChildren: Both the supplied DisplayObjects must be a child of the caller.' ) ;
}
this . children [ index1 ] = child2 ;
this . children [ index2 ] = child ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
} ;
/ * *
* Returns the child at the specified index
*
* @ method getChildAt
* @ param index { Number } The index to get the child from
* /
PIXI . DisplayObjectContainer . prototype . getChildAt = function ( index )
{
if ( index >= 0 && index < this . children . length )
{
return this . children [ index ] ;
}
else
{
2014-04-01 02:02:36 +00:00
throw new Error ( 'Supplied index does not exist in the child list, or the supplied DisplayObject must be a child of the caller' ) ;
2014-02-28 09:30:53 +00:00
}
} ;
/ * *
* Removes a child from the container .
*
* @ method removeChild
* @ param child { DisplayObject } The DisplayObject to remove
* /
PIXI . DisplayObjectContainer . prototype . removeChild = function ( child )
{
2014-04-01 02:02:36 +00:00
return this . removeChildAt ( this . children . indexOf ( child ) ) ;
2014-02-28 09:30:53 +00:00
} ;
2014-04-01 02:02:36 +00:00
/ * *
* Removes a child from the specified index position in the child list of the container .
*
* @ method removeChildAt
* @ param index { Number } The index to get the child from
* /
PIXI . DisplayObjectContainer . prototype . removeChildAt = function ( index )
{
var child = this . getChildAt ( index ) ;
if ( this . stage )
child . removeStageReference ( ) ;
child . parent = undefined ;
this . children . splice ( index , 1 ) ;
return child ;
} ;
2014-02-28 09:30:53 +00:00
/ * *
2014-04-01 02:02:36 +00:00
* Removes all child instances from the child list of the container .
2014-02-28 09:30:53 +00:00
*
2014-04-01 02:02:36 +00:00
* @ method removeChildren
* @ param beginIndex { Number } The beginning position . Predefined value is 0.
* @ param endIndex { Number } The ending position . Predefined value is children ' s array length .
2014-02-28 09:30:53 +00:00
* /
2014-04-01 02:02:36 +00:00
PIXI . DisplayObjectContainer . prototype . removeChildren = function ( beginIndex , endIndex )
2014-02-28 09:30:53 +00:00
{
2014-04-01 02:02:36 +00:00
var begin = beginIndex || 0 ;
var end = typeof endIndex === 'number' ? endIndex : this . children . length ;
var range = end - begin ;
2014-02-28 09:30:53 +00:00
2014-04-01 02:02:36 +00:00
if ( range > 0 && range <= end )
2014-02-28 09:30:53 +00:00
{
2014-04-01 02:02:36 +00:00
var removed = this . children . splice ( begin , range ) ;
for ( var i = 0 ; i < removed . length ; i ++ ) {
var child = removed [ i ] ;
if ( this . stage )
child . removeStageReference ( ) ;
child . parent = undefined ;
}
return removed ;
}
else
{
throw new Error ( 'Range Error, numeric values are outside the acceptable range' ) ;
2014-02-28 09:30:53 +00:00
}
} ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
/ *
* Updates the container ' s childrens transform for rendering
*
* @ method updateTransform
* @ private
* /
PIXI . DisplayObjectContainer . prototype . updateTransform = function ( )
{
//this._currentBounds = null;
if ( ! this . visible ) return ;
PIXI . DisplayObject . prototype . updateTransform . call ( this ) ;
if ( this . _cacheAsBitmap ) return ;
for ( var i = 0 , j = this . children . length ; i < j ; i ++ )
{
this . children [ i ] . updateTransform ( ) ;
}
} ;
/ * *
* Retrieves the bounds of the displayObjectContainer as a rectangle object
*
* @ method getBounds
* @ return { Rectangle } the rectangular bounding area
* /
PIXI . DisplayObjectContainer . prototype . getBounds = function ( matrix )
{
if ( this . children . length === 0 ) return PIXI . EmptyRectangle ;
// TODO the bounds have already been calculated this render session so return what we have
if ( matrix )
{
var matrixCache = this . worldTransform ;
this . worldTransform = matrix ;
this . updateTransform ( ) ;
this . worldTransform = matrixCache ;
}
var minX = Infinity ;
var minY = Infinity ;
var maxX = - Infinity ;
var maxY = - Infinity ;
var childBounds ;
var childMaxX ;
var childMaxY ;
var childVisible = false ;
for ( var i = 0 , j = this . children . length ; i < j ; i ++ )
{
var child = this . children [ i ] ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
if ( ! child . visible ) continue ;
childVisible = true ;
childBounds = this . children [ i ] . getBounds ( matrix ) ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
minX = minX < childBounds . x ? minX : childBounds . x ;
minY = minY < childBounds . y ? minY : childBounds . y ;
childMaxX = childBounds . width + childBounds . x ;
childMaxY = childBounds . height + childBounds . y ;
maxX = maxX > childMaxX ? maxX : childMaxX ;
maxY = maxY > childMaxY ? maxY : childMaxY ;
}
if ( ! childVisible )
return PIXI . EmptyRectangle ;
var bounds = this . _bounds ;
bounds . x = minX ;
bounds . y = minY ;
bounds . width = maxX - minX ;
bounds . height = maxY - minY ;
// TODO: store a reference so that if this function gets called again in the render cycle we do not have to recalculate
//this._currentBounds = bounds;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
return bounds ;
} ;
PIXI . DisplayObjectContainer . prototype . getLocalBounds = function ( )
{
var matrixCache = this . worldTransform ;
this . worldTransform = PIXI . identityMatrix ;
for ( var i = 0 , j = this . children . length ; i < j ; i ++ )
{
this . children [ i ] . updateTransform ( ) ;
}
var bounds = this . getBounds ( ) ;
this . worldTransform = matrixCache ;
return bounds ;
} ;
/ * *
* Sets the container ' s stage reference , the stage this object is connected to
*
* @ method setStageReference
* @ param stage { Stage } the stage that the container will have as its current stage reference
* /
PIXI . DisplayObjectContainer . prototype . setStageReference = function ( stage )
{
this . stage = stage ;
if ( this . _interactive ) this . stage . dirty = true ;
for ( var i = 0 , j = this . children . length ; i < j ; i ++ )
{
var child = this . children [ i ] ;
child . setStageReference ( stage ) ;
}
} ;
/ * *
* removes the current stage reference of the container
*
* @ method removeStageReference
* /
PIXI . DisplayObjectContainer . prototype . removeStageReference = function ( )
{
for ( var i = 0 , j = this . children . length ; i < j ; i ++ )
{
var child = this . children [ i ] ;
child . removeStageReference ( ) ;
}
if ( this . _interactive ) this . stage . dirty = true ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
this . stage = null ;
} ;
/ * *
* Renders the object using the WebGL renderer
*
* @ method _renderWebGL
2014-04-01 02:02:36 +00:00
* @ param renderSession { RenderSession }
2014-02-28 09:30:53 +00:00
* @ private
* /
PIXI . DisplayObjectContainer . prototype . _renderWebGL = function ( renderSession )
{
if ( ! this . visible || this . alpha <= 0 ) return ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
if ( this . _cacheAsBitmap )
{
this . _renderCachedSprite ( renderSession ) ;
return ;
}
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
var i , j ;
if ( this . _mask || this . _filters )
{
if ( this . _mask )
{
renderSession . spriteBatch . stop ( ) ;
renderSession . maskManager . pushMask ( this . mask , renderSession ) ;
renderSession . spriteBatch . start ( ) ;
}
if ( this . _filters )
{
renderSession . spriteBatch . flush ( ) ;
renderSession . filterManager . pushFilter ( this . _filterBlock ) ;
}
// simple render children!
for ( i = 0 , j = this . children . length ; i < j ; i ++ )
{
this . children [ i ] . _renderWebGL ( renderSession ) ;
}
renderSession . spriteBatch . stop ( ) ;
if ( this . _filters ) renderSession . filterManager . popFilter ( ) ;
if ( this . _mask ) renderSession . maskManager . popMask ( renderSession ) ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
renderSession . spriteBatch . start ( ) ;
}
else
{
// simple render children!
for ( i = 0 , j = this . children . length ; i < j ; i ++ )
{
this . children [ i ] . _renderWebGL ( renderSession ) ;
}
}
} ;
/ * *
* Renders the object using the Canvas renderer
*
* @ method _renderCanvas
2014-04-01 02:02:36 +00:00
* @ param renderSession { RenderSession }
2014-02-28 09:30:53 +00:00
* @ private
* /
PIXI . DisplayObjectContainer . prototype . _renderCanvas = function ( renderSession )
{
if ( this . visible === false || this . alpha === 0 ) return ;
if ( this . _cacheAsBitmap )
{
this . _renderCachedSprite ( renderSession ) ;
return ;
}
if ( this . _mask )
{
renderSession . maskManager . pushMask ( this . _mask , renderSession . context ) ;
}
for ( var i = 0 , j = this . children . length ; i < j ; i ++ )
{
var child = this . children [ i ] ;
child . _renderCanvas ( renderSession ) ;
}
if ( this . _mask )
{
renderSession . maskManager . popMask ( renderSession . context ) ;
}
} ;
/ * *
* @ author Mat Groves http : //matgroves.com/ @Doormat23
* /
/ * *
* The Sprite object is the base for all textured objects that are rendered to the screen
*
* @ class Sprite
* @ extends DisplayObjectContainer
* @ constructor
* @ param texture { Texture } The texture for this sprite
2014-04-01 02:02:36 +00:00
*
* A sprite can be created directly from an image like this :
2014-02-28 09:30:53 +00:00
* var sprite = nex PIXI . Sprite . FromImage ( 'assets/image.png' ) ;
* yourStage . addChild ( sprite ) ;
* then obviously don ' t forget to add it to the stage you have already created
* /
PIXI . Sprite = function ( texture )
{
PIXI . DisplayObjectContainer . call ( this ) ;
/ * *
* The anchor sets the origin point of the texture .
* The default is 0 , 0 this means the texture ' s origin is the top left
* Setting than anchor to 0.5 , 0.5 means the textures origin is centred
* Setting the anchor to 1 , 1 would mean the textures origin points will be the bottom right corner
*
* @ property anchor
* @ type Point
* /
this . anchor = new PIXI . Point ( ) ;
/ * *
* The texture that the sprite is using
*
* @ property texture
* @ type Texture
* /
this . texture = texture ;
/ * *
* The width of the sprite ( this is initially set by the texture )
*
* @ property _width
* @ type Number
* @ private
* /
this . _width = 0 ;
/ * *
* The height of the sprite ( this is initially set by the texture )
*
* @ property _height
* @ type Number
* @ private
* /
this . _height = 0 ;
/ * *
* The tint applied to the sprite . This is a hex value
*
* @ property tint
* @ type Number
* @ default 0xFFFFFF
* /
this . tint = 0xFFFFFF ; // * Math.random();
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
/ * *
* The blend mode to be applied to the sprite
*
* @ property blendMode
* @ type Number
* @ default PIXI . blendModes . NORMAL ;
* /
this . blendMode = PIXI . blendModes . NORMAL ;
if ( texture . baseTexture . hasLoaded )
{
this . onTextureUpdate ( ) ;
}
else
{
this . onTextureUpdateBind = this . onTextureUpdate . bind ( this ) ;
this . texture . addEventListener ( 'update' , this . onTextureUpdateBind ) ;
}
this . renderable = true ;
} ;
// constructor
PIXI . Sprite . prototype = Object . create ( PIXI . DisplayObjectContainer . prototype ) ;
PIXI . Sprite . prototype . constructor = PIXI . Sprite ;
/ * *
* The width of the sprite , setting this will actually modify the scale to achieve the value set
*
* @ property width
* @ type Number
* /
Object . defineProperty ( PIXI . Sprite . prototype , 'width' , {
get : function ( ) {
return this . scale . x * this . texture . frame . width ;
} ,
set : function ( value ) {
this . scale . x = value / this . texture . frame . width ;
this . _width = value ;
}
} ) ;
/ * *
* The height of the sprite , setting this will actually modify the scale to achieve the value set
*
* @ property height
* @ type Number
* /
Object . defineProperty ( PIXI . Sprite . prototype , 'height' , {
get : function ( ) {
return this . scale . y * this . texture . frame . height ;
} ,
set : function ( value ) {
this . scale . y = value / this . texture . frame . height ;
this . _height = value ;
}
} ) ;
/ * *
* Sets the texture of the sprite
*
* @ method setTexture
* @ param texture { Texture } The PIXI texture that is displayed by the sprite
* /
PIXI . Sprite . prototype . setTexture = function ( texture )
{
// stop current texture;
if ( this . texture . baseTexture !== texture . baseTexture )
{
this . textureChange = true ;
this . texture = texture ;
}
else
{
this . texture = texture ;
}
this . cachedTint = 0xFFFFFF ;
this . updateFrame = true ;
} ;
/ * *
* When the texture is updated , this event will fire to update the scale and frame
*
* @ method onTextureUpdate
* @ param event
* @ private
* /
PIXI . Sprite . prototype . onTextureUpdate = function ( )
{
// 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 ;
this . updateFrame = true ;
} ;
/ * *
* Returns the framing rectangle of the sprite as a PIXI . Rectangle object
*
* @ method getBounds
* @ param matrix { Matrix } the transformation matrix of the sprite
* @ return { Rectangle } the framing rectangle
* /
PIXI . Sprite . prototype . getBounds = function ( matrix )
{
var width = this . texture . frame . width ;
var height = this . texture . frame . height ;
var w0 = width * ( 1 - this . anchor . x ) ;
var w1 = width * - this . anchor . x ;
var h0 = height * ( 1 - this . anchor . y ) ;
var h1 = height * - this . anchor . y ;
var worldTransform = matrix || this . worldTransform ;
var a = worldTransform . a ;
var b = worldTransform . c ;
var c = worldTransform . b ;
var d = worldTransform . d ;
var tx = worldTransform . tx ;
var ty = worldTransform . ty ;
var x1 = a * w1 + c * h1 + tx ;
var y1 = d * h1 + b * w1 + ty ;
var x2 = a * w0 + c * h1 + tx ;
var y2 = d * h1 + b * w0 + ty ;
var x3 = a * w0 + c * h0 + tx ;
var y3 = d * h0 + b * w0 + ty ;
var x4 = a * w1 + c * h0 + tx ;
var y4 = d * h0 + b * w1 + ty ;
var maxX = - Infinity ;
var maxY = - Infinity ;
var minX = Infinity ;
var minY = Infinity ;
minX = x1 < minX ? x1 : minX ;
minX = x2 < minX ? x2 : minX ;
minX = x3 < minX ? x3 : minX ;
minX = x4 < minX ? x4 : minX ;
minY = y1 < minY ? y1 : minY ;
minY = y2 < minY ? y2 : minY ;
minY = y3 < minY ? y3 : minY ;
minY = y4 < minY ? y4 : minY ;
maxX = x1 > maxX ? x1 : maxX ;
maxX = x2 > maxX ? x2 : maxX ;
maxX = x3 > maxX ? x3 : maxX ;
maxX = x4 > maxX ? x4 : maxX ;
maxY = y1 > maxY ? y1 : maxY ;
maxY = y2 > maxY ? y2 : maxY ;
maxY = y3 > maxY ? y3 : maxY ;
maxY = y4 > maxY ? y4 : maxY ;
var bounds = this . _bounds ;
bounds . x = minX ;
bounds . width = maxX - minX ;
bounds . y = minY ;
bounds . height = maxY - minY ;
// store a reference so that if this function gets called again in the render cycle we do not have to recalculate
this . _currentBounds = bounds ;
return bounds ;
} ;
/ * *
* Renders the object using the WebGL renderer
*
* @ method _renderWebGL
2014-04-01 02:02:36 +00:00
* @ param renderSession { RenderSession }
2014-02-28 09:30:53 +00:00
* @ private
* /
PIXI . Sprite . prototype . _renderWebGL = function ( renderSession )
{
// if the sprite is not visible or the alpha is 0 then no need to render this element
if ( ! this . visible || this . alpha <= 0 ) return ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
var i , j ;
// do a quick check to see if this element has a mask or a filter.
if ( this . _mask || this . _filters )
{
var spriteBatch = renderSession . spriteBatch ;
if ( this . _mask )
{
spriteBatch . stop ( ) ;
renderSession . maskManager . pushMask ( this . mask , renderSession ) ;
spriteBatch . start ( ) ;
}
if ( this . _filters )
{
spriteBatch . flush ( ) ;
renderSession . filterManager . pushFilter ( this . _filterBlock ) ;
}
// add this sprite to the batch
spriteBatch . render ( this ) ;
// now loop through the children and make sure they get rendered
for ( i = 0 , j = this . children . length ; i < j ; i ++ )
{
this . children [ i ] . _renderWebGL ( renderSession ) ;
}
// time to stop the sprite batch as either a mask element or a filter draw will happen next
spriteBatch . stop ( ) ;
if ( this . _filters ) renderSession . filterManager . popFilter ( ) ;
if ( this . _mask ) renderSession . maskManager . popMask ( renderSession ) ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
spriteBatch . start ( ) ;
}
else
{
renderSession . spriteBatch . render ( this ) ;
// simple render children!
for ( i = 0 , j = this . children . length ; i < j ; i ++ )
{
this . children [ i ] . _renderWebGL ( renderSession ) ;
}
}
2014-04-01 02:02:36 +00:00
//TODO check culling
2014-02-28 09:30:53 +00:00
} ;
/ * *
* Renders the object using the Canvas renderer
*
* @ method _renderCanvas
2014-04-01 02:02:36 +00:00
* @ param renderSession { RenderSession }
2014-02-28 09:30:53 +00:00
* @ private
* /
PIXI . Sprite . prototype . _renderCanvas = function ( renderSession )
{
// if the sprite is not visible or the alpha is 0 then no need to render this element
if ( this . visible === false || this . alpha === 0 ) return ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
var frame = this . texture . frame ;
var context = renderSession . context ;
var texture = this . texture ;
if ( this . blendMode !== renderSession . currentBlendMode )
{
renderSession . currentBlendMode = this . blendMode ;
context . globalCompositeOperation = PIXI . blendModesCanvas [ renderSession . currentBlendMode ] ;
}
if ( this . _mask )
{
renderSession . maskManager . pushMask ( this . _mask , renderSession . context ) ;
}
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
//ignore null sources
if ( frame && frame . width && frame . height && texture . baseTexture . source )
{
context . globalAlpha = this . worldAlpha ;
var transform = this . worldTransform ;
// allow for trimming
if ( renderSession . roundPixels )
{
2014-03-04 01:29:04 +00:00
context . setTransform ( transform . a , transform . c , transform . b , transform . d , transform . tx | 0 , transform . ty | 0 ) ;
2014-02-28 09:30:53 +00:00
}
else
{
context . setTransform ( transform . a , transform . c , transform . b , transform . d , transform . tx , transform . ty ) ;
}
//if smoothingEnabled is supported and we need to change the smoothing property for this texture
if ( renderSession . smoothProperty && renderSession . scaleMode !== this . texture . baseTexture . scaleMode ) {
renderSession . scaleMode = this . texture . baseTexture . scaleMode ;
context [ renderSession . smoothProperty ] = ( renderSession . scaleMode === PIXI . scaleModes . LINEAR ) ;
}
if ( this . tint !== 0xFFFFFF )
{
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
if ( this . cachedTint !== this . tint )
{
// no point tinting an image that has not loaded yet!
if ( ! texture . baseTexture . hasLoaded ) return ;
this . cachedTint = this . tint ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
//TODO clean up caching - how to clean up the caches?
this . tintedTexture = PIXI . CanvasTinter . getTintedTexture ( this , this . tint ) ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
}
context . drawImage ( this . tintedTexture ,
0 ,
0 ,
frame . width ,
frame . height ,
( this . anchor . x ) * - frame . width ,
( this . anchor . y ) * - frame . height ,
frame . width ,
frame . height ) ;
}
else
{
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
if ( texture . trim )
{
var trim = texture . trim ;
context . drawImage ( this . texture . baseTexture . source ,
frame . x ,
frame . y ,
frame . width ,
frame . height ,
trim . x - this . anchor . x * trim . width ,
trim . y - this . anchor . y * trim . height ,
frame . width ,
frame . height ) ;
}
else
{
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
context . drawImage ( this . texture . baseTexture . source ,
frame . x ,
frame . y ,
frame . width ,
frame . height ,
( this . anchor . x ) * - frame . width ,
( this . anchor . y ) * - frame . height ,
frame . width ,
frame . height ) ;
}
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
}
}
// OVERWRITE
for ( var i = 0 , j = this . children . length ; i < j ; i ++ )
{
var child = this . children [ i ] ;
child . _renderCanvas ( renderSession ) ;
}
if ( this . _mask )
{
renderSession . maskManager . popMask ( renderSession . context ) ;
}
} ;
// some helper functions..
/ * *
*
* Helper function that creates a sprite that will contain a texture from the TextureCache based on the frameId
* The frame ids are created when a Texture packer file has been loaded
*
* @ method fromFrame
* @ static
* @ param frameId { String } The frame Id of the texture in the cache
* @ return { Sprite } A new Sprite using a texture from the texture cache matching the frameId
* /
PIXI . Sprite . fromFrame = function ( frameId )
{
var texture = PIXI . TextureCache [ frameId ] ;
if ( ! texture ) throw new Error ( 'The frameId "' + frameId + '" does not exist in the texture cache' + this ) ;
return new PIXI . Sprite ( texture ) ;
} ;
/ * *
*
* Helper function that creates a sprite that will contain a texture based on an image url
* If the image is not in the texture cache it will be loaded
*
* @ method fromImage
* @ static
* @ param imageId { String } The image url of the texture
* @ return { Sprite } A new Sprite using a texture from the texture cache matching the image id
* /
PIXI . Sprite . fromImage = function ( imageId , crossorigin , scaleMode )
{
var texture = PIXI . Texture . fromImage ( imageId , crossorigin , scaleMode ) ;
return new PIXI . Sprite ( texture ) ;
} ;
/ * *
* @ author Mat Groves http : //matgroves.com/
* /
/ * *
2014-04-01 02:02:36 +00:00
* The SpriteBatch class is a really fast version of the DisplayObjectContainer
2014-02-28 09:30:53 +00:00
* built solely for speed , so use when you need a lot of sprites or particles .
2014-04-01 02:02:36 +00:00
* And it ' s extremely easy to use :
2014-02-28 09:30:53 +00:00
var container = new PIXI . SpriteBatch ( ) ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
stage . addChild ( container ) ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
for ( var i = 0 ; i < 100 ; i ++ )
{
var sprite = new PIXI . Sprite . fromImage ( "myImage.png" ) ;
container . addChild ( sprite ) ;
}
* And here you have a hundred sprites that will be renderer at the speed of light
*
* @ class SpriteBatch
* @ constructor
* @ param texture { Texture }
* /
PIXI . SpriteBatch = function ( texture )
{
PIXI . DisplayObjectContainer . call ( this ) ;
this . textureThing = texture ;
this . ready = false ;
} ;
PIXI . SpriteBatch . prototype = Object . create ( PIXI . DisplayObjectContainer . prototype ) ;
PIXI . SpriteBatch . constructor = PIXI . SpriteBatch ;
/ *
* Initialises the spriteBatch
*
* @ method initWebGL
* @ param gl { WebGLContext } the current WebGL drawing context
* /
PIXI . SpriteBatch . prototype . initWebGL = function ( gl )
{
// TODO only one needed for the whole engine really?
this . fastSpriteBatch = new PIXI . WebGLFastSpriteBatch ( gl ) ;
this . ready = true ;
} ;
/ *
* Updates the object transform for rendering
*
* @ method updateTransform
* @ private
* /
PIXI . SpriteBatch . prototype . updateTransform = function ( )
{
// TODO dont need to!
PIXI . DisplayObject . prototype . updateTransform . call ( this ) ;
// PIXI.DisplayObjectContainer.prototype.updateTransform.call( this );
} ;
/ * *
* Renders the object using the WebGL renderer
*
* @ method _renderWebGL
2014-04-01 02:02:36 +00:00
* @ param renderSession { RenderSession }
2014-02-28 09:30:53 +00:00
* @ private
* /
PIXI . SpriteBatch . prototype . _renderWebGL = function ( renderSession )
{
if ( ! this . visible || this . alpha <= 0 || ! this . children . length ) return ;
if ( ! this . ready ) this . initWebGL ( renderSession . gl ) ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
renderSession . spriteBatch . stop ( ) ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
renderSession . shaderManager . activateShader ( renderSession . shaderManager . fastShader ) ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
this . fastSpriteBatch . begin ( this , renderSession ) ;
this . fastSpriteBatch . render ( this ) ;
renderSession . shaderManager . activateShader ( renderSession . shaderManager . defaultShader ) ;
renderSession . spriteBatch . start ( ) ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
} ;
/ * *
* Renders the object using the Canvas renderer
*
* @ method _renderCanvas
2014-04-01 02:02:36 +00:00
* @ param renderSession { RenderSession }
2014-02-28 09:30:53 +00:00
* @ private
* /
PIXI . SpriteBatch . prototype . _renderCanvas = function ( renderSession )
{
var context = renderSession . context ;
context . globalAlpha = this . worldAlpha ;
PIXI . DisplayObject . prototype . updateTransform . call ( this ) ;
var transform = this . worldTransform ;
// alow for trimming
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
var isRotated = true ;
for ( var i = 0 ; i < this . children . length ; i ++ ) {
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
var child = this . children [ i ] ;
2014-02-28 18:55:07 +00:00
if ( ! child . visible ) continue ;
2014-02-28 09:30:53 +00:00
var texture = child . texture ;
var frame = texture . frame ;
context . globalAlpha = this . worldAlpha * child . alpha ;
if ( child . rotation % ( Math . PI * 2 ) === 0 )
{
if ( isRotated )
{
context . setTransform ( transform . a , transform . c , transform . b , transform . d , transform . tx , transform . ty ) ;
isRotated = false ;
}
// this is the fastest way to optimise! - if rotation is 0 then we can avoid any kind of setTransform call
context . drawImage ( texture . baseTexture . source ,
frame . x ,
frame . y ,
frame . width ,
frame . height ,
( ( child . anchor . x ) * ( - frame . width * child . scale . x ) + child . position . x + 0.5 ) | 0 ,
( ( child . anchor . y ) * ( - frame . height * child . scale . y ) + child . position . y + 0.5 ) | 0 ,
frame . width * child . scale . x ,
frame . height * child . scale . y ) ;
}
else
{
if ( ! isRotated ) isRotated = true ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
PIXI . DisplayObject . prototype . updateTransform . call ( child ) ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
var childTransform = child . worldTransform ;
// allow for trimming
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
if ( renderSession . roundPixels )
{
2014-03-04 01:29:04 +00:00
context . setTransform ( childTransform . a , childTransform . c , childTransform . b , childTransform . d , childTransform . tx | 0 , childTransform . ty | 0 ) ;
2014-02-28 09:30:53 +00:00
}
else
{
context . setTransform ( childTransform . a , childTransform . c , childTransform . b , childTransform . d , childTransform . tx , childTransform . ty ) ;
}
context . drawImage ( texture . baseTexture . source ,
frame . x ,
frame . y ,
frame . width ,
frame . height ,
( ( child . anchor . x ) * ( - frame . width ) + 0.5 ) | 0 ,
( ( child . anchor . y ) * ( - frame . height ) + 0.5 ) | 0 ,
frame . width ,
frame . height ) ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
}
// context.restore();
}
// context.restore();
} ;
/ * *
* @ author Mat Groves http : //matgroves.com/ @Doormat23
* /
PIXI . FilterBlock = function ( )
{
this . visible = true ;
this . renderable = true ;
} ;
/ * *
* @ author Mat Groves http : //matgroves.com/ @Doormat23
2014-04-01 02:02:36 +00:00
* - Modified by Tom Slezakowski http : //www.tomslezakowski.com @TomSlezakowski (24/03/2014) - Added dropShadowColor.
2014-02-28 09:30:53 +00:00
* /
/ * *
2014-04-01 02:02:36 +00:00
* A Text Object will create a line ( s ) of text . To split a line you can use '\n'
2014-02-28 09:30:53 +00:00
* or add a wordWrap property set to true and and wordWrapWidth property with a value
* in the style object
*
* @ class Text
* @ extends Sprite
* @ constructor
* @ param text { String } The copy that you would like the text to display
* @ param [ style ] { Object } The style parameters
* @ param [ style . font ] { String } default 'bold 20px Arial' The style and size of the font
* @ param [ style . fill = 'black' ] { String | Number } A canvas fillstyle that will be used on the text e . g 'red' , '#00FF00'
* @ param [ style . align = 'left' ] { String } Alignment for multiline text ( 'left' , 'center' or 'right' ) , does not affect single line text
* @ param [ style . stroke ] { String | Number } A canvas fillstyle that will be used on the text stroke e . g 'blue' , '#FCFF00'
* @ param [ style . strokeThickness = 0 ] { Number } A number that represents the thickness of the stroke . Default is 0 ( no stroke )
* @ param [ style . wordWrap = false ] { Boolean } Indicates if word wrap should be used
* @ param [ style . wordWrapWidth = 100 ] { Number } The width at which text will wrap , it needs wordWrap to be set to true
2014-04-01 02:02:36 +00:00
* @ param [ style . dropShadow = false ] { Boolean } Set a drop shadow for the text
* @ param [ style . dropShadowColor = '#000000' ] { String } A fill style to be used on the dropshadow e . g 'red' , '#00FF00'
* @ param [ style . dropShadowAngle = Math . PI / 4 ] { Number } Set a angle of the drop shadow
* @ param [ style . dropShadowDistance = 5 ] { Number } Set a distance of the drop shadow
2014-02-28 09:30:53 +00:00
* /
PIXI . Text = function ( text , style )
{
/ * *
* The canvas element that everything is drawn to
*
* @ property canvas
* @ type HTMLCanvasElement
* /
this . canvas = document . createElement ( 'canvas' ) ;
/ * *
* The canvas 2 d context that everything is drawn with
* @ property context
* @ type HTMLCanvasElement 2 d Context
* /
this . context = this . canvas . getContext ( '2d' ) ;
PIXI . Sprite . call ( this , PIXI . Texture . fromCanvas ( this . canvas ) ) ;
this . setText ( text ) ;
this . setStyle ( style ) ;
this . updateText ( ) ;
this . dirty = false ;
} ;
// constructor
PIXI . Text . prototype = Object . create ( PIXI . Sprite . prototype ) ;
PIXI . Text . prototype . constructor = PIXI . Text ;
/ * *
* Set the style of the text
*
* @ method setStyle
* @ param [ style ] { Object } The style parameters
* @ param [ style . font = 'bold 20pt Arial' ] { String } The style and size of the font
* @ param [ style . fill = 'black' ] { Object } A canvas fillstyle that will be used on the text eg 'red' , '#00FF00'
* @ param [ style . align = 'left' ] { String } Alignment for multiline text ( 'left' , 'center' or 'right' ) , does not affect single line text
* @ param [ style . stroke = 'black' ] { String } A canvas fillstyle that will be used on the text stroke eg 'blue' , '#FCFF00'
* @ param [ style . strokeThickness = 0 ] { Number } A number that represents the thickness of the stroke . Default is 0 ( no stroke )
* @ param [ style . wordWrap = false ] { Boolean } Indicates if word wrap should be used
* @ param [ style . wordWrapWidth = 100 ] { Number } The width at which text will wrap
2014-04-01 02:02:36 +00:00
* @ param [ style . dropShadow = false ] { Boolean } Set a drop shadow for the text
* @ param [ style . dropShadowColor = '#000000' ] { String } A fill style to be used on the dropshadow e . g 'red' , '#00FF00'
* @ param [ style . dropShadowAngle = Math . PI / 4 ] { Number } Set a angle of the drop shadow
* @ param [ style . dropShadowDistance = 5 ] { Number } Set a distance of the drop shadow
2014-02-28 09:30:53 +00:00
* /
PIXI . Text . prototype . setStyle = function ( style )
{
style = style || { } ;
style . font = style . font || 'bold 20pt Arial' ;
style . fill = style . fill || 'black' ;
style . align = style . align || 'left' ;
style . stroke = style . stroke || 'black' ; //provide a default, see: https://github.com/GoodBoyDigital/pixi.js/issues/136
style . strokeThickness = style . strokeThickness || 0 ;
style . wordWrap = style . wordWrap || false ;
style . wordWrapWidth = style . wordWrapWidth || 100 ;
2014-04-01 02:02:36 +00:00
style . wordWrapWidth = style . wordWrapWidth || 100 ;
style . dropShadow = style . dropShadow || false ;
style . dropShadowAngle = style . dropShadowAngle || Math . PI / 6 ;
style . dropShadowDistance = style . dropShadowDistance || 4 ;
style . dropShadowColor = style . dropShadowColor || 'black' ;
2014-02-28 09:30:53 +00:00
this . style = style ;
this . dirty = true ;
} ;
/ * *
* Set the copy for the text object . To split a line you can use '\n'
*
* @ method setText
* @ param { String } text The copy that you would like the text to display
* /
PIXI . Text . prototype . setText = function ( text )
{
this . text = text . toString ( ) || ' ' ;
this . dirty = true ;
} ;
/ * *
* Renders text and updates it when needed
*
* @ method updateText
* @ private
* /
PIXI . Text . prototype . updateText = function ( )
{
this . context . font = this . style . font ;
var outputText = this . text ;
// word wrap
// preserve original text
if ( this . style . wordWrap ) outputText = this . wordWrap ( this . text ) ;
//split text into lines
var lines = outputText . split ( /(?:\r\n|\r|\n)/ ) ;
//calculate text width
var lineWidths = [ ] ;
var maxLineWidth = 0 ;
for ( var i = 0 ; i < lines . length ; i ++ )
{
var lineWidth = this . context . measureText ( lines [ i ] ) . width ;
lineWidths [ i ] = lineWidth ;
maxLineWidth = Math . max ( maxLineWidth , lineWidth ) ;
}
2014-04-01 02:02:36 +00:00
var width = maxLineWidth + this . style . strokeThickness ;
if ( this . style . dropShadow ) width += this . style . dropShadowDistance ;
this . canvas . width = width ;
2014-02-28 09:30:53 +00:00
//calculate text height
var lineHeight = this . determineFontHeight ( 'font: ' + this . style . font + ';' ) + this . style . strokeThickness ;
2014-04-01 02:02:36 +00:00
var height = lineHeight * lines . length ;
if ( this . style . dropShadow ) height += this . style . dropShadowDistance ;
2014-02-28 09:30:53 +00:00
2014-04-01 02:02:36 +00:00
this . canvas . height = height ;
2014-03-28 01:42:49 +00:00
2014-04-01 02:02:36 +00:00
if ( navigator . isCocoonJS ) this . context . clearRect ( 0 , 0 , this . canvas . width , this . canvas . height ) ;
2014-02-28 09:30:53 +00:00
this . context . font = this . style . font ;
this . context . strokeStyle = this . style . stroke ;
this . context . lineWidth = this . style . strokeThickness ;
this . context . textBaseline = 'top' ;
2014-04-01 02:02:36 +00:00
var linePositionX ;
var linePositionY ;
if ( this . style . dropShadow )
{
this . context . fillStyle = this . style . dropShadowColor ;
var xShadowOffset = Math . sin ( this . style . dropShadowAngle ) * this . style . dropShadowDistance ;
var yShadowOffset = Math . cos ( this . style . dropShadowAngle ) * this . style . dropShadowDistance ;
for ( i = 0 ; i < lines . length ; i ++ )
{
linePositionX = this . style . strokeThickness / 2 ;
linePositionY = this . style . strokeThickness / 2 + i * lineHeight ;
if ( this . style . align === 'right' )
{
linePositionX += maxLineWidth - lineWidths [ i ] ;
}
else if ( this . style . align === 'center' )
{
linePositionX += ( maxLineWidth - lineWidths [ i ] ) / 2 ;
}
if ( this . style . fill )
{
this . context . fillText ( lines [ i ] , linePositionX + xShadowOffset , linePositionY + yShadowOffset ) ;
}
// if(dropShadow)
}
}
//set canvas text styles
this . context . fillStyle = this . style . fill ;
2014-02-28 09:30:53 +00:00
//draw lines line by line
for ( i = 0 ; i < lines . length ; i ++ )
{
2014-04-01 02:02:36 +00:00
linePositionX = this . style . strokeThickness / 2 ;
linePositionY = this . style . strokeThickness / 2 + i * lineHeight ;
2014-02-28 09:30:53 +00:00
if ( this . style . align === 'right' )
{
2014-04-01 02:02:36 +00:00
linePositionX += maxLineWidth - lineWidths [ i ] ;
2014-02-28 09:30:53 +00:00
}
else if ( this . style . align === 'center' )
{
2014-04-01 02:02:36 +00:00
linePositionX += ( maxLineWidth - lineWidths [ i ] ) / 2 ;
2014-02-28 09:30:53 +00:00
}
if ( this . style . stroke && this . style . strokeThickness )
{
2014-04-01 02:02:36 +00:00
this . context . strokeText ( lines [ i ] , linePositionX , linePositionY ) ;
2014-02-28 09:30:53 +00:00
}
if ( this . style . fill )
{
2014-04-01 02:02:36 +00:00
this . context . fillText ( lines [ i ] , linePositionX , linePositionY ) ;
2014-02-28 09:30:53 +00:00
}
2014-04-01 02:02:36 +00:00
// if(dropShadow)
2014-02-28 09:30:53 +00:00
}
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
this . updateTexture ( ) ;
} ;
/ * *
* Updates texture size based on canvas size
*
* @ method updateTexture
* @ private
* /
PIXI . Text . prototype . updateTexture = function ( )
{
this . texture . baseTexture . width = this . canvas . width ;
this . texture . baseTexture . height = this . canvas . height ;
this . texture . frame . width = this . canvas . width ;
this . texture . frame . height = this . canvas . height ;
this . _width = this . canvas . width ;
this . _height = this . canvas . height ;
this . requiresUpdate = true ;
} ;
/ * *
* Renders the object using the WebGL renderer
*
* @ method _renderWebGL
2014-04-01 02:02:36 +00:00
* @ param renderSession { RenderSession }
2014-02-28 09:30:53 +00:00
* @ private
* /
PIXI . Text . prototype . _renderWebGL = function ( renderSession )
{
if ( this . requiresUpdate )
{
this . requiresUpdate = false ;
PIXI . updateWebGLTexture ( this . texture . baseTexture , renderSession . gl ) ;
}
PIXI . Sprite . prototype . _renderWebGL . call ( this , renderSession ) ;
} ;
/ * *
* Updates the transform of this object
*
* @ method updateTransform
* @ private
* /
PIXI . Text . prototype . updateTransform = function ( )
{
if ( this . dirty )
{
this . updateText ( ) ;
this . dirty = false ;
}
PIXI . Sprite . prototype . updateTransform . call ( this ) ;
} ;
/ *
* http : //stackoverflow.com/users/34441/ellisbben
* great solution to the problem !
* returns the height of the given font
*
* @ method determineFontHeight
* @ param fontStyle { Object }
* @ private
* /
PIXI . Text . prototype . determineFontHeight = function ( fontStyle )
{
// build a little reference dictionary so if the font style has been used return a
// cached version...
var result = PIXI . Text . heightCache [ fontStyle ] ;
if ( ! result )
{
var body = document . getElementsByTagName ( 'body' ) [ 0 ] ;
var dummy = document . createElement ( 'div' ) ;
var dummyText = document . createTextNode ( 'M' ) ;
dummy . appendChild ( dummyText ) ;
dummy . setAttribute ( 'style' , fontStyle + ';position:absolute;top:0;left:0' ) ;
body . appendChild ( dummy ) ;
result = dummy . offsetHeight ;
PIXI . Text . heightCache [ fontStyle ] = result ;
body . removeChild ( dummy ) ;
}
return result ;
} ;
/ * *
* Applies newlines to a string to have it optimally fit into the horizontal
* bounds set by the Text object ' s wordWrapWidth property .
*
* @ method wordWrap
* @ param text { String }
* @ private
* /
PIXI . Text . prototype . wordWrap = function ( text )
{
// Greedy wrapping algorithm that will wrap words as the line grows longer
// than its horizontal bounds.
var result = '' ;
var lines = text . split ( '\n' ) ;
for ( var i = 0 ; i < lines . length ; i ++ )
{
var spaceLeft = this . style . wordWrapWidth ;
var words = lines [ i ] . split ( ' ' ) ;
for ( var j = 0 ; j < words . length ; j ++ )
{
var wordWidth = this . context . measureText ( words [ j ] ) . width ;
var wordWidthWithSpace = wordWidth + this . context . measureText ( ' ' ) . width ;
if ( wordWidthWithSpace > spaceLeft )
{
// Skip printing the newline if it's the first word of the line that is
// greater than the word wrap width.
if ( j > 0 )
{
result += '\n' ;
}
result += words [ j ] + ' ' ;
spaceLeft = this . style . wordWrapWidth - wordWidth ;
}
else
{
spaceLeft -= wordWidthWithSpace ;
result += words [ j ] + ' ' ;
}
}
if ( i < lines . length - 1 )
{
result += '\n' ;
}
}
return result ;
} ;
/ * *
* Destroys this text object
*
* @ method destroy
* @ param destroyTexture { Boolean }
* /
PIXI . Text . prototype . destroy = function ( destroyTexture )
{
if ( destroyTexture )
{
this . texture . destroy ( ) ;
}
} ;
PIXI . Text . heightCache = { } ;
/ * *
* @ author Mat Groves http : //matgroves.com/ @Doormat23
* /
/ * *
* A Text Object will create a line ( s ) of text using bitmap font . To split a line you can use '\n' , '\r' or '\r\n'
* You can generate the fnt files using
* http : //www.angelcode.com/products/bmfont/ for windows or
* http : //www.bmglyph.com/ for mac.
*
* @ class BitmapText
* @ extends DisplayObjectContainer
* @ constructor
* @ param text { String } The copy that you would like the text to display
* @ param style { Object } The style parameters
* @ param style . font { String } The size ( optional ) and bitmap font id ( required ) eq 'Arial' or '20px Arial' ( must have loaded previously )
* @ param [ style . align = 'left' ] { String } Alignment for multiline text ( 'left' , 'center' or 'right' ) , does not affect single line text
* /
PIXI . BitmapText = function ( text , style )
{
PIXI . DisplayObjectContainer . call ( this ) ;
this . _pool = [ ] ;
this . setText ( text ) ;
this . setStyle ( style ) ;
this . updateText ( ) ;
this . dirty = false ;
} ;
// constructor
PIXI . BitmapText . prototype = Object . create ( PIXI . DisplayObjectContainer . prototype ) ;
PIXI . BitmapText . prototype . constructor = PIXI . BitmapText ;
/ * *
* Set the copy for the text object
*
* @ method setText
* @ param text { String } The copy that you would like the text to display
* /
PIXI . BitmapText . prototype . setText = function ( text )
{
this . text = text || ' ' ;
this . dirty = true ;
} ;
/ * *
* Set the style of the text
* style . font { String } The size ( optional ) and bitmap font id ( required ) eq 'Arial' or '20px Arial' ( must have loaded previously )
* [ style . align = 'left' ] { String } Alignment for multiline text ( 'left' , 'center' or 'right' ) , does not affect single line text
*
* @ method setStyle
* @ param style { Object } The style parameters , contained as properties of an object
* /
PIXI . BitmapText . prototype . setStyle = function ( style )
{
style = style || { } ;
style . align = style . align || 'left' ;
this . style = style ;
var font = style . font . split ( ' ' ) ;
this . fontName = font [ font . length - 1 ] ;
this . fontSize = font . length >= 2 ? parseInt ( font [ font . length - 2 ] , 10 ) : PIXI . BitmapText . fonts [ this . fontName ] . size ;
this . dirty = true ;
this . tint = style . tint ;
} ;
/ * *
* Renders text and updates it when needed
*
* @ method updateText
* @ private
* /
PIXI . BitmapText . prototype . updateText = function ( )
{
var data = PIXI . BitmapText . fonts [ this . fontName ] ;
var pos = new PIXI . Point ( ) ;
var prevCharCode = null ;
var chars = [ ] ;
var maxLineWidth = 0 ;
var lineWidths = [ ] ;
var line = 0 ;
var scale = this . fontSize / data . size ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
for ( var i = 0 ; i < this . text . length ; i ++ )
{
var charCode = this . text . charCodeAt ( i ) ;
if ( /(?:\r\n|\r|\n)/ . test ( this . text . charAt ( i ) ) )
{
lineWidths . push ( pos . x ) ;
maxLineWidth = Math . max ( maxLineWidth , pos . x ) ;
line ++ ;
pos . x = 0 ;
pos . y += data . lineHeight ;
prevCharCode = null ;
continue ;
}
var charData = data . chars [ charCode ] ;
if ( ! charData ) continue ;
if ( prevCharCode && charData [ prevCharCode ] )
{
pos . x += charData . kerning [ prevCharCode ] ;
}
chars . push ( { texture : charData . texture , line : line , charCode : charCode , position : new PIXI . Point ( pos . x + charData . xOffset , pos . y + charData . yOffset ) } ) ;
pos . x += charData . xAdvance ;
prevCharCode = charCode ;
}
lineWidths . push ( pos . x ) ;
maxLineWidth = Math . max ( maxLineWidth , pos . x ) ;
var lineAlignOffsets = [ ] ;
for ( i = 0 ; i <= line ; i ++ )
{
var alignOffset = 0 ;
if ( this . style . align === 'right' )
{
alignOffset = maxLineWidth - lineWidths [ i ] ;
}
else if ( this . style . align === 'center' )
{
alignOffset = ( maxLineWidth - lineWidths [ i ] ) / 2 ;
}
lineAlignOffsets . push ( alignOffset ) ;
}
var lenChildren = this . children . length ;
var lenChars = chars . length ;
var tint = this . tint || 0xFFFFFF ;
for ( i = 0 ; i < lenChars ; i ++ )
{
var c = i < lenChildren ? this . children [ i ] : this . _pool . pop ( ) ; // get old child if have. if not - take from pool.
if ( c ) c . setTexture ( chars [ i ] . texture ) ; // check if got one before.
else c = new PIXI . Sprite ( chars [ i ] . texture ) ; // if no create new one.
c . position . x = ( chars [ i ] . position . x + lineAlignOffsets [ chars [ i ] . line ] ) * scale ;
c . position . y = chars [ i ] . position . y * scale ;
c . scale . x = c . scale . y = scale ;
c . tint = tint ;
if ( ! c . parent ) this . addChild ( c ) ;
}
// remove unnecessary children.
// and put their into the pool.
while ( this . children . length > lenChars )
{
var child = this . getChildAt ( this . children . length - 1 ) ;
this . _pool . push ( child ) ;
this . removeChild ( child ) ;
}
/ * *
* [ read - only ] The width of the overall text , different from fontSize ,
* which is defined in the style object
*
* @ property textWidth
* @ type Number
* /
this . textWidth = maxLineWidth * scale ;
/ * *
* [ read - only ] The height of the overall text , different from fontSize ,
* which is defined in the style object
*
* @ property textHeight
* @ type Number
* /
this . textHeight = ( pos . y + data . lineHeight ) * scale ;
} ;
/ * *
* Updates the transform of this object
*
* @ method updateTransform
* @ private
* /
PIXI . BitmapText . prototype . updateTransform = function ( )
{
if ( this . dirty )
{
this . updateText ( ) ;
this . dirty = false ;
}
PIXI . DisplayObjectContainer . prototype . updateTransform . call ( this ) ;
} ;
PIXI . BitmapText . fonts = { } ;
/ * *
* @ author Mat Groves http : //matgroves.com/ @Doormat23
* /
/ * *
* A Stage represents the root of the display tree . Everything connected to the stage is rendered
*
* @ class Stage
* @ extends DisplayObjectContainer
* @ constructor
* @ param backgroundColor { Number } the background color of the stage , you have to pass this in is in hex format
* like : 0xFFFFFF for white
2014-04-01 02:02:36 +00:00
*
* Creating a stage is a mandatory process when you use Pixi , which is as simple as this :
2014-02-28 09:30:53 +00:00
* var stage = new PIXI . Stage ( 0xFFFFFF ) ;
* where the parameter given is the background colour of the stage , in hex
* you will use this stage instance to add your sprites to it and therefore to the renderer
2014-04-01 02:02:36 +00:00
* Here is how to add a sprite to the stage :
2014-02-28 09:30:53 +00:00
* stage . addChild ( sprite ) ;
* /
PIXI . Stage = function ( backgroundColor )
{
PIXI . DisplayObjectContainer . call ( this ) ;
/ * *
* [ read - only ] Current transform of the object based on world ( parent ) factors
*
* @ property worldTransform
* @ type Mat3
* @ readOnly
* @ private
* /
this . worldTransform = new PIXI . Matrix ( ) ;
/ * *
* Whether or not the stage is interactive
*
* @ property interactive
* @ type Boolean
* /
this . interactive = true ;
/ * *
* The interaction manage for this stage , manages all interactive activity on the stage
*
* @ property interactive
* @ type InteractionManager
* /
this . interactionManager = new PIXI . InteractionManager ( this ) ;
/ * *
* Whether the stage is dirty and needs to have interactions updated
*
* @ property dirty
* @ type Boolean
* @ private
* /
this . dirty = true ;
//the stage is its own stage
this . stage = this ;
//optimize hit detection a bit
this . stage . hitArea = new PIXI . Rectangle ( 0 , 0 , 100000 , 100000 ) ;
this . setBackgroundColor ( backgroundColor ) ;
} ;
// constructor
PIXI . Stage . prototype = Object . create ( PIXI . DisplayObjectContainer . prototype ) ;
PIXI . Stage . prototype . constructor = PIXI . Stage ;
/ * *
* Sets another DOM element which can receive mouse / touch interactions instead of the default Canvas element .
* This is useful for when you have other DOM elements on top of the Canvas element .
*
* @ method setInteractionDelegate
* @ param domElement { DOMElement } This new domElement which will receive mouse / touch events
* /
PIXI . Stage . prototype . setInteractionDelegate = function ( domElement )
{
this . interactionManager . setTargetDomElement ( domElement ) ;
} ;
/ *
* Updates the object transform for rendering
*
* @ method updateTransform
* @ private
* /
PIXI . Stage . prototype . updateTransform = function ( )
{
this . worldAlpha = 1 ;
for ( var i = 0 , j = this . children . length ; i < j ; i ++ )
{
this . children [ i ] . updateTransform ( ) ;
}
if ( this . dirty )
{
this . dirty = false ;
// update interactive!
this . interactionManager . dirty = true ;
}
if ( this . interactive ) this . interactionManager . update ( ) ;
} ;
/ * *
* Sets the background color for the stage
*
* @ method setBackgroundColor
* @ param backgroundColor { Number } the color of the background , easiest way to pass this in is in hex format
* like : 0xFFFFFF for white
* /
PIXI . Stage . prototype . setBackgroundColor = function ( backgroundColor )
{
this . backgroundColor = backgroundColor || 0x000000 ;
this . backgroundColorSplit = PIXI . hex2rgb ( this . backgroundColor ) ;
var hex = this . backgroundColor . toString ( 16 ) ;
hex = '000000' . substr ( 0 , 6 - hex . length ) + hex ;
this . backgroundColorString = '#' + hex ;
} ;
/ * *
* This will return the point containing global coords of the mouse .
*
* @ method getMousePosition
* @ return { Point } The point containing the coords of the global InteractionData position .
* /
PIXI . Stage . prototype . getMousePosition = function ( )
{
return this . interactionManager . mouse . global ;
} ;
/ * *
* @ author Mat Groves http : //matgroves.com/ @Doormat23
* /
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
// http://paulirish.com/2011/requestanimationframe-for-smart-animating/
// http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating
// requestAnimationFrame polyfill by Erik Möller. fixes from Paul Irish and Tino Zijdel
// MIT license
/ * *
* A polyfill for requestAnimationFrame
2014-04-01 02:02:36 +00:00
* You can actually use both requestAnimationFrame and requestAnimFrame ,
2014-02-28 09:30:53 +00:00
* you will still benefit from the polyfill
*
* @ method requestAnimationFrame
* /
/ * *
* A polyfill for cancelAnimationFrame
*
* @ method cancelAnimationFrame
* /
var lastTime = 0 ;
var vendors = [ 'ms' , 'moz' , 'webkit' , 'o' ] ;
for ( var x = 0 ; x < vendors . length && ! window . requestAnimationFrame ; ++ x ) {
window . requestAnimationFrame = window [ vendors [ x ] + 'RequestAnimationFrame' ] ;
window . cancelAnimationFrame = window [ vendors [ x ] + 'CancelAnimationFrame' ] ||
window [ vendors [ x ] + 'CancelRequestAnimationFrame' ] ;
}
if ( ! window . requestAnimationFrame ) {
window . requestAnimationFrame = function ( callback ) {
var currTime = new Date ( ) . getTime ( ) ;
var timeToCall = Math . max ( 0 , 16 - ( currTime - lastTime ) ) ;
var id = window . setTimeout ( function ( ) { callback ( currTime + timeToCall ) ; } ,
timeToCall ) ;
lastTime = currTime + timeToCall ;
return id ;
} ;
}
if ( ! window . cancelAnimationFrame ) {
window . cancelAnimationFrame = function ( id ) {
clearTimeout ( id ) ;
} ;
}
window . requestAnimFrame = window . requestAnimationFrame ;
/ * *
* Converts a hex color number to an [ R , G , B ] array
*
* @ method hex2rgb
* @ param hex { Number }
* /
PIXI . hex2rgb = function ( hex ) {
return [ ( hex >> 16 & 0xFF ) / 255 , ( hex >> 8 & 0xFF ) / 255 , ( hex & 0xFF ) / 255 ] ;
} ;
/ * *
* Converts a color as an [ R , G , B ] array to a hex number
*
* @ method rgb2hex
* @ param rgb { Array }
* /
PIXI . rgb2hex = function ( rgb ) {
return ( ( rgb [ 0 ] * 255 << 16 ) + ( rgb [ 1 ] * 255 << 8 ) + rgb [ 2 ] * 255 ) ;
} ;
/ * *
* A polyfill for Function . prototype . bind
*
* @ method bind
* /
if ( typeof Function . prototype . bind !== 'function' ) {
Function . prototype . bind = ( function ( ) {
var slice = Array . prototype . slice ;
return function ( thisArg ) {
var target = this , boundArgs = slice . call ( arguments , 1 ) ;
if ( typeof target !== 'function' ) throw new TypeError ( ) ;
function bound ( ) {
var args = boundArgs . concat ( slice . call ( arguments ) ) ;
target . apply ( this instanceof bound ? this : thisArg , args ) ;
}
bound . prototype = ( function F ( proto ) {
if ( proto ) F . prototype = proto ;
if ( ! ( this instanceof F ) ) return new F ( ) ;
} ) ( target . prototype ) ;
return bound ;
} ;
} ) ( ) ;
}
/ * *
* A wrapper for ajax requests to be handled cross browser
*
* @ class AjaxRequest
* @ constructor
* /
PIXI . AjaxRequest = function ( )
{
var activexmodes = [ 'Msxml2.XMLHTTP.6.0' , 'Msxml2.XMLHTTP.3.0' , 'Microsoft.XMLHTTP' ] ; //activeX versions to check for in IE
if ( window . ActiveXObject )
{ //Test for support for ActiveXObject in IE first (as XMLHttpRequest in IE7 is broken)
for ( var i = 0 ; i < activexmodes . length ; i ++ )
{
try {
return new window . ActiveXObject ( activexmodes [ i ] ) ;
}
catch ( e ) {
//suppress error
}
}
}
else if ( window . XMLHttpRequest ) // if Mozilla, Safari etc
{
return new window . XMLHttpRequest ( ) ;
}
else
{
return false ;
}
} ;
/ *
PIXI . packColorRGBA = function ( r , g , b , a ) //r, g, b, a)
{
// console.log(r, b, c, d)
return ( Math . floor ( ( r ) * 63 ) << 18 ) | ( Math . floor ( ( g ) * 63 ) << 12 ) | ( Math . floor ( ( b ) * 63 ) << 6 ) ; // | (Math.floor((a)*63))
// i = i | (Math.floor((a)*63));
// return i;
// var r = (i / 262144.0 ) / 64;
// var g = (i / 4096.0)%64 / 64;
// var b = (i / 64.0)%64 / 64;
// var a = (i)%64 / 64;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
// console.log(r, g, b, a);
// return i;
} ;
* /
/ *
PIXI . packColorRGB = function ( r , g , b ) //r, g, b, a)
{
return ( Math . floor ( ( r ) * 255 ) << 16 ) | ( Math . floor ( ( g ) * 255 ) << 8 ) | ( Math . floor ( ( b ) * 255 ) ) ;
} ;
PIXI . unpackColorRGB = function ( r , g , b ) //r, g, b, a)
{
return ( Math . floor ( ( r ) * 255 ) << 16 ) | ( Math . floor ( ( g ) * 255 ) << 8 ) | ( Math . floor ( ( b ) * 255 ) ) ;
} ;
* /
/ * *
* Checks whether the Canvas BlendModes are supported by the current browser
*
* @ method canUseNewCanvasBlendModes
* @ return { Boolean } whether they are supported
* /
PIXI . canUseNewCanvasBlendModes = function ( )
{
var canvas = document . createElement ( 'canvas' ) ;
canvas . width = 1 ;
canvas . height = 1 ;
var context = canvas . getContext ( '2d' ) ;
context . fillStyle = '#000' ;
context . fillRect ( 0 , 0 , 1 , 1 ) ;
context . globalCompositeOperation = 'multiply' ;
context . fillStyle = '#fff' ;
context . fillRect ( 0 , 0 , 1 , 1 ) ;
return context . getImageData ( 0 , 0 , 1 , 1 ) . data [ 0 ] === 0 ;
} ;
/ * *
* Given a number , this function returns the closest number that is a power of two
* this function is taken from Starling Framework as its pretty neat ; )
*
* @ method getNextPowerOfTwo
* @ param number { Number }
* @ return { Number } the closest number that is a power of two
* /
PIXI . getNextPowerOfTwo = function ( number )
{
if ( number > 0 && ( number & ( number - 1 ) ) === 0 ) // see: http://goo.gl/D9kPj
return number ;
else
{
var result = 1 ;
while ( result < number ) result <<= 1 ;
return result ;
}
} ;
/ * *
* @ author Mat Groves http : //matgroves.com/ @Doormat23
* /
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
/ * *
* https : //github.com/mrdoob/eventtarget.js/
* THankS mr DOob !
* /
/ * *
* Adds event emitter functionality to a class
*
* @ class EventTarget
* @ example
* function MyEmitter ( ) {
* PIXI . EventTarget . call ( this ) ; //mixes in event target stuff
* }
*
* var em = new MyEmitter ( ) ;
* em . emit ( { type : 'eventName' , data : 'some data' } ) ;
* /
PIXI . EventTarget = function ( ) {
/ * *
* Holds all the listeners
*
2014-04-01 02:02:36 +00:00
* @ property listeners
2014-02-28 09:30:53 +00:00
* @ type Object
* /
var listeners = { } ;
/ * *
* Adds a listener for a specific event
*
* @ method addEventListener
* @ param type { string } A string representing the event type to listen for .
* @ param listener { function } The callback function that will be fired when the event occurs
* /
this . addEventListener = this . on = function ( type , listener ) {
if ( listeners [ type ] === undefined ) {
listeners [ type ] = [ ] ;
}
if ( listeners [ type ] . indexOf ( listener ) === - 1 ) {
listeners [ type ] . push ( listener ) ;
}
} ;
/ * *
* Fires the event , ie pretends that the event has happened
*
* @ method dispatchEvent
* @ param event { Event } the event object
* /
this . dispatchEvent = this . emit = function ( event ) {
if ( ! listeners [ event . type ] || ! listeners [ event . type ] . length ) {
return ;
}
for ( var i = 0 , l = listeners [ event . type ] . length ; i < l ; i ++ ) {
listeners [ event . type ] [ i ] ( event ) ;
}
} ;
/ * *
* Removes the specified listener that was assigned to the specified event type
*
* @ method removeEventListener
* @ param type { string } A string representing the event type which will have its listener removed
* @ param listener { function } The callback function that was be fired when the event occured
* /
this . removeEventListener = this . off = function ( type , listener ) {
var index = listeners [ type ] . indexOf ( listener ) ;
if ( index !== - 1 ) {
listeners [ type ] . splice ( index , 1 ) ;
}
} ;
/ * *
* Removes all the listeners that were active for the specified event type
*
* @ method removeAllEventListeners
* @ param type { string } A string representing the event type which will have all its listeners removed
* /
this . removeAllEventListeners = function ( type ) {
var a = listeners [ type ] ;
if ( a )
a . length = 0 ;
} ;
} ;
/ *
PolyK library
url : http : //polyk.ivank.net
Released under MIT licence .
Copyright ( c ) 2012 Ivan Kuckir
Permission is hereby granted , free of charge , to any person
obtaining a copy of this software and associated documentation
files ( the "Software" ) , to deal in the Software without
restriction , including without limitation the rights to use ,
copy , modify , merge , publish , distribute , sublicense , and / or sell
copies of the Software , and to permit persons to whom the
Software is furnished to do so , subject to the following
conditions :
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software .
THE SOFTWARE IS PROVIDED "AS IS" , WITHOUT WARRANTY OF ANY KIND ,
EXPRESS OR IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY , FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT . IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER LIABILITY ,
WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING
FROM , OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE .
This is an amazing lib !
slightly modified by Mat Groves ( matgroves . com ) ;
* /
/ * *
* Based on the Polyk library http : //polyk.ivank.net released under MIT licence.
* This is an amazing lib !
* slightly modified by Mat Groves ( matgroves . com ) ;
* @ class PolyK
*
* /
PIXI . PolyK = { } ;
/ * *
* Triangulates shapes for webGL graphic fills
*
* @ method Triangulate
2014-04-01 02:02:36 +00:00
*
2014-02-28 09:30:53 +00:00
* /
PIXI . PolyK . Triangulate = function ( p )
{
var sign = true ;
var n = p . length >> 1 ;
if ( n < 3 ) return [ ] ;
var tgs = [ ] ;
var avl = [ ] ;
for ( var i = 0 ; i < n ; i ++ ) avl . push ( i ) ;
i = 0 ;
var al = n ;
while ( al > 3 )
{
var i0 = avl [ ( i + 0 ) % al ] ;
var i1 = avl [ ( i + 1 ) % al ] ;
var i2 = avl [ ( i + 2 ) % al ] ;
var ax = p [ 2 * i0 ] , ay = p [ 2 * i0 + 1 ] ;
var bx = p [ 2 * i1 ] , by = p [ 2 * i1 + 1 ] ;
var cx = p [ 2 * i2 ] , cy = p [ 2 * i2 + 1 ] ;
var earFound = false ;
if ( PIXI . PolyK . _convex ( ax , ay , bx , by , cx , cy , sign ) )
{
earFound = true ;
for ( var j = 0 ; j < al ; j ++ )
{
var vi = avl [ j ] ;
if ( vi === i0 || vi === i1 || vi === i2 ) continue ;
if ( PIXI . PolyK . _PointInTriangle ( p [ 2 * vi ] , p [ 2 * vi + 1 ] , ax , ay , bx , by , cx , cy ) ) {
earFound = false ;
break ;
}
}
}
if ( earFound )
{
tgs . push ( i0 , i1 , i2 ) ;
avl . splice ( ( i + 1 ) % al , 1 ) ;
al -- ;
i = 0 ;
}
else if ( i ++ > 3 * al )
{
// need to flip flip reverse it!
// reset!
if ( sign )
{
tgs = [ ] ;
avl = [ ] ;
for ( i = 0 ; i < n ; i ++ ) avl . push ( i ) ;
i = 0 ;
al = n ;
sign = false ;
}
else
{
window . console . log ( "PIXI Warning: shape too complex to fill" ) ;
return [ ] ;
}
}
}
tgs . push ( avl [ 0 ] , avl [ 1 ] , avl [ 2 ] ) ;
return tgs ;
} ;
/ * *
* Checks whether a point is within a triangle
*
* @ method _PointInTriangle
* @ param px { Number } x coordinate of the point to test
* @ param py { Number } y coordinate of the point to test
* @ param ax { Number } x coordinate of the a point of the triangle
* @ param ay { Number } y coordinate of the a point of the triangle
* @ param bx { Number } x coordinate of the b point of the triangle
* @ param by { Number } y coordinate of the b point of the triangle
* @ param cx { Number } x coordinate of the c point of the triangle
* @ param cy { Number } y coordinate of the c point of the triangle
* @ private
* /
PIXI . PolyK . _PointInTriangle = function ( px , py , ax , ay , bx , by , cx , cy )
{
var v0x = cx - ax ;
var v0y = cy - ay ;
var v1x = bx - ax ;
var v1y = by - ay ;
var v2x = px - ax ;
var v2y = py - ay ;
var dot00 = v0x * v0x + v0y * v0y ;
var dot01 = v0x * v1x + v0y * v1y ;
var dot02 = v0x * v2x + v0y * v2y ;
var dot11 = v1x * v1x + v1y * v1y ;
var dot12 = v1x * v2x + v1y * v2y ;
var invDenom = 1 / ( dot00 * dot11 - dot01 * dot01 ) ;
var u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom ;
var v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom ;
// Check if point is in triangle
return ( u >= 0 ) && ( v >= 0 ) && ( u + v < 1 ) ;
} ;
/ * *
* Checks whether a shape is convex
*
* @ method _convex
2014-04-01 02:02:36 +00:00
*
2014-02-28 09:30:53 +00:00
* @ private
* /
PIXI . PolyK . _convex = function ( ax , ay , bx , by , cx , cy , sign )
{
return ( ( ay - by ) * ( cx - bx ) + ( bx - ax ) * ( cy - by ) >= 0 ) === sign ;
} ;
/ * *
* @ author Mat Groves http : //matgroves.com/ @Doormat23
* /
// TODO Alvin and Mat
2014-04-01 02:02:36 +00:00
// Should we eventually create a Utils class ?
2014-02-28 09:30:53 +00:00
// Or just move this file to the pixi.js file ?
PIXI . initDefaultShaders = function ( )
{
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
// PIXI.stripShader = new PIXI.StripShader();
// PIXI.stripShader.init();
} ;
PIXI . CompileVertexShader = function ( gl , shaderSrc )
{
return PIXI . _CompileShader ( gl , shaderSrc , gl . VERTEX _SHADER ) ;
} ;
PIXI . CompileFragmentShader = function ( gl , shaderSrc )
{
return PIXI . _CompileShader ( gl , shaderSrc , gl . FRAGMENT _SHADER ) ;
} ;
PIXI . _CompileShader = function ( gl , shaderSrc , shaderType )
{
var src = shaderSrc . join ( "\n" ) ;
var shader = gl . createShader ( shaderType ) ;
gl . shaderSource ( shader , src ) ;
gl . compileShader ( shader ) ;
if ( ! gl . getShaderParameter ( shader , gl . COMPILE _STATUS ) ) {
window . console . log ( gl . getShaderInfoLog ( shader ) ) ;
return null ;
}
return shader ;
} ;
PIXI . compileProgram = function ( gl , vertexSrc , fragmentSrc )
{
var fragmentShader = PIXI . CompileFragmentShader ( gl , fragmentSrc ) ;
var vertexShader = PIXI . CompileVertexShader ( gl , vertexSrc ) ;
var shaderProgram = gl . createProgram ( ) ;
gl . attachShader ( shaderProgram , vertexShader ) ;
gl . attachShader ( shaderProgram , fragmentShader ) ;
gl . linkProgram ( shaderProgram ) ;
if ( ! gl . getProgramParameter ( shaderProgram , gl . LINK _STATUS ) ) {
window . console . log ( "Could not initialise shaders" ) ;
}
return shaderProgram ;
} ;
/ * *
* @ author Mat Groves http : //matgroves.com/ @Doormat23
* @ author Richard Davey http : //www.photonstorm.com @photonstorm
* /
/ * *
* @ class PixiShader
* @ constructor
* /
PIXI . PixiShader = function ( gl )
{
/ * *
* @ property gl
* @ type WebGLContext
* /
this . gl = gl ;
/ * *
* @ property { any } program - The WebGL program .
* /
this . program = null ;
/ * *
* @ property { array } fragmentSrc - The fragment shader .
* /
this . fragmentSrc = [
'precision lowp float;' ,
'varying vec2 vTextureCoord;' ,
'varying vec4 vColor;' ,
'uniform sampler2D uSampler;' ,
'void main(void) {' ,
' gl_FragColor = texture2D(uSampler, vTextureCoord) * vColor ;' ,
'}'
] ;
/ * *
* @ property { number } textureCount - A local texture counter for multi - texture shaders .
* /
this . textureCount = 0 ;
this . attributes = [ ] ;
this . init ( ) ;
} ;
/ * *
* Initialises the shader
* @ method init
*
* /
PIXI . PixiShader . prototype . init = function ( )
{
var gl = this . gl ;
var program = PIXI . compileProgram ( gl , this . vertexSrc || PIXI . PixiShader . defaultVertexSrc , this . fragmentSrc ) ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
gl . useProgram ( program ) ;
// get and store the uniforms for the shader
this . uSampler = gl . getUniformLocation ( program , 'uSampler' ) ;
this . projectionVector = gl . getUniformLocation ( program , 'projectionVector' ) ;
this . offsetVector = gl . getUniformLocation ( program , 'offsetVector' ) ;
this . dimensions = gl . getUniformLocation ( program , 'dimensions' ) ;
// get and store the attributes
this . aVertexPosition = gl . getAttribLocation ( program , 'aVertexPosition' ) ;
this . aTextureCoord = gl . getAttribLocation ( program , 'aTextureCoord' ) ;
this . colorAttribute = gl . getAttribLocation ( program , 'aColor' ) ;
// Begin worst hack eva //
// WHY??? ONLY on my chrome pixel the line above returns -1 when using filters?
// maybe its something to do with the current state of the gl context.
// Im convinced this is a bug in the chrome browser as there is NO reason why this should be returning -1 especially as it only manifests on my chrome pixel
// If theres any webGL people that know why could happen please help :)
if ( this . colorAttribute === - 1 )
{
this . colorAttribute = 2 ;
}
this . attributes = [ this . aVertexPosition , this . aTextureCoord , this . colorAttribute ] ;
// End worst hack eva //
// add those custom shaders!
for ( var key in this . uniforms )
{
// get the uniform locations..
this . uniforms [ key ] . uniformLocation = gl . getUniformLocation ( program , key ) ;
}
this . initUniforms ( ) ;
this . program = program ;
} ;
/ * *
* Initialises the shader uniform values .
* Uniforms are specified in the GLSL _ES Specification : http : //www.khronos.org/registry/webgl/specs/latest/1.0/
* http : //www.khronos.org/registry/gles/specs/2.0/GLSL_ES_Specification_1.0.17.pdf
*
* @ method initUniforms
* /
PIXI . PixiShader . prototype . initUniforms = function ( )
{
this . textureCount = 1 ;
var gl = this . gl ;
var uniform ;
for ( var key in this . uniforms )
{
uniform = this . uniforms [ key ] ;
var type = uniform . type ;
if ( type === 'sampler2D' )
{
uniform . _init = false ;
if ( uniform . value !== null )
{
this . initSampler2D ( uniform ) ;
}
}
else if ( type === 'mat2' || type === 'mat3' || type === 'mat4' )
{
// These require special handling
uniform . glMatrix = true ;
uniform . glValueLength = 1 ;
if ( type === 'mat2' )
{
uniform . glFunc = gl . uniformMatrix2fv ;
}
else if ( type === 'mat3' )
{
uniform . glFunc = gl . uniformMatrix3fv ;
}
else if ( type === 'mat4' )
{
uniform . glFunc = gl . uniformMatrix4fv ;
}
}
else
{
// GL function reference
uniform . glFunc = gl [ 'uniform' + type ] ;
if ( type === '2f' || type === '2i' )
{
uniform . glValueLength = 2 ;
}
else if ( type === '3f' || type === '3i' )
{
uniform . glValueLength = 3 ;
}
else if ( type === '4f' || type === '4i' )
{
uniform . glValueLength = 4 ;
}
else
{
uniform . glValueLength = 1 ;
}
}
}
} ;
/ * *
* Initialises a Sampler2D uniform ( which may only be available later on after initUniforms once the texture has loaded )
*
* @ method initSampler2D
* /
PIXI . PixiShader . prototype . initSampler2D = function ( uniform )
{
if ( ! uniform . value || ! uniform . value . baseTexture || ! uniform . value . baseTexture . hasLoaded )
{
return ;
}
var gl = this . gl ;
gl . activeTexture ( gl [ 'TEXTURE' + this . textureCount ] ) ;
gl . bindTexture ( gl . TEXTURE _2D , uniform . value . baseTexture . _glTextures [ gl . id ] ) ;
// Extended texture data
if ( uniform . textureData )
{
var data = uniform . textureData ;
// GLTexture = mag linear, min linear_mipmap_linear, wrap repeat + gl.generateMipmap(gl.TEXTURE_2D);
// GLTextureLinear = mag/min linear, wrap clamp
// GLTextureNearestRepeat = mag/min NEAREST, wrap repeat
// GLTextureNearest = mag/min nearest, wrap clamp
// AudioTexture = whatever + luminance + width 512, height 2, border 0
// KeyTexture = whatever + luminance + width 256, height 2, border 0
// magFilter can be: gl.LINEAR, gl.LINEAR_MIPMAP_LINEAR or gl.NEAREST
// wrapS/T can be: gl.CLAMP_TO_EDGE or gl.REPEAT
var magFilter = ( data . magFilter ) ? data . magFilter : gl . LINEAR ;
var minFilter = ( data . minFilter ) ? data . minFilter : gl . LINEAR ;
var wrapS = ( data . wrapS ) ? data . wrapS : gl . CLAMP _TO _EDGE ;
var wrapT = ( data . wrapT ) ? data . wrapT : gl . CLAMP _TO _EDGE ;
var format = ( data . luminance ) ? gl . LUMINANCE : gl . RGBA ;
if ( data . repeat )
{
wrapS = gl . REPEAT ;
wrapT = gl . REPEAT ;
}
gl . pixelStorei ( gl . UNPACK _FLIP _Y _WEBGL , ! ! data . flipY ) ;
if ( data . width )
{
var width = ( data . width ) ? data . width : 512 ;
var height = ( data . height ) ? data . height : 2 ;
var border = ( data . border ) ? data . border : 0 ;
// void texImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, ArrayBufferView? pixels);
gl . texImage2D ( gl . TEXTURE _2D , 0 , format , width , height , border , format , gl . UNSIGNED _BYTE , null ) ;
}
else
{
// void texImage2D(GLenum target, GLint level, GLenum internalformat, GLenum format, GLenum type, ImageData? pixels);
gl . texImage2D ( gl . TEXTURE _2D , 0 , format , gl . RGBA , gl . UNSIGNED _BYTE , uniform . value . baseTexture . source ) ;
}
gl . texParameteri ( gl . TEXTURE _2D , gl . TEXTURE _MAG _FILTER , magFilter ) ;
gl . texParameteri ( gl . TEXTURE _2D , gl . TEXTURE _MIN _FILTER , minFilter ) ;
gl . texParameteri ( gl . TEXTURE _2D , gl . TEXTURE _WRAP _S , wrapS ) ;
gl . texParameteri ( gl . TEXTURE _2D , gl . TEXTURE _WRAP _T , wrapT ) ;
}
gl . uniform1i ( uniform . uniformLocation , this . textureCount ) ;
uniform . _init = true ;
this . textureCount ++ ;
} ;
/ * *
* Updates the shader uniform values .
*
* @ method syncUniforms
* /
PIXI . PixiShader . prototype . syncUniforms = function ( )
{
this . textureCount = 1 ;
var uniform ;
var gl = this . gl ;
// This would probably be faster in an array and it would guarantee key order
for ( var key in this . uniforms )
{
uniform = this . uniforms [ key ] ;
if ( uniform . glValueLength === 1 )
{
if ( uniform . glMatrix === true )
{
uniform . glFunc . call ( gl , uniform . uniformLocation , uniform . transpose , uniform . value ) ;
}
else
{
uniform . glFunc . call ( gl , uniform . uniformLocation , uniform . value ) ;
}
}
else if ( uniform . glValueLength === 2 )
{
uniform . glFunc . call ( gl , uniform . uniformLocation , uniform . value . x , uniform . value . y ) ;
}
else if ( uniform . glValueLength === 3 )
{
uniform . glFunc . call ( gl , uniform . uniformLocation , uniform . value . x , uniform . value . y , uniform . value . z ) ;
}
else if ( uniform . glValueLength === 4 )
{
uniform . glFunc . call ( gl , uniform . uniformLocation , uniform . value . x , uniform . value . y , uniform . value . z , uniform . value . w ) ;
}
else if ( uniform . type === 'sampler2D' )
{
if ( uniform . _init )
{
gl . activeTexture ( gl [ 'TEXTURE' + this . textureCount ] ) ;
gl . bindTexture ( gl . TEXTURE _2D , uniform . value . baseTexture . _glTextures [ gl . id ] || PIXI . createWebGLTexture ( uniform . value . baseTexture , gl ) ) ;
gl . uniform1i ( uniform . uniformLocation , this . textureCount ) ;
this . textureCount ++ ;
}
else
{
this . initSampler2D ( uniform ) ;
}
}
}
} ;
/ * *
* Destroys the shader
* @ method destroy
* /
PIXI . PixiShader . prototype . destroy = function ( )
{
this . gl . deleteProgram ( this . program ) ;
this . uniforms = null ;
this . gl = null ;
this . attributes = null ;
} ;
/ * *
2014-02-28 18:55:07 +00:00
* The Default Vertex shader source
2014-02-28 09:30:53 +00:00
* @ property defaultVertexSrc
* @ type String
* /
PIXI . PixiShader . defaultVertexSrc = [
'attribute vec2 aVertexPosition;' ,
'attribute vec2 aTextureCoord;' ,
'attribute vec2 aColor;' ,
'uniform vec2 projectionVector;' ,
'uniform vec2 offsetVector;' ,
'varying vec2 vTextureCoord;' ,
'varying vec4 vColor;' ,
'const vec2 center = vec2(-1.0, 1.0);' ,
'void main(void) {' ,
' gl_Position = vec4( ((aVertexPosition + offsetVector) / projectionVector) + center , 0.0, 1.0);' ,
' vTextureCoord = aTextureCoord;' ,
' vec3 color = mod(vec3(aColor.y/65536.0, aColor.y/256.0, aColor.y), 256.0) / 256.0;' ,
' vColor = vec4(color * aColor.x, aColor.x);' ,
'}'
] ;
/ * *
* @ author Mat Groves http : //matgroves.com/ @Doormat23
* @ author Richard Davey http : //www.photonstorm.com @photonstorm
* /
/ * *
* @ class PixiFastShader
* @ constructor
* @ param gl { WebGLContext } the current WebGL drawing context
* /
PIXI . PixiFastShader = function ( gl )
{
/ * *
* @ property gl
* @ type WebGLContext
* /
this . gl = gl ;
/ * *
* @ property { any } program - The WebGL program .
* /
this . program = null ;
/ * *
* @ property { array } fragmentSrc - The fragment shader .
* /
this . fragmentSrc = [
'precision lowp float;' ,
'varying vec2 vTextureCoord;' ,
'varying float vColor;' ,
'uniform sampler2D uSampler;' ,
'void main(void) {' ,
' gl_FragColor = texture2D(uSampler, vTextureCoord) * vColor ;' ,
'}'
] ;
/ * *
* @ property { array } vertexSrc - The vertex shader
* /
this . vertexSrc = [
'attribute vec2 aVertexPosition;' ,
'attribute vec2 aPositionCoord;' ,
'attribute vec2 aScale;' ,
'attribute float aRotation;' ,
'attribute vec2 aTextureCoord;' ,
'attribute float aColor;' ,
'uniform vec2 projectionVector;' ,
'uniform vec2 offsetVector;' ,
'uniform mat3 uMatrix;' ,
'varying vec2 vTextureCoord;' ,
'varying float vColor;' ,
'const vec2 center = vec2(-1.0, 1.0);' ,
'void main(void) {' ,
' vec2 v;' ,
' vec2 sv = aVertexPosition * aScale;' ,
' v.x = (sv.x) * cos(aRotation) - (sv.y) * sin(aRotation);' ,
' v.y = (sv.x) * sin(aRotation) + (sv.y) * cos(aRotation);' ,
' v = ( uMatrix * vec3(v + aPositionCoord , 1.0) ).xy ;' ,
' gl_Position = vec4( ( v / projectionVector) + center , 0.0, 1.0);' ,
' vTextureCoord = aTextureCoord;' ,
// ' vec3 color = mod(vec3(aColor.y/65536.0, aColor.y/256.0, aColor.y), 256.0) / 256.0;',
' vColor = aColor;' ,
'}'
] ;
/ * *
* @ property { number } textureCount - A local texture counter for multi - texture shaders .
* /
this . textureCount = 0 ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
this . init ( ) ;
} ;
/ * *
* Initialises the shader
* @ method init
*
* /
PIXI . PixiFastShader . prototype . init = function ( )
{
var gl = this . gl ;
var program = PIXI . compileProgram ( gl , this . vertexSrc , this . fragmentSrc ) ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
gl . useProgram ( program ) ;
// get and store the uniforms for the shader
this . uSampler = gl . getUniformLocation ( program , 'uSampler' ) ;
this . projectionVector = gl . getUniformLocation ( program , 'projectionVector' ) ;
this . offsetVector = gl . getUniformLocation ( program , 'offsetVector' ) ;
this . dimensions = gl . getUniformLocation ( program , 'dimensions' ) ;
this . uMatrix = gl . getUniformLocation ( program , 'uMatrix' ) ;
// get and store the attributes
this . aVertexPosition = gl . getAttribLocation ( program , 'aVertexPosition' ) ;
this . aPositionCoord = gl . getAttribLocation ( program , 'aPositionCoord' ) ;
this . aScale = gl . getAttribLocation ( program , 'aScale' ) ;
this . aRotation = gl . getAttribLocation ( program , 'aRotation' ) ;
this . aTextureCoord = gl . getAttribLocation ( program , 'aTextureCoord' ) ;
this . colorAttribute = gl . getAttribLocation ( program , 'aColor' ) ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
// Begin worst hack eva //
// WHY??? ONLY on my chrome pixel the line above returns -1 when using filters?
// maybe its somthing to do with the current state of the gl context.
// Im convinced this is a bug in the chrome browser as there is NO reason why this should be returning -1 especially as it only manifests on my chrome pixel
// If theres any webGL people that know why could happen please help :)
if ( this . colorAttribute === - 1 )
{
this . colorAttribute = 2 ;
}
this . attributes = [ this . aVertexPosition , this . aPositionCoord , this . aScale , this . aRotation , this . aTextureCoord , this . colorAttribute ] ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
// End worst hack eva //
this . program = program ;
} ;
/ * *
* Destroys the shader
* @ method destroy
*
* /
PIXI . PixiFastShader . prototype . destroy = function ( )
{
this . gl . deleteProgram ( this . program ) ;
this . uniforms = null ;
this . gl = null ;
this . attributes = null ;
} ;
/ * *
* @ author Mat Groves http : //matgroves.com/ @Doormat23
* /
PIXI . StripShader = function ( )
{
/ * *
* @ property { any } program - The WebGL program .
* /
this . program = null ;
/ * *
* @ property { array } fragmentSrc - The fragment shader .
* /
this . fragmentSrc = [
'precision mediump float;' ,
'varying vec2 vTextureCoord;' ,
'varying float vColor;' ,
'uniform float alpha;' ,
'uniform sampler2D uSampler;' ,
'void main(void) {' ,
' gl_FragColor = texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y));' ,
' gl_FragColor = gl_FragColor * alpha;' ,
'}'
] ;
/ * *
* @ property { array } fragmentSrc - The fragment shader .
* /
this . vertexSrc = [
'attribute vec2 aVertexPosition;' ,
'attribute vec2 aTextureCoord;' ,
'attribute float aColor;' ,
'uniform mat3 translationMatrix;' ,
'uniform vec2 projectionVector;' ,
'varying vec2 vTextureCoord;' ,
'uniform vec2 offsetVector;' ,
'varying float vColor;' ,
'void main(void) {' ,
' vec3 v = translationMatrix * vec3(aVertexPosition, 1.0);' ,
' v -= offsetVector.xyx;' ,
' gl_Position = vec4( v.x / projectionVector.x -1.0, v.y / projectionVector.y + 1.0 , 0.0, 1.0);' ,
' vTextureCoord = aTextureCoord;' ,
' vColor = aColor;' ,
'}'
] ;
} ;
/ * *
* Initialises the shader
* @ method init
*
* /
PIXI . StripShader . prototype . init = function ( )
{
var gl = PIXI . gl ;
var program = PIXI . compileProgram ( gl , this . vertexSrc , this . fragmentSrc ) ;
gl . useProgram ( program ) ;
// get and store the uniforms for the shader
this . uSampler = gl . getUniformLocation ( program , 'uSampler' ) ;
this . projectionVector = gl . getUniformLocation ( program , 'projectionVector' ) ;
this . offsetVector = gl . getUniformLocation ( program , 'offsetVector' ) ;
this . colorAttribute = gl . getAttribLocation ( program , 'aColor' ) ;
//this.dimensions = gl.getUniformLocation(this.program, 'dimensions');
// get and store the attributes
this . aVertexPosition = gl . getAttribLocation ( program , 'aVertexPosition' ) ;
this . aTextureCoord = gl . getAttribLocation ( program , 'aTextureCoord' ) ;
this . translationMatrix = gl . getUniformLocation ( program , 'translationMatrix' ) ;
this . alpha = gl . getUniformLocation ( program , 'alpha' ) ;
this . program = program ;
} ;
/ * *
* @ author Mat Groves http : //matgroves.com/ @Doormat23
* /
/ * *
* @ class PrimitiveShader
* @ constructor
* @ param gl { WebGLContext } the current WebGL drawing context
* /
PIXI . PrimitiveShader = function ( gl )
{
/ * *
* @ property gl
* @ type WebGLContext
* /
this . gl = gl ;
/ * *
* @ property { any } program - The WebGL program .
* /
this . program = null ;
/ * *
* @ property fragmentSrc
* @ type Array
* /
this . fragmentSrc = [
'precision mediump float;' ,
'varying vec4 vColor;' ,
'void main(void) {' ,
' gl_FragColor = vColor;' ,
'}'
] ;
/ * *
* @ property vertexSrc
* @ type Array
* /
this . vertexSrc = [
'attribute vec2 aVertexPosition;' ,
'attribute vec4 aColor;' ,
'uniform mat3 translationMatrix;' ,
'uniform vec2 projectionVector;' ,
'uniform vec2 offsetVector;' ,
'uniform float alpha;' ,
'uniform vec3 tint;' ,
'varying vec4 vColor;' ,
'void main(void) {' ,
' vec3 v = translationMatrix * vec3(aVertexPosition , 1.0);' ,
' v -= offsetVector.xyx;' ,
' gl_Position = vec4( v.x / projectionVector.x -1.0, v.y / -projectionVector.y + 1.0 , 0.0, 1.0);' ,
' vColor = aColor * vec4(tint * alpha, alpha);' ,
'}'
] ;
this . init ( ) ;
} ;
/ * *
* Initialises the shader
* @ method init
*
* /
PIXI . PrimitiveShader . prototype . init = function ( )
{
var gl = this . gl ;
var program = PIXI . compileProgram ( gl , this . vertexSrc , this . fragmentSrc ) ;
gl . useProgram ( program ) ;
// get and store the uniforms for the shader
this . projectionVector = gl . getUniformLocation ( program , 'projectionVector' ) ;
this . offsetVector = gl . getUniformLocation ( program , 'offsetVector' ) ;
this . tintColor = gl . getUniformLocation ( program , 'tint' ) ;
// get and store the attributes
this . aVertexPosition = gl . getAttribLocation ( program , 'aVertexPosition' ) ;
this . colorAttribute = gl . getAttribLocation ( program , 'aColor' ) ;
this . attributes = [ this . aVertexPosition , this . colorAttribute ] ;
this . translationMatrix = gl . getUniformLocation ( program , 'translationMatrix' ) ;
this . alpha = gl . getUniformLocation ( program , 'alpha' ) ;
this . program = program ;
} ;
/ * *
* Destroys the shader
* @ method destroy
*
* /
PIXI . PrimitiveShader . prototype . destroy = function ( )
{
this . gl . deleteProgram ( this . program ) ;
this . uniforms = null ;
this . gl = null ;
this . attribute = null ;
} ;
/ * *
* @ author Mat Groves http : //matgroves.com/ @Doormat23
* /
/ * *
* A set of functions used by the webGL renderer to draw the primitive graphics data
*
* @ class WebGLGraphics
* @ private
* @ static
* /
PIXI . WebGLGraphics = function ( )
{
} ;
/ * *
* Renders the graphics object
*
* @ static
* @ private
* @ method renderGraphics
* @ param graphics { Graphics }
* @ param renderSession { Object }
* /
PIXI . WebGLGraphics . renderGraphics = function ( graphics , renderSession ) //projection, offset)
{
var gl = renderSession . gl ;
var projection = renderSession . projection ,
offset = renderSession . offset ,
shader = renderSession . shaderManager . primitiveShader ;
if ( ! graphics . _webGL [ gl . id ] ) graphics . _webGL [ gl . id ] = { points : [ ] , indices : [ ] , lastIndex : 0 ,
buffer : gl . createBuffer ( ) ,
indexBuffer : gl . createBuffer ( ) } ;
var webGL = graphics . _webGL [ gl . id ] ;
if ( graphics . dirty )
{
graphics . dirty = false ;
if ( graphics . clearDirty )
{
graphics . clearDirty = false ;
webGL . lastIndex = 0 ;
webGL . points = [ ] ;
webGL . indices = [ ] ;
}
PIXI . WebGLGraphics . updateGraphics ( graphics , gl ) ;
}
renderSession . shaderManager . activatePrimitiveShader ( ) ;
// This could be speeded up for sure!
// set the matrix transform
gl . blendFunc ( gl . ONE , gl . ONE _MINUS _SRC _ALPHA ) ;
gl . uniformMatrix3fv ( shader . translationMatrix , false , graphics . worldTransform . toArray ( true ) ) ;
gl . uniform2f ( shader . projectionVector , projection . x , - projection . y ) ;
gl . uniform2f ( shader . offsetVector , - offset . x , - offset . y ) ;
gl . uniform3fv ( shader . tintColor , PIXI . hex2rgb ( graphics . tint ) ) ;
gl . uniform1f ( shader . alpha , graphics . worldAlpha ) ;
gl . bindBuffer ( gl . ARRAY _BUFFER , webGL . buffer ) ;
gl . vertexAttribPointer ( shader . aVertexPosition , 2 , gl . FLOAT , false , 4 * 6 , 0 ) ;
gl . vertexAttribPointer ( shader . colorAttribute , 4 , gl . FLOAT , false , 4 * 6 , 2 * 4 ) ;
// set the index buffer!
gl . bindBuffer ( gl . ELEMENT _ARRAY _BUFFER , webGL . indexBuffer ) ;
gl . drawElements ( gl . TRIANGLE _STRIP , webGL . indices . length , gl . UNSIGNED _SHORT , 0 ) ;
renderSession . shaderManager . deactivatePrimitiveShader ( ) ;
// return to default shader...
// PIXI.activateShader(PIXI.defaultShader);
} ;
/ * *
* Updates the graphics object
*
* @ static
* @ private
* @ method updateGraphics
* @ param graphicsData { Graphics } The graphics object to update
* @ param gl { WebGLContext } the current WebGL drawing context
* /
PIXI . WebGLGraphics . updateGraphics = function ( graphics , gl )
{
var webGL = graphics . _webGL [ gl . id ] ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
for ( var i = webGL . lastIndex ; i < graphics . graphicsData . length ; i ++ )
{
var data = graphics . graphicsData [ i ] ;
if ( data . type === PIXI . Graphics . POLY )
{
if ( data . fill )
{
if ( data . points . length > 3 )
PIXI . WebGLGraphics . buildPoly ( data , webGL ) ;
}
if ( data . lineWidth > 0 )
{
PIXI . WebGLGraphics . buildLine ( data , webGL ) ;
}
}
else if ( data . type === PIXI . Graphics . RECT )
{
PIXI . WebGLGraphics . buildRectangle ( data , webGL ) ;
}
else if ( data . type === PIXI . Graphics . CIRC || data . type === PIXI . Graphics . ELIP )
{
PIXI . WebGLGraphics . buildCircle ( data , webGL ) ;
}
}
webGL . lastIndex = graphics . graphicsData . length ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
webGL . glPoints = new Float32Array ( webGL . points ) ;
gl . bindBuffer ( gl . ARRAY _BUFFER , webGL . buffer ) ;
gl . bufferData ( gl . ARRAY _BUFFER , webGL . glPoints , gl . STATIC _DRAW ) ;
webGL . glIndicies = new Uint16Array ( webGL . indices ) ;
gl . bindBuffer ( gl . ELEMENT _ARRAY _BUFFER , webGL . indexBuffer ) ;
gl . bufferData ( gl . ELEMENT _ARRAY _BUFFER , webGL . glIndicies , gl . STATIC _DRAW ) ;
} ;
/ * *
* Builds a rectangle to draw
*
* @ static
* @ private
* @ method buildRectangle
* @ param graphicsData { Graphics } The graphics object containing all the necessary properties
* @ param webGLData { Object }
* /
PIXI . WebGLGraphics . buildRectangle = function ( graphicsData , webGLData )
{
// --- //
// need to convert points to a nice regular data
//
var rectData = graphicsData . points ;
var x = rectData [ 0 ] ;
var y = rectData [ 1 ] ;
var width = rectData [ 2 ] ;
var height = rectData [ 3 ] ;
if ( graphicsData . fill )
{
var color = PIXI . hex2rgb ( graphicsData . fillColor ) ;
var alpha = graphicsData . fillAlpha ;
var r = color [ 0 ] * alpha ;
var g = color [ 1 ] * alpha ;
var b = color [ 2 ] * alpha ;
var verts = webGLData . points ;
var indices = webGLData . indices ;
var vertPos = verts . length / 6 ;
// start
verts . push ( x , y ) ;
verts . push ( r , g , b , alpha ) ;
verts . push ( x + width , y ) ;
verts . push ( r , g , b , alpha ) ;
verts . push ( x , y + height ) ;
verts . push ( r , g , b , alpha ) ;
verts . push ( x + width , y + height ) ;
verts . push ( r , g , b , alpha ) ;
// insert 2 dead triangles..
indices . push ( vertPos , vertPos , vertPos + 1 , vertPos + 2 , vertPos + 3 , vertPos + 3 ) ;
}
if ( graphicsData . lineWidth )
{
var tempPoints = graphicsData . points ;
graphicsData . points = [ x , y ,
x + width , y ,
x + width , y + height ,
x , y + height ,
x , y ] ;
PIXI . WebGLGraphics . buildLine ( graphicsData , webGLData ) ;
graphicsData . points = tempPoints ;
}
} ;
/ * *
* Builds a circle to draw
*
* @ static
* @ private
* @ method buildCircle
* @ param graphicsData { Graphics } The graphics object to draw
* @ param webGLData { Object }
* /
PIXI . WebGLGraphics . buildCircle = function ( graphicsData , webGLData )
{
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
// need to convert points to a nice regular data
var rectData = graphicsData . points ;
var x = rectData [ 0 ] ;
var y = rectData [ 1 ] ;
var width = rectData [ 2 ] ;
var height = rectData [ 3 ] ;
var totalSegs = 40 ;
var seg = ( Math . PI * 2 ) / totalSegs ;
var i = 0 ;
if ( graphicsData . fill )
{
var color = PIXI . hex2rgb ( graphicsData . fillColor ) ;
var alpha = graphicsData . fillAlpha ;
var r = color [ 0 ] * alpha ;
var g = color [ 1 ] * alpha ;
var b = color [ 2 ] * alpha ;
var verts = webGLData . points ;
var indices = webGLData . indices ;
var vecPos = verts . length / 6 ;
indices . push ( vecPos ) ;
for ( i = 0 ; i < totalSegs + 1 ; i ++ )
{
verts . push ( x , y , r , g , b , alpha ) ;
verts . push ( x + Math . sin ( seg * i ) * width ,
y + Math . cos ( seg * i ) * height ,
r , g , b , alpha ) ;
indices . push ( vecPos ++ , vecPos ++ ) ;
}
indices . push ( vecPos - 1 ) ;
}
if ( graphicsData . lineWidth )
{
var tempPoints = graphicsData . points ;
graphicsData . points = [ ] ;
for ( i = 0 ; i < totalSegs + 1 ; i ++ )
{
graphicsData . points . push ( x + Math . sin ( seg * i ) * width ,
y + Math . cos ( seg * i ) * height ) ;
}
PIXI . WebGLGraphics . buildLine ( graphicsData , webGLData ) ;
graphicsData . points = tempPoints ;
}
} ;
/ * *
* Builds a line to draw
*
* @ static
* @ private
* @ method buildLine
* @ param graphicsData { Graphics } The graphics object containing all the necessary properties
* @ param webGLData { Object }
* /
PIXI . WebGLGraphics . buildLine = function ( graphicsData , webGLData )
{
// TODO OPTIMISE!
var i = 0 ;
var points = graphicsData . points ;
if ( points . length === 0 ) return ;
// if the line width is an odd number add 0.5 to align to a whole pixel
if ( graphicsData . lineWidth % 2 )
{
for ( i = 0 ; i < points . length ; i ++ ) {
points [ i ] += 0.5 ;
}
}
// get first and last point.. figure out the middle!
var firstPoint = new PIXI . Point ( points [ 0 ] , points [ 1 ] ) ;
var lastPoint = new PIXI . Point ( points [ points . length - 2 ] , points [ points . length - 1 ] ) ;
// if the first point is the last point - gonna have issues :)
if ( firstPoint . x === lastPoint . x && firstPoint . y === lastPoint . y )
{
points . pop ( ) ;
points . pop ( ) ;
lastPoint = new PIXI . Point ( points [ points . length - 2 ] , points [ points . length - 1 ] ) ;
var midPointX = lastPoint . x + ( firstPoint . x - lastPoint . x ) * 0.5 ;
var midPointY = lastPoint . y + ( firstPoint . y - lastPoint . y ) * 0.5 ;
points . unshift ( midPointX , midPointY ) ;
points . push ( midPointX , midPointY ) ;
}
var verts = webGLData . points ;
var indices = webGLData . indices ;
var length = points . length / 2 ;
var indexCount = points . length ;
var indexStart = verts . length / 6 ;
// DRAW the Line
var width = graphicsData . lineWidth / 2 ;
// sort color
var color = PIXI . hex2rgb ( graphicsData . lineColor ) ;
var alpha = graphicsData . lineAlpha ;
var r = color [ 0 ] * alpha ;
var g = color [ 1 ] * alpha ;
var b = color [ 2 ] * alpha ;
var px , py , p1x , p1y , p2x , p2y , p3x , p3y ;
var perpx , perpy , perp2x , perp2y , perp3x , perp3y ;
var a1 , b1 , c1 , a2 , b2 , c2 ;
var denom , pdist , dist ;
p1x = points [ 0 ] ;
p1y = points [ 1 ] ;
p2x = points [ 2 ] ;
p2y = points [ 3 ] ;
perpx = - ( p1y - p2y ) ;
perpy = p1x - p2x ;
dist = Math . sqrt ( perpx * perpx + perpy * perpy ) ;
perpx /= dist ;
perpy /= dist ;
perpx *= width ;
perpy *= width ;
// start
verts . push ( p1x - perpx , p1y - perpy ,
r , g , b , alpha ) ;
verts . push ( p1x + perpx , p1y + perpy ,
r , g , b , alpha ) ;
for ( i = 1 ; i < length - 1 ; i ++ )
{
p1x = points [ ( i - 1 ) * 2 ] ;
p1y = points [ ( i - 1 ) * 2 + 1 ] ;
p2x = points [ ( i ) * 2 ] ;
p2y = points [ ( i ) * 2 + 1 ] ;
p3x = points [ ( i + 1 ) * 2 ] ;
p3y = points [ ( i + 1 ) * 2 + 1 ] ;
perpx = - ( p1y - p2y ) ;
perpy = p1x - p2x ;
dist = Math . sqrt ( perpx * perpx + perpy * perpy ) ;
perpx /= dist ;
perpy /= dist ;
perpx *= width ;
perpy *= width ;
perp2x = - ( p2y - p3y ) ;
perp2y = p2x - p3x ;
dist = Math . sqrt ( perp2x * perp2x + perp2y * perp2y ) ;
perp2x /= dist ;
perp2y /= dist ;
perp2x *= width ;
perp2y *= width ;
a1 = ( - perpy + p1y ) - ( - perpy + p2y ) ;
b1 = ( - perpx + p2x ) - ( - perpx + p1x ) ;
c1 = ( - perpx + p1x ) * ( - perpy + p2y ) - ( - perpx + p2x ) * ( - perpy + p1y ) ;
a2 = ( - perp2y + p3y ) - ( - perp2y + p2y ) ;
b2 = ( - perp2x + p2x ) - ( - perp2x + p3x ) ;
c2 = ( - perp2x + p3x ) * ( - perp2y + p2y ) - ( - perp2x + p2x ) * ( - perp2y + p3y ) ;
denom = a1 * b2 - a2 * b1 ;
if ( Math . abs ( denom ) < 0.1 )
{
denom += 10.1 ;
verts . push ( p2x - perpx , p2y - perpy ,
r , g , b , alpha ) ;
verts . push ( p2x + perpx , p2y + perpy ,
r , g , b , alpha ) ;
continue ;
}
px = ( b1 * c2 - b2 * c1 ) / denom ;
py = ( a2 * c1 - a1 * c2 ) / denom ;
pdist = ( px - p2x ) * ( px - p2x ) + ( py - p2y ) + ( py - p2y ) ;
if ( pdist > 140 * 140 )
{
perp3x = perpx - perp2x ;
perp3y = perpy - perp2y ;
dist = Math . sqrt ( perp3x * perp3x + perp3y * perp3y ) ;
perp3x /= dist ;
perp3y /= dist ;
perp3x *= width ;
perp3y *= width ;
verts . push ( p2x - perp3x , p2y - perp3y ) ;
verts . push ( r , g , b , alpha ) ;
verts . push ( p2x + perp3x , p2y + perp3y ) ;
verts . push ( r , g , b , alpha ) ;
verts . push ( p2x - perp3x , p2y - perp3y ) ;
verts . push ( r , g , b , alpha ) ;
indexCount ++ ;
}
else
{
verts . push ( px , py ) ;
verts . push ( r , g , b , alpha ) ;
verts . push ( p2x - ( px - p2x ) , p2y - ( py - p2y ) ) ;
verts . push ( r , g , b , alpha ) ;
}
}
p1x = points [ ( length - 2 ) * 2 ] ;
p1y = points [ ( length - 2 ) * 2 + 1 ] ;
p2x = points [ ( length - 1 ) * 2 ] ;
p2y = points [ ( length - 1 ) * 2 + 1 ] ;
perpx = - ( p1y - p2y ) ;
perpy = p1x - p2x ;
dist = Math . sqrt ( perpx * perpx + perpy * perpy ) ;
perpx /= dist ;
perpy /= dist ;
perpx *= width ;
perpy *= width ;
verts . push ( p2x - perpx , p2y - perpy ) ;
verts . push ( r , g , b , alpha ) ;
verts . push ( p2x + perpx , p2y + perpy ) ;
verts . push ( r , g , b , alpha ) ;
indices . push ( indexStart ) ;
for ( i = 0 ; i < indexCount ; i ++ )
{
indices . push ( indexStart ++ ) ;
}
indices . push ( indexStart - 1 ) ;
} ;
/ * *
* Builds a polygon to draw
*
* @ static
* @ private
* @ method buildPoly
* @ param graphicsData { Graphics } The graphics object containing all the necessary properties
* @ param webGLData { Object }
* /
PIXI . WebGLGraphics . buildPoly = function ( graphicsData , webGLData )
{
var points = graphicsData . points ;
if ( points . length < 6 ) return ;
// get first and last point.. figure out the middle!
var verts = webGLData . points ;
var indices = webGLData . indices ;
var length = points . length / 2 ;
// sort color
var color = PIXI . hex2rgb ( graphicsData . fillColor ) ;
var alpha = graphicsData . fillAlpha ;
var r = color [ 0 ] * alpha ;
var g = color [ 1 ] * alpha ;
var b = color [ 2 ] * alpha ;
var triangles = PIXI . PolyK . Triangulate ( points ) ;
var vertPos = verts . length / 6 ;
var i = 0 ;
for ( i = 0 ; i < triangles . length ; i += 3 )
{
indices . push ( triangles [ i ] + vertPos ) ;
indices . push ( triangles [ i ] + vertPos ) ;
indices . push ( triangles [ i + 1 ] + vertPos ) ;
indices . push ( triangles [ i + 2 ] + vertPos ) ;
indices . push ( triangles [ i + 2 ] + vertPos ) ;
}
for ( i = 0 ; i < length ; i ++ )
{
verts . push ( points [ i * 2 ] , points [ i * 2 + 1 ] ,
r , g , b , alpha ) ;
}
} ;
/ * *
* @ author Mat Groves http : //matgroves.com/ @Doormat23
* /
PIXI . glContexts = [ ] ; // this is where we store the webGL contexts for easy access.
/ * *
* the WebGLRenderer draws the stage and all its content onto a webGL enabled canvas . This renderer
* should be used for browsers that support webGL . This Render works by automatically managing webGLBatch ' s .
* So no need for Sprite Batch 's or Sprite Cloud' s
* Dont forget to add the view to your DOM or you will not see anything : )
*
* @ class WebGLRenderer
* @ constructor
* @ param width = 0 { Number } the width of the canvas view
* @ param height = 0 { Number } the height of the canvas view
* @ param view { HTMLCanvasElement } the canvas to use as a view , optional
* @ param transparent = false { Boolean } If the render view is transparent , default false
* @ param antialias = false { Boolean } sets antialias ( only applicable in chrome at the moment )
*
* /
PIXI . WebGLRenderer = function ( width , height , view , transparent , antialias )
{
if ( ! PIXI . defaultRenderer ) PIXI . defaultRenderer = this ;
this . type = PIXI . WEBGL _RENDERER ;
// do a catch.. only 1 webGL renderer..
/ * *
* Whether the render view is transparent
*
* @ property transparent
* @ type Boolean
* /
this . transparent = ! ! transparent ;
/ * *
* The width of the canvas view
*
* @ property width
* @ type Number
* @ default 800
* /
this . width = width || 800 ;
/ * *
* The height of the canvas view
*
* @ property height
* @ type Number
* @ default 600
* /
this . height = height || 600 ;
/ * *
* The canvas element that everything is drawn to
*
* @ property view
* @ type HTMLCanvasElement
* /
this . view = view || document . createElement ( 'canvas' ) ;
this . view . width = this . width ;
this . view . height = this . height ;
// deal with losing context..
this . contextLost = this . handleContextLost . bind ( this ) ;
this . contextRestoredLost = this . handleContextRestored . bind ( this ) ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
this . view . addEventListener ( 'webglcontextlost' , this . contextLost , false ) ;
this . view . addEventListener ( 'webglcontextrestored' , this . contextRestoredLost , false ) ;
this . options = {
alpha : this . transparent ,
antialias : ! ! antialias , // SPEED UP??
premultipliedAlpha : ! ! transparent ,
stencil : true
} ;
//try 'experimental-webgl'
try {
this . gl = this . view . getContext ( 'experimental-webgl' , this . options ) ;
} catch ( e ) {
//try 'webgl'
try {
this . gl = this . view . getContext ( 'webgl' , this . options ) ;
} catch ( e2 ) {
// fail, not able to get a context
throw new Error ( ' This browser does not support webGL. Try using the canvas renderer' + this ) ;
}
}
var gl = this . gl ;
this . glContextId = gl . id = PIXI . WebGLRenderer . glContextId ++ ;
PIXI . glContexts [ this . glContextId ] = gl ;
if ( ! PIXI . blendModesWebGL )
{
PIXI . blendModesWebGL = [ ] ;
PIXI . blendModesWebGL [ PIXI . blendModes . NORMAL ] = [ gl . ONE , gl . ONE _MINUS _SRC _ALPHA ] ;
PIXI . blendModesWebGL [ PIXI . blendModes . ADD ] = [ gl . SRC _ALPHA , gl . DST _ALPHA ] ;
PIXI . blendModesWebGL [ PIXI . blendModes . MULTIPLY ] = [ gl . DST _COLOR , gl . ONE _MINUS _SRC _ALPHA ] ;
PIXI . blendModesWebGL [ PIXI . blendModes . SCREEN ] = [ gl . SRC _ALPHA , gl . ONE ] ;
PIXI . blendModesWebGL [ PIXI . blendModes . OVERLAY ] = [ gl . ONE , gl . ONE _MINUS _SRC _ALPHA ] ;
PIXI . blendModesWebGL [ PIXI . blendModes . DARKEN ] = [ gl . ONE , gl . ONE _MINUS _SRC _ALPHA ] ;
PIXI . blendModesWebGL [ PIXI . blendModes . LIGHTEN ] = [ gl . ONE , gl . ONE _MINUS _SRC _ALPHA ] ;
PIXI . blendModesWebGL [ PIXI . blendModes . COLOR _DODGE ] = [ gl . ONE , gl . ONE _MINUS _SRC _ALPHA ] ;
PIXI . blendModesWebGL [ PIXI . blendModes . COLOR _BURN ] = [ gl . ONE , gl . ONE _MINUS _SRC _ALPHA ] ;
PIXI . blendModesWebGL [ PIXI . blendModes . HARD _LIGHT ] = [ gl . ONE , gl . ONE _MINUS _SRC _ALPHA ] ;
PIXI . blendModesWebGL [ PIXI . blendModes . SOFT _LIGHT ] = [ gl . ONE , gl . ONE _MINUS _SRC _ALPHA ] ;
PIXI . blendModesWebGL [ PIXI . blendModes . DIFFERENCE ] = [ gl . ONE , gl . ONE _MINUS _SRC _ALPHA ] ;
PIXI . blendModesWebGL [ PIXI . blendModes . EXCLUSION ] = [ gl . ONE , gl . ONE _MINUS _SRC _ALPHA ] ;
PIXI . blendModesWebGL [ PIXI . blendModes . HUE ] = [ gl . ONE , gl . ONE _MINUS _SRC _ALPHA ] ;
PIXI . blendModesWebGL [ PIXI . blendModes . SATURATION ] = [ gl . ONE , gl . ONE _MINUS _SRC _ALPHA ] ;
PIXI . blendModesWebGL [ PIXI . blendModes . COLOR ] = [ gl . ONE , gl . ONE _MINUS _SRC _ALPHA ] ;
PIXI . blendModesWebGL [ PIXI . blendModes . LUMINOSITY ] = [ gl . ONE , gl . ONE _MINUS _SRC _ALPHA ] ;
}
this . projection = new PIXI . Point ( ) ;
this . projection . x = this . width / 2 ;
this . projection . y = - this . height / 2 ;
this . offset = new PIXI . Point ( 0 , 0 ) ;
this . resize ( this . width , this . height ) ;
this . contextLost = false ;
// time to create the render managers! each one focuses on managine a state in webGL
this . shaderManager = new PIXI . WebGLShaderManager ( gl ) ; // deals with managing the shader programs and their attribs
this . spriteBatch = new PIXI . WebGLSpriteBatch ( gl ) ; // manages the rendering of sprites
this . maskManager = new PIXI . WebGLMaskManager ( gl ) ; // manages the masks using the stencil buffer
this . filterManager = new PIXI . WebGLFilterManager ( gl , this . transparent ) ; // manages the filters
this . renderSession = { } ;
this . renderSession . gl = this . gl ;
this . renderSession . drawCount = 0 ;
this . renderSession . shaderManager = this . shaderManager ;
this . renderSession . maskManager = this . maskManager ;
this . renderSession . filterManager = this . filterManager ;
this . renderSession . spriteBatch = this . spriteBatch ;
this . renderSession . renderer = this ;
gl . useProgram ( this . shaderManager . defaultShader . program ) ;
gl . disable ( gl . DEPTH _TEST ) ;
gl . disable ( gl . CULL _FACE ) ;
gl . enable ( gl . BLEND ) ;
gl . colorMask ( true , true , true , this . transparent ) ;
} ;
// constructor
PIXI . WebGLRenderer . prototype . constructor = PIXI . WebGLRenderer ;
/ * *
* Renders the stage to its webGL view
*
* @ method render
* @ param stage { Stage } the Stage element to be rendered
* /
PIXI . WebGLRenderer . prototype . render = function ( stage )
{
if ( this . contextLost ) return ;
// if rendering a new stage clear the batches..
if ( this . _ _stage !== stage )
{
if ( stage . interactive ) stage . interactionManager . removeEvents ( ) ;
// TODO make this work
// dont think this is needed any more?
this . _ _stage = stage ;
}
// update any textures this includes uvs and uploading them to the gpu
PIXI . WebGLRenderer . updateTextures ( ) ;
// update the scene graph
stage . updateTransform ( ) ;
// interaction
if ( stage . _interactive )
{
//need to add some events!
if ( ! stage . _interactiveEventsAdded )
{
stage . _interactiveEventsAdded = true ;
stage . interactionManager . setTarget ( this ) ;
}
}
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
var gl = this . gl ;
// -- Does this need to be set every frame? -- //
//gl.colorMask(true, true, true, this.transparent);
gl . viewport ( 0 , 0 , this . width , this . height ) ;
// make sure we are bound to the main frame buffer
gl . bindFramebuffer ( gl . FRAMEBUFFER , null ) ;
if ( this . transparent )
{
gl . clearColor ( 0 , 0 , 0 , 0 ) ;
}
else
{
gl . clearColor ( stage . backgroundColorSplit [ 0 ] , stage . backgroundColorSplit [ 1 ] , stage . backgroundColorSplit [ 2 ] , 1 ) ;
}
gl . clear ( gl . COLOR _BUFFER _BIT ) ;
this . renderDisplayObject ( stage , this . projection ) ;
// interaction
if ( stage . interactive )
{
//need to add some events!
if ( ! stage . _interactiveEventsAdded )
{
stage . _interactiveEventsAdded = true ;
stage . interactionManager . setTarget ( this ) ;
}
}
else
{
if ( stage . _interactiveEventsAdded )
{
stage . _interactiveEventsAdded = false ;
stage . interactionManager . setTarget ( this ) ;
}
}
/ *
//can simulate context loss in Chrome like so:
this . view . onmousedown = function ( ev ) {
console . dir ( this . gl . getSupportedExtensions ( ) ) ;
var ext = (
gl . getExtension ( "WEBGL_scompressed_texture_s3tc" )
// gl.getExtension("WEBGL_compressed_texture_s3tc") ||
// gl.getExtension("MOZ_WEBGL_compressed_texture_s3tc") ||
// gl.getExtension("WEBKIT_WEBGL_compressed_texture_s3tc")
) ;
console . dir ( ext ) ;
var loseCtx = this . gl . getExtension ( "WEBGL_lose_context" ) ;
console . log ( "killing context" ) ;
loseCtx . loseContext ( ) ;
setTimeout ( function ( ) {
console . log ( "restoring context..." ) ;
loseCtx . restoreContext ( ) ;
} . bind ( this ) , 1000 ) ;
} . bind ( this ) ;
* /
} ;
/ * *
* Renders a display Object
*
* @ method renderDIsplayObject
* @ param displayObject { DisplayObject } The DisplayObject to render
* @ param projection { Point } The projection
2014-04-01 02:02:36 +00:00
* @ param buffer { Array } a standard WebGL buffer
2014-02-28 09:30:53 +00:00
* /
PIXI . WebGLRenderer . prototype . renderDisplayObject = function ( displayObject , projection , buffer )
{
// reset the render session data..
this . renderSession . drawCount = 0 ;
this . renderSession . currentBlendMode = 9999 ;
this . renderSession . projection = projection ;
this . renderSession . offset = this . offset ;
// start the sprite batch
this . spriteBatch . begin ( this . renderSession ) ;
// start the filter manager
this . filterManager . begin ( this . renderSession , buffer ) ;
// render the scene!
displayObject . _renderWebGL ( this . renderSession ) ;
// finish the sprite batch
this . spriteBatch . end ( ) ;
} ;
/ * *
* Updates the textures loaded into this webgl renderer
*
* @ static
* @ method updateTextures
* @ private
* /
PIXI . WebGLRenderer . updateTextures = function ( )
{
var i = 0 ;
//TODO break this out into a texture manager...
//for (i = 0; i < PIXI.texturesToUpdate.length; i++)
// PIXI.WebGLRenderer.updateTexture(PIXI.texturesToUpdate[i]);
for ( i = 0 ; i < PIXI . Texture . frameUpdates . length ; i ++ )
PIXI . WebGLRenderer . updateTextureFrame ( PIXI . Texture . frameUpdates [ i ] ) ;
for ( i = 0 ; i < PIXI . texturesToDestroy . length ; i ++ )
PIXI . WebGLRenderer . destroyTexture ( PIXI . texturesToDestroy [ i ] ) ;
PIXI . texturesToUpdate . length = 0 ;
PIXI . texturesToDestroy . length = 0 ;
PIXI . Texture . frameUpdates . length = 0 ;
} ;
/ * *
* Destroys a loaded webgl texture
*
* @ method destroyTexture
* @ param texture { Texture } The texture to update
* @ private
* /
PIXI . WebGLRenderer . destroyTexture = function ( texture )
{
//TODO break this out into a texture manager...
for ( var i = texture . _glTextures . length - 1 ; i >= 0 ; i -- )
{
var glTexture = texture . _glTextures [ i ] ;
var gl = PIXI . glContexts [ i ] ;
if ( gl && glTexture )
{
gl . deleteTexture ( glTexture ) ;
}
}
texture . _glTextures . length = 0 ;
} ;
/ * *
*
* @ method updateTextureFrame
* @ param texture { Texture } The texture to update the frame from
* @ private
* /
PIXI . WebGLRenderer . updateTextureFrame = function ( texture )
{
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 ( ) ;
} ;
/ * *
* resizes the webGL view to the specified width and height
*
* @ method resize
* @ param width { Number } the new width of the webGL view
* @ param height { Number } the new height of the webGL view
* /
PIXI . WebGLRenderer . prototype . resize = function ( width , height )
{
this . width = width ;
this . height = height ;
this . view . width = width ;
this . view . height = height ;
this . gl . viewport ( 0 , 0 , this . width , this . height ) ;
this . projection . x = this . width / 2 ;
this . projection . y = - this . height / 2 ;
} ;
/ * *
* Creates a WebGL texture
*
* @ method createWebGLTexture
* @ param texture { Texture } the texture to render
* @ param gl { webglContext } the WebGL context
* @ static
* /
PIXI . createWebGLTexture = function ( texture , gl )
{
if ( texture . hasLoaded )
{
texture . _glTextures [ gl . id ] = gl . createTexture ( ) ;
gl . bindTexture ( gl . TEXTURE _2D , texture . _glTextures [ gl . id ] ) ;
gl . pixelStorei ( gl . UNPACK _PREMULTIPLY _ALPHA _WEBGL , true ) ;
gl . texImage2D ( gl . TEXTURE _2D , 0 , gl . RGBA , gl . RGBA , gl . UNSIGNED _BYTE , texture . source ) ;
gl . texParameteri ( gl . TEXTURE _2D , gl . TEXTURE _MAG _FILTER , texture . scaleMode === PIXI . scaleModes . LINEAR ? gl . LINEAR : gl . NEAREST ) ;
gl . texParameteri ( gl . TEXTURE _2D , gl . TEXTURE _MIN _FILTER , texture . scaleMode === PIXI . scaleModes . LINEAR ? gl . LINEAR : gl . NEAREST ) ;
// reguler...
if ( ! texture . _powerOf2 )
{
gl . texParameteri ( gl . TEXTURE _2D , gl . TEXTURE _WRAP _S , gl . CLAMP _TO _EDGE ) ;
gl . texParameteri ( gl . TEXTURE _2D , gl . TEXTURE _WRAP _T , gl . CLAMP _TO _EDGE ) ;
}
else
{
gl . texParameteri ( gl . TEXTURE _2D , gl . TEXTURE _WRAP _S , gl . REPEAT ) ;
gl . texParameteri ( gl . TEXTURE _2D , gl . TEXTURE _WRAP _T , gl . REPEAT ) ;
}
gl . bindTexture ( gl . TEXTURE _2D , null ) ;
}
return texture . _glTextures [ gl . id ] ;
} ;
/ * *
* Updates a WebGL texture
*
* @ method updateWebGLTexture
* @ param texture { Texture } the texture to update
* @ param gl { webglContext } the WebGL context
* @ private
* /
PIXI . updateWebGLTexture = function ( texture , gl )
{
if ( texture . _glTextures [ gl . id ] )
{
gl . bindTexture ( gl . TEXTURE _2D , texture . _glTextures [ gl . id ] ) ;
gl . pixelStorei ( gl . UNPACK _PREMULTIPLY _ALPHA _WEBGL , true ) ;
gl . texImage2D ( gl . TEXTURE _2D , 0 , gl . RGBA , gl . RGBA , gl . UNSIGNED _BYTE , texture . source ) ;
gl . texParameteri ( gl . TEXTURE _2D , gl . TEXTURE _MAG _FILTER , texture . scaleMode === PIXI . scaleModes . LINEAR ? gl . LINEAR : gl . NEAREST ) ;
gl . texParameteri ( gl . TEXTURE _2D , gl . TEXTURE _MIN _FILTER , texture . scaleMode === PIXI . scaleModes . LINEAR ? gl . LINEAR : gl . NEAREST ) ;
// reguler...
if ( ! texture . _powerOf2 )
{
gl . texParameteri ( gl . TEXTURE _2D , gl . TEXTURE _WRAP _S , gl . CLAMP _TO _EDGE ) ;
gl . texParameteri ( gl . TEXTURE _2D , gl . TEXTURE _WRAP _T , gl . CLAMP _TO _EDGE ) ;
}
else
{
gl . texParameteri ( gl . TEXTURE _2D , gl . TEXTURE _WRAP _S , gl . REPEAT ) ;
gl . texParameteri ( gl . TEXTURE _2D , gl . TEXTURE _WRAP _T , gl . REPEAT ) ;
}
gl . bindTexture ( gl . TEXTURE _2D , null ) ;
}
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
} ;
/ * *
* Handles a lost webgl context
*
* @ method handleContextLost
* @ param event { Event }
* @ private
* /
PIXI . WebGLRenderer . prototype . handleContextLost = function ( event )
{
event . preventDefault ( ) ;
this . contextLost = true ;
} ;
/ * *
* Handles a restored webgl context
*
* @ method handleContextRestored
* @ param event { Event }
* @ private
* /
PIXI . WebGLRenderer . prototype . handleContextRestored = function ( )
{
//try 'experimental-webgl'
try {
this . gl = this . view . getContext ( 'experimental-webgl' , this . options ) ;
} catch ( e ) {
//try 'webgl'
try {
this . gl = this . view . getContext ( 'webgl' , this . options ) ;
} catch ( e2 ) {
// fail, not able to get a context
throw new Error ( ' This browser does not support webGL. Try using the canvas renderer' + this ) ;
}
}
var gl = this . gl ;
gl . id = PIXI . WebGLRenderer . glContextId ++ ;
// need to set the context...
this . shaderManager . setContext ( gl ) ;
this . spriteBatch . setContext ( gl ) ;
this . maskManager . setContext ( gl ) ;
this . filterManager . setContext ( gl ) ;
this . renderSession . gl = this . gl ;
gl . disable ( gl . DEPTH _TEST ) ;
gl . disable ( gl . CULL _FACE ) ;
gl . enable ( gl . BLEND ) ;
gl . colorMask ( true , true , true , this . transparent ) ;
this . gl . viewport ( 0 , 0 , this . width , this . height ) ;
for ( var key in PIXI . TextureCache )
{
var texture = PIXI . TextureCache [ key ] . baseTexture ;
texture . _glTextures = [ ] ;
}
/ * *
2014-04-01 02:02:36 +00:00
* Whether the context was lost
2014-02-28 09:30:53 +00:00
* @ property contextLost
* @ type Boolean
* /
this . contextLost = false ;
} ;
/ * *
* Removes everything from the renderer ( event listeners , spritebatch , etc ... )
*
* @ method destroy
* /
PIXI . WebGLRenderer . prototype . destroy = function ( )
{
// deal with losing context..
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
// remove listeners
this . view . removeEventListener ( 'webglcontextlost' , this . contextLost ) ;
this . view . removeEventListener ( 'webglcontextrestored' , this . contextRestoredLost ) ;
PIXI . glContexts [ this . glContextId ] = null ;
this . projection = null ;
this . offset = null ;
// time to create the render managers! each one focuses on managine a state in webGL
this . shaderManager . destroy ( ) ;
this . spriteBatch . destroy ( ) ;
this . maskManager . destroy ( ) ;
this . filterManager . destroy ( ) ;
this . shaderManager = null ;
this . spriteBatch = null ;
this . maskManager = null ;
this . filterManager = null ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
this . gl = null ;
//
this . renderSession = null ;
} ;
PIXI . WebGLRenderer . glContextId = 0 ;
/ * *
* @ author Mat Groves http : //matgroves.com/ @Doormat23
* /
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
/ * *
* @ class WebGLMaskManager
* @ constructor
* @ param gl { WebGLContext } the current WebGL drawing context
* @ private
* /
PIXI . WebGLMaskManager = function ( gl )
{
this . maskStack = [ ] ;
this . maskPosition = 0 ;
this . setContext ( gl ) ;
} ;
/ * *
* Sets the drawing context to the one given in parameter
2014-04-01 02:02:36 +00:00
* @ method setContext
2014-02-28 09:30:53 +00:00
* @ param gl { WebGLContext } the current WebGL drawing context
* /
PIXI . WebGLMaskManager . prototype . setContext = function ( gl )
{
this . gl = gl ;
} ;
/ * *
* Applies the Mask and adds it to the current filter stack
* @ method pushMask
* @ param maskData { Array }
* @ param renderSession { RenderSession }
* /
PIXI . WebGLMaskManager . prototype . pushMask = function ( maskData , renderSession )
{
var gl = this . gl ;
if ( this . maskStack . length === 0 )
{
gl . enable ( gl . STENCIL _TEST ) ;
gl . stencilFunc ( gl . ALWAYS , 1 , 1 ) ;
}
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
// maskData.visible = false;
this . maskStack . push ( maskData ) ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
gl . colorMask ( false , false , false , true ) ;
gl . stencilOp ( gl . KEEP , gl . KEEP , gl . INCR ) ;
PIXI . WebGLGraphics . renderGraphics ( maskData , renderSession ) ;
gl . colorMask ( true , true , true , true ) ;
gl . stencilFunc ( gl . NOTEQUAL , 0 , this . maskStack . length ) ;
gl . stencilOp ( gl . KEEP , gl . KEEP , gl . KEEP ) ;
} ;
/ * *
* Removes the last filter from the filter stack and doesn ' t return it
* @ method popMask
*
* @ param renderSession { RenderSession } an object containing all the useful parameters
* /
PIXI . WebGLMaskManager . prototype . popMask = function ( renderSession )
{
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 , renderSession ) ;
gl . colorMask ( true , true , true , true ) ;
gl . stencilFunc ( gl . NOTEQUAL , 0 , this . maskStack . length ) ;
gl . stencilOp ( gl . KEEP , gl . KEEP , gl . KEEP ) ;
}
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
if ( this . maskStack . length === 0 ) gl . disable ( gl . STENCIL _TEST ) ;
} ;
/ * *
* Destroys the mask stack
* @ method destroy
* /
PIXI . WebGLMaskManager . prototype . destroy = function ( )
{
this . maskStack = null ;
this . gl = null ;
} ;
/ * *
* @ author Mat Groves http : //matgroves.com/ @Doormat23
* /
/ * *
* @ class WebGLShaderManager
* @ constructor
* @ param gl { WebGLContext } the current WebGL drawing context
* @ private
* /
PIXI . WebGLShaderManager = function ( gl )
{
this . maxAttibs = 10 ;
this . attribState = [ ] ;
this . tempAttribState = [ ] ;
for ( var i = 0 ; i < this . maxAttibs ; i ++ ) {
this . attribState [ i ] = false ;
}
this . setContext ( gl ) ;
// the final one is used for the rendering strips
//this.stripShader = new PIXI.StripShader(gl);
} ;
/ * *
* Initialises the context and the properties
2014-04-01 02:02:36 +00:00
* @ method setContext
2014-02-28 09:30:53 +00:00
* @ param gl { WebGLContext } the current WebGL drawing context
* @ param transparent { Boolean } Whether or not the drawing context should be transparent
* /
PIXI . WebGLShaderManager . prototype . setContext = function ( gl )
{
this . gl = gl ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
// the next one is used for rendering primatives
this . primitiveShader = new PIXI . PrimitiveShader ( gl ) ;
// this shader is used for the default sprite rendering
this . defaultShader = new PIXI . PixiShader ( gl ) ;
// this shader is used for the fast sprite rendering
this . fastShader = new PIXI . PixiFastShader ( gl ) ;
this . activateShader ( this . defaultShader ) ;
} ;
/ * *
2014-04-01 02:02:36 +00:00
* Takes the attributes given in parameters
2014-02-28 09:30:53 +00:00
* @ method setAttribs
2014-04-01 02:02:36 +00:00
* @ param attribs { Array } attribs
2014-02-28 09:30:53 +00:00
* /
PIXI . WebGLShaderManager . prototype . setAttribs = function ( attribs )
{
// reset temp state
var i ;
for ( i = 0 ; i < this . tempAttribState . length ; i ++ )
{
this . tempAttribState [ i ] = false ;
}
// set the new attribs
for ( i = 0 ; i < attribs . length ; i ++ )
{
var attribId = attribs [ i ] ;
this . tempAttribState [ attribId ] = true ;
}
var gl = this . gl ;
for ( i = 0 ; i < this . attribState . length ; i ++ )
{
if ( this . attribState [ i ] !== this . tempAttribState [ i ] )
{
this . attribState [ i ] = this . tempAttribState [ i ] ;
if ( this . tempAttribState [ i ] )
{
gl . enableVertexAttribArray ( i ) ;
}
else
{
gl . disableVertexAttribArray ( i ) ;
}
}
}
} ;
/ * *
2014-04-01 02:02:36 +00:00
* Sets - up the given shader
2014-02-28 09:30:53 +00:00
*
* @ method activateShader
* @ param shader { Object } the shader that is going to be activated
* /
PIXI . WebGLShaderManager . prototype . activateShader = function ( shader )
{
//if(this.currentShader == shader)return;
this . currentShader = shader ;
this . gl . useProgram ( shader . program ) ;
this . setAttribs ( shader . attributes ) ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
} ;
/ * *
* Triggers the primitive shader
* @ method activatePrimitiveShader
* /
PIXI . WebGLShaderManager . prototype . activatePrimitiveShader = function ( )
{
var gl = this . gl ;
gl . useProgram ( this . primitiveShader . program ) ;
this . setAttribs ( this . primitiveShader . attributes ) ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
} ;
/ * *
* Disable the primitive shader
* @ method deactivatePrimitiveShader
* /
PIXI . WebGLShaderManager . prototype . deactivatePrimitiveShader = function ( )
{
var gl = this . gl ;
gl . useProgram ( this . defaultShader . program ) ;
this . setAttribs ( this . defaultShader . attributes ) ;
} ;
/ * *
* Destroys
* @ method destroy
* /
PIXI . WebGLShaderManager . prototype . destroy = function ( )
{
this . attribState = null ;
this . tempAttribState = null ;
this . primitiveShader . destroy ( ) ;
this . defaultShader . destroy ( ) ;
this . fastShader . destroy ( ) ;
this . gl = null ;
} ;
/ * *
* @ author Mat Groves
2014-04-01 02:02:36 +00:00
*
2014-02-28 09:30:53 +00:00
* Big thanks to the very clever Matt DesLauriers < mattdesl > https : //github.com/mattdesl/
* for creating the original pixi version !
*
* Heavily inspired by LibGDX ' s WebGLSpriteBatch :
* https : //github.com/libgdx/libgdx/blob/master/gdx/src/com/badlogic/gdx/graphics/g2d/WebGLSpriteBatch.java
* /
/ * *
*
* @ class WebGLSpriteBatch
* @ private
* @ constructor
* @ param gl { WebGLContext } the current WebGL drawing context
*
* /
PIXI . WebGLSpriteBatch = function ( gl )
{
/ * *
2014-04-01 02:02:36 +00:00
*
2014-02-28 09:30:53 +00:00
*
* @ property vertSize
* @ type Number
* /
this . vertSize = 6 ;
/ * *
* The number of images in the SpriteBatch before it flushes
* @ property size
* @ type Number
* /
2014-03-04 01:29:04 +00:00
this . size = 2000 ; //Math.pow(2, 16) / this.vertSize;
2014-02-28 09:30:53 +00:00
//the total number of floats in our batch
var numVerts = this . size * 4 * this . vertSize ;
//the total number of indices in our batch
var numIndices = this . size * 6 ;
//vertex data
/ * *
* Holds the vertices
*
* @ property vertices
* @ type Float32Array
* /
this . vertices = new Float32Array ( numVerts ) ;
//index data
/ * *
* Holds the indices
*
* @ property indices
* @ type Uint16Array
* /
this . indices = new Uint16Array ( numIndices ) ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
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 ;
}
this . drawing = false ;
this . currentBatchSize = 0 ;
this . currentBaseTexture = null ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
this . setContext ( gl ) ;
} ;
/ * *
2014-04-01 02:02:36 +00:00
*
2014-02-28 09:30:53 +00:00
* @ method setContext
*
* @ param gl { WebGLContext } the current WebGL drawing context
* /
PIXI . WebGLSpriteBatch . prototype . setContext = function ( gl )
{
this . gl = gl ;
// create a couple of buffers
this . vertexBuffer = gl . createBuffer ( ) ;
this . indexBuffer = gl . createBuffer ( ) ;
// 65535 is max index, so 65535 / 6 = 10922.
//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 . currentBlendMode = 99999 ;
} ;
/ * *
2014-04-01 02:02:36 +00:00
*
2014-02-28 09:30:53 +00:00
* @ method begin
*
* @ param renderSession { RenderSession } the RenderSession
* /
PIXI . WebGLSpriteBatch . prototype . begin = function ( renderSession )
{
this . renderSession = renderSession ;
this . shader = this . renderSession . shaderManager . defaultShader ;
this . start ( ) ;
} ;
/ * *
2014-04-01 02:02:36 +00:00
*
2014-02-28 09:30:53 +00:00
* @ method end
*
* /
PIXI . WebGLSpriteBatch . prototype . end = function ( )
{
this . flush ( ) ;
} ;
/ * *
2014-04-01 02:02:36 +00:00
*
2014-02-28 09:30:53 +00:00
* @ method render
2014-04-01 02:02:36 +00:00
*
2014-02-28 09:30:53 +00:00
* @ param sprite { Sprite } the sprite to render when using this spritebatch
* /
PIXI . WebGLSpriteBatch . prototype . render = function ( sprite )
{
var texture = sprite . texture ;
// check texture..
if ( texture . baseTexture !== this . currentBaseTexture || this . currentBatchSize >= this . size )
{
this . flush ( ) ;
this . currentBaseTexture = texture . baseTexture ;
}
// check blend mode
if ( sprite . blendMode !== this . currentBlendMode )
{
this . setBlendMode ( sprite . blendMode ) ;
}
// get the uvs for the texture
var uvs = sprite . _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 . worldAlpha ;
var tint = sprite . tint ;
var verticies = this . vertices ;
// TODO trim??
var aX = sprite . anchor . x ;
var aY = sprite . anchor . y ;
var w0 , w1 , h0 , h1 ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
if ( sprite . texture . trim )
{
// if the sprite is trimmed then we need to add the extra space before transforming the sprite coords..
var trim = sprite . texture . trim ;
w1 = trim . x - aX * trim . width ;
w0 = w1 + texture . frame . width ;
h1 = trim . y - aY * trim . height ;
h0 = h1 + texture . frame . height ;
}
else
{
w0 = ( texture . frame . width ) * ( 1 - aX ) ;
w1 = ( texture . frame . width ) * - aX ;
h0 = texture . frame . height * ( 1 - aY ) ;
h1 = texture . frame . height * - aY ;
}
var index = this . currentBatchSize * 4 * this . vertSize ;
var worldTransform = sprite . worldTransform ; //.toArray();
var a = worldTransform . a ; //[0];
var b = worldTransform . c ; //[3];
var c = worldTransform . b ; //[1];
var d = worldTransform . d ; //[4];
var tx = worldTransform . tx ; //[2];
var ty = worldTransform . ty ; ///[5];
// xy
verticies [ index ++ ] = a * w1 + c * h1 + tx ;
verticies [ index ++ ] = d * h1 + b * w1 + ty ;
// uv
verticies [ index ++ ] = uvs . x0 ;
verticies [ index ++ ] = uvs . y0 ;
// color
verticies [ index ++ ] = alpha ;
verticies [ index ++ ] = tint ;
// xy
verticies [ index ++ ] = a * w0 + c * h1 + tx ;
verticies [ index ++ ] = d * h1 + b * w0 + ty ;
// uv
verticies [ index ++ ] = uvs . x1 ;
verticies [ index ++ ] = uvs . y1 ;
// color
verticies [ index ++ ] = alpha ;
verticies [ index ++ ] = tint ;
// xy
verticies [ index ++ ] = a * w0 + c * h0 + tx ;
verticies [ index ++ ] = d * h0 + b * w0 + ty ;
// uv
verticies [ index ++ ] = uvs . x2 ;
verticies [ index ++ ] = uvs . y2 ;
// color
verticies [ index ++ ] = alpha ;
verticies [ index ++ ] = tint ;
// xy
verticies [ index ++ ] = a * w1 + c * h0 + tx ;
verticies [ index ++ ] = d * h0 + b * w1 + ty ;
// uv
verticies [ index ++ ] = uvs . x3 ;
verticies [ index ++ ] = uvs . y3 ;
// color
verticies [ index ++ ] = alpha ;
verticies [ index ++ ] = tint ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
// increment the batchsize
this . currentBatchSize ++ ;
} ;
/ * *
* Renders a tilingSprite using the spriteBatch
* @ method renderTilingSprite
2014-04-01 02:02:36 +00:00
*
2014-02-28 09:30:53 +00:00
* @ param sprite { TilingSprite } the tilingSprite to render
* /
PIXI . WebGLSpriteBatch . prototype . renderTilingSprite = function ( tilingSprite )
{
var texture = tilingSprite . tilingTexture ;
if ( texture . baseTexture !== this . currentBaseTexture || this . currentBatchSize >= this . size )
{
this . flush ( ) ;
this . currentBaseTexture = texture . baseTexture ;
}
// check blend mode
if ( tilingSprite . blendMode !== this . currentBlendMode )
{
this . setBlendMode ( tilingSprite . blendMode ) ;
}
// set the textures uvs temporarily
// TODO create a separate texture so that we can tile part of a texture
if ( ! tilingSprite . _uvs ) tilingSprite . _uvs = new PIXI . TextureUvs ( ) ;
var uvs = tilingSprite . _uvs ;
tilingSprite . tilePosition . x %= texture . baseTexture . width * tilingSprite . tileScaleOffset . x ;
tilingSprite . tilePosition . y %= texture . baseTexture . height * tilingSprite . tileScaleOffset . y ;
var offsetX = tilingSprite . tilePosition . x / ( texture . baseTexture . width * tilingSprite . tileScaleOffset . x ) ;
var offsetY = tilingSprite . tilePosition . y / ( texture . baseTexture . height * tilingSprite . tileScaleOffset . y ) ;
var scaleX = ( tilingSprite . width / texture . baseTexture . width ) / ( tilingSprite . tileScale . x * tilingSprite . tileScaleOffset . x ) ;
var scaleY = ( tilingSprite . height / texture . baseTexture . height ) / ( tilingSprite . tileScale . y * tilingSprite . tileScaleOffset . y ) ;
uvs . x0 = 0 - offsetX ;
uvs . y0 = 0 - offsetY ;
uvs . x1 = ( 1 * scaleX ) - offsetX ;
uvs . y1 = 0 - offsetY ;
uvs . x2 = ( 1 * scaleX ) - offsetX ;
uvs . y2 = ( 1 * scaleY ) - offsetY ;
uvs . x3 = 0 - offsetX ;
uvs . y3 = ( 1 * scaleY ) - offsetY ;
// get the tilingSprites current alpha
var alpha = tilingSprite . worldAlpha ;
var tint = tilingSprite . tint ;
var verticies = this . vertices ;
var width = tilingSprite . width ;
var height = tilingSprite . height ;
// TODO trim??
var aX = tilingSprite . anchor . x ; // - tilingSprite.texture.trim.x
var aY = tilingSprite . anchor . y ; //- tilingSprite.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 * this . vertSize ;
var worldTransform = tilingSprite . worldTransform ;
var a = worldTransform . a ; //[0];
var b = worldTransform . c ; //[3];
var c = worldTransform . b ; //[1];
var d = worldTransform . d ; //[4];
var tx = worldTransform . tx ; //[2];
var ty = worldTransform . ty ; ///[5];
// xy
verticies [ index ++ ] = a * w1 + c * h1 + tx ;
verticies [ index ++ ] = d * h1 + b * w1 + ty ;
// uv
verticies [ index ++ ] = uvs . x0 ;
verticies [ index ++ ] = uvs . y0 ;
// color
verticies [ index ++ ] = alpha ;
verticies [ index ++ ] = tint ;
// xy
verticies [ index ++ ] = a * w0 + c * h1 + tx ;
verticies [ index ++ ] = d * h1 + b * w0 + ty ;
// uv
verticies [ index ++ ] = uvs . x1 ;
verticies [ index ++ ] = uvs . y1 ;
// color
verticies [ index ++ ] = alpha ;
verticies [ index ++ ] = tint ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
// xy
verticies [ index ++ ] = a * w0 + c * h0 + tx ;
verticies [ index ++ ] = d * h0 + b * w0 + ty ;
// uv
verticies [ index ++ ] = uvs . x2 ;
verticies [ index ++ ] = uvs . y2 ;
// color
verticies [ index ++ ] = alpha ;
verticies [ index ++ ] = tint ;
// xy
verticies [ index ++ ] = a * w1 + c * h0 + tx ;
verticies [ index ++ ] = d * h0 + b * w1 + ty ;
// uv
verticies [ index ++ ] = uvs . x3 ;
verticies [ index ++ ] = uvs . y3 ;
// color
verticies [ index ++ ] = alpha ;
verticies [ index ++ ] = tint ;
// increment the batchs
this . currentBatchSize ++ ;
} ;
/ * *
* Renders the content and empties the current batch
*
* @ method flush
2014-04-01 02:02:36 +00:00
*
2014-02-28 09:30:53 +00:00
* /
PIXI . WebGLSpriteBatch . prototype . flush = function ( )
{
// If the batch is length 0 then return as there is nothing to draw
if ( this . currentBatchSize === 0 ) return ;
var gl = this . gl ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
// bind the current texture
gl . bindTexture ( gl . TEXTURE _2D , this . currentBaseTexture . _glTextures [ gl . id ] || PIXI . createWebGLTexture ( this . currentBaseTexture , gl ) ) ;
// upload the verts to the buffer
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
if ( this . currentBatchSize > ( this . size * 0.5 ) )
{
gl . bufferSubData ( gl . ARRAY _BUFFER , 0 , this . vertices ) ;
}
else
{
var view = this . vertices . subarray ( 0 , this . currentBatchSize * 4 * this . vertSize ) ;
gl . bufferSubData ( gl . ARRAY _BUFFER , 0 , view ) ;
}
// var view = this.vertices.subarray(0, this.currentBatchSize * 4 * this.vertSize);
//gl.bufferSubData(gl.ARRAY_BUFFER, 0, view);
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
// now draw those suckas!
gl . drawElements ( gl . TRIANGLES , this . currentBatchSize * 6 , gl . UNSIGNED _SHORT , 0 ) ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
// then reset the batch!
this . currentBatchSize = 0 ;
// increment the draw count
this . renderSession . drawCount ++ ;
} ;
/ * *
2014-04-01 02:02:36 +00:00
*
2014-02-28 09:30:53 +00:00
* @ method stop
*
* /
PIXI . WebGLSpriteBatch . prototype . stop = function ( )
{
this . flush ( ) ;
} ;
/ * *
2014-04-01 02:02:36 +00:00
*
2014-02-28 09:30:53 +00:00
* @ method start
*
* /
PIXI . WebGLSpriteBatch . prototype . start = function ( )
{
var gl = this . gl ;
// bind the main texture
gl . activeTexture ( gl . TEXTURE0 ) ;
// bind the buffers
gl . bindBuffer ( gl . ARRAY _BUFFER , this . vertexBuffer ) ;
gl . bindBuffer ( gl . ELEMENT _ARRAY _BUFFER , this . indexBuffer ) ;
// set the projection
var projection = this . renderSession . projection ;
gl . uniform2f ( this . shader . projectionVector , projection . x , projection . y ) ;
// set the pointers
var stride = this . vertSize * 4 ;
gl . vertexAttribPointer ( this . shader . aVertexPosition , 2 , gl . FLOAT , false , stride , 0 ) ;
gl . vertexAttribPointer ( this . shader . aTextureCoord , 2 , gl . FLOAT , false , stride , 2 * 4 ) ;
gl . vertexAttribPointer ( this . shader . colorAttribute , 2 , gl . FLOAT , false , stride , 4 * 4 ) ;
// set the blend mode..
if ( this . currentBlendMode !== PIXI . blendModes . NORMAL )
{
this . setBlendMode ( PIXI . blendModes . NORMAL ) ;
}
} ;
/ * *
* Sets - up the given blendMode from WebGL ' s point of view
2014-04-01 02:02:36 +00:00
* @ method setBlendMode
2014-02-28 09:30:53 +00:00
*
* @ param blendMode { Number } the blendMode , should be a Pixi const , such as PIXI . BlendModes . ADD
* /
PIXI . WebGLSpriteBatch . prototype . setBlendMode = function ( blendMode )
{
this . flush ( ) ;
this . currentBlendMode = blendMode ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
var blendModeWebGL = PIXI . blendModesWebGL [ this . currentBlendMode ] ;
this . gl . blendFunc ( blendModeWebGL [ 0 ] , blendModeWebGL [ 1 ] ) ;
} ;
/ * *
* Destroys the SpriteBatch
* @ method destroy
* /
PIXI . WebGLSpriteBatch . prototype . destroy = function ( )
{
this . vertices = null ;
this . indices = null ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
this . gl . deleteBuffer ( this . vertexBuffer ) ;
this . gl . deleteBuffer ( this . indexBuffer ) ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
this . currentBaseTexture = null ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
this . gl = null ;
} ;
/ * *
* @ author Mat Groves
2014-04-01 02:02:36 +00:00
*
2014-02-28 09:30:53 +00:00
* Big thanks to the very clever Matt DesLauriers < mattdesl > https : //github.com/mattdesl/
* for creating the original pixi version !
*
* Heavily inspired by LibGDX ' s WebGLSpriteBatch :
* https : //github.com/libgdx/libgdx/blob/master/gdx/src/com/badlogic/gdx/graphics/g2d/WebGLSpriteBatch.java
* /
PIXI . WebGLFastSpriteBatch = function ( gl )
{
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
this . vertSize = 10 ;
this . maxSize = 6000 ; //Math.pow(2, 16) / this.vertSize;
this . size = this . maxSize ;
//the total number of floats in our batch
var numVerts = this . size * 4 * this . vertSize ;
//the total number of indices in our batch
var numIndices = this . maxSize * 6 ;
//vertex data
this . vertices = new Float32Array ( numVerts ) ;
//index data
this . indices = new Uint16Array ( numIndices ) ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
this . vertexBuffer = null ;
this . indexBuffer = null ;
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 ;
}
this . drawing = false ;
this . currentBatchSize = 0 ;
this . currentBaseTexture = null ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
this . currentBlendMode = 0 ;
this . renderSession = null ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
this . shader = null ;
this . matrix = null ;
this . setContext ( gl ) ;
} ;
PIXI . WebGLFastSpriteBatch . prototype . setContext = function ( gl )
{
this . gl = gl ;
// create a couple of buffers
this . vertexBuffer = gl . createBuffer ( ) ;
this . indexBuffer = gl . createBuffer ( ) ;
// 65535 is max index, so 65535 / 6 = 10922.
//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 . currentBlendMode = 99999 ;
} ;
PIXI . WebGLFastSpriteBatch . prototype . begin = function ( spriteBatch , renderSession )
{
this . renderSession = renderSession ;
this . shader = this . renderSession . shaderManager . fastShader ;
this . matrix = spriteBatch . worldTransform . toArray ( true ) ;
this . start ( ) ;
} ;
PIXI . WebGLFastSpriteBatch . prototype . end = function ( )
{
this . flush ( ) ;
} ;
PIXI . WebGLFastSpriteBatch . prototype . render = function ( spriteBatch )
{
var children = spriteBatch . children ;
var sprite = children [ 0 ] ;
// if the uvs have not updated then no point rendering just yet!
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
// check texture.
if ( ! sprite . texture . _uvs ) return ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
this . currentBaseTexture = sprite . texture . baseTexture ;
// check blend mode
if ( sprite . blendMode !== this . currentBlendMode )
{
this . setBlendMode ( sprite . blendMode ) ;
}
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
for ( var i = 0 , j = children . length ; i < j ; i ++ )
{
this . renderSprite ( children [ i ] ) ;
}
this . flush ( ) ;
} ;
PIXI . WebGLFastSpriteBatch . prototype . renderSprite = function ( sprite )
{
//sprite = children[i];
2014-02-28 18:55:07 +00:00
if ( ! sprite . visible ) return ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
// TODO trim??
if ( sprite . texture . baseTexture !== this . currentBaseTexture )
{
this . flush ( ) ;
this . currentBaseTexture = sprite . texture . baseTexture ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
if ( ! sprite . texture . _uvs ) return ;
}
var uvs , verticies = this . vertices , width , height , w0 , w1 , h0 , h1 , index ;
uvs = sprite . texture . _uvs ;
width = sprite . texture . frame . width ;
height = sprite . texture . frame . height ;
if ( sprite . texture . trim )
{
// if the sprite is trimmed then we need to add the extra space before transforming the sprite coords..
var trim = sprite . texture . trim ;
w1 = trim . x - sprite . anchor . x * trim . width ;
w0 = w1 + sprite . texture . frame . width ;
h1 = trim . y - sprite . anchor . y * trim . height ;
h0 = h1 + sprite . texture . frame . height ;
}
else
{
w0 = ( sprite . texture . frame . width ) * ( 1 - sprite . anchor . x ) ;
w1 = ( sprite . texture . frame . width ) * - sprite . anchor . x ;
h0 = sprite . texture . frame . height * ( 1 - sprite . anchor . y ) ;
h1 = sprite . texture . frame . height * - sprite . anchor . y ;
}
index = this . currentBatchSize * 4 * this . vertSize ;
// xy
verticies [ index ++ ] = w1 ;
verticies [ index ++ ] = h1 ;
verticies [ index ++ ] = sprite . position . x ;
verticies [ index ++ ] = sprite . position . y ;
//scale
verticies [ index ++ ] = sprite . scale . x ;
verticies [ index ++ ] = sprite . scale . y ;
//rotation
verticies [ index ++ ] = sprite . rotation ;
// uv
verticies [ index ++ ] = uvs . x0 ;
verticies [ index ++ ] = uvs . y1 ;
// color
verticies [ index ++ ] = sprite . alpha ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
// xy
verticies [ index ++ ] = w0 ;
verticies [ index ++ ] = h1 ;
verticies [ index ++ ] = sprite . position . x ;
verticies [ index ++ ] = sprite . position . y ;
//scale
verticies [ index ++ ] = sprite . scale . x ;
verticies [ index ++ ] = sprite . scale . y ;
//rotation
verticies [ index ++ ] = sprite . rotation ;
// uv
verticies [ index ++ ] = uvs . x1 ;
verticies [ index ++ ] = uvs . y1 ;
// color
verticies [ index ++ ] = sprite . alpha ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
// xy
verticies [ index ++ ] = w0 ;
verticies [ index ++ ] = h0 ;
verticies [ index ++ ] = sprite . position . x ;
verticies [ index ++ ] = sprite . position . y ;
//scale
verticies [ index ++ ] = sprite . scale . x ;
verticies [ index ++ ] = sprite . scale . y ;
//rotation
verticies [ index ++ ] = sprite . rotation ;
// uv
verticies [ index ++ ] = uvs . x2 ;
verticies [ index ++ ] = uvs . y2 ;
// color
verticies [ index ++ ] = sprite . alpha ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
// xy
verticies [ index ++ ] = w1 ;
verticies [ index ++ ] = h0 ;
verticies [ index ++ ] = sprite . position . x ;
verticies [ index ++ ] = sprite . position . y ;
//scale
verticies [ index ++ ] = sprite . scale . x ;
verticies [ index ++ ] = sprite . scale . y ;
//rotation
verticies [ index ++ ] = sprite . rotation ;
// uv
verticies [ index ++ ] = uvs . x3 ;
verticies [ index ++ ] = uvs . y3 ;
// color
verticies [ index ++ ] = sprite . alpha ;
// increment the batchs
this . currentBatchSize ++ ;
if ( this . currentBatchSize >= this . size )
{
this . flush ( ) ;
}
} ;
PIXI . WebGLFastSpriteBatch . prototype . flush = function ( )
{
// If the batch is length 0 then return as there is nothing to draw
if ( this . currentBatchSize === 0 ) return ;
var gl = this . gl ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
// bind the current texture
if ( ! this . currentBaseTexture . _glTextures [ gl . id ] ) PIXI . createWebGLTexture ( this . currentBaseTexture , gl ) ;
gl . bindTexture ( gl . TEXTURE _2D , this . currentBaseTexture . _glTextures [ gl . id ] ) ; // || PIXI.createWebGLTexture(this.currentBaseTexture, gl));
// upload the verts to the buffer
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
if ( this . currentBatchSize > ( this . size * 0.5 ) )
{
gl . bufferSubData ( gl . ARRAY _BUFFER , 0 , this . vertices ) ;
}
else
{
var view = this . vertices . subarray ( 0 , this . currentBatchSize * 4 * this . vertSize ) ;
gl . bufferSubData ( gl . ARRAY _BUFFER , 0 , view ) ;
}
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
// now draw those suckas!
gl . drawElements ( gl . TRIANGLES , this . currentBatchSize * 6 , gl . UNSIGNED _SHORT , 0 ) ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
// then reset the batch!
this . currentBatchSize = 0 ;
// increment the draw count
this . renderSession . drawCount ++ ;
} ;
PIXI . WebGLFastSpriteBatch . prototype . stop = function ( )
{
this . flush ( ) ;
} ;
PIXI . WebGLFastSpriteBatch . prototype . start = function ( )
{
var gl = this . gl ;
// bind the main texture
gl . activeTexture ( gl . TEXTURE0 ) ;
// bind the buffers
gl . bindBuffer ( gl . ARRAY _BUFFER , this . vertexBuffer ) ;
gl . bindBuffer ( gl . ELEMENT _ARRAY _BUFFER , this . indexBuffer ) ;
// set the projection
var projection = this . renderSession . projection ;
gl . uniform2f ( this . shader . projectionVector , projection . x , projection . y ) ;
// set the matrix
gl . uniformMatrix3fv ( this . shader . uMatrix , false , this . matrix ) ;
// set the pointers
var stride = this . vertSize * 4 ;
gl . vertexAttribPointer ( this . shader . aVertexPosition , 2 , gl . FLOAT , false , stride , 0 ) ;
gl . vertexAttribPointer ( this . shader . aPositionCoord , 2 , gl . FLOAT , false , stride , 2 * 4 ) ;
gl . vertexAttribPointer ( this . shader . aScale , 2 , gl . FLOAT , false , stride , 4 * 4 ) ;
gl . vertexAttribPointer ( this . shader . aRotation , 1 , gl . FLOAT , false , stride , 6 * 4 ) ;
gl . vertexAttribPointer ( this . shader . aTextureCoord , 2 , gl . FLOAT , false , stride , 7 * 4 ) ;
gl . vertexAttribPointer ( this . shader . colorAttribute , 1 , gl . FLOAT , false , stride , 9 * 4 ) ;
// set the blend mode..
if ( this . currentBlendMode !== PIXI . blendModes . NORMAL )
{
this . setBlendMode ( PIXI . blendModes . NORMAL ) ;
}
} ;
PIXI . WebGLFastSpriteBatch . prototype . setBlendMode = function ( blendMode )
{
this . flush ( ) ;
this . currentBlendMode = blendMode ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
var blendModeWebGL = PIXI . blendModesWebGL [ this . currentBlendMode ] ;
this . gl . blendFunc ( blendModeWebGL [ 0 ] , blendModeWebGL [ 1 ] ) ;
} ;
/ * *
* @ author Mat Groves http : //matgroves.com/ @Doormat23
* /
/ * *
* @ class WebGLFilterManager
* @ constructor
* @ param gl { WebGLContext } the current WebGL drawing context
* @ param transparent { Boolean } Whether or not the drawing context should be transparent
* @ private
* /
PIXI . WebGLFilterManager = function ( gl , transparent )
{
this . transparent = transparent ;
this . filterStack = [ ] ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
this . offsetX = 0 ;
this . offsetY = 0 ;
this . setContext ( gl ) ;
} ;
// API
/ * *
* Initialises the context and the properties
2014-04-01 02:02:36 +00:00
* @ method setContext
2014-02-28 09:30:53 +00:00
* @ param gl { WebGLContext } the current WebGL drawing context
* /
PIXI . WebGLFilterManager . prototype . setContext = function ( gl )
{
this . gl = gl ;
this . texturePool = [ ] ;
this . initShaderBuffers ( ) ;
} ;
/ * *
2014-04-01 02:02:36 +00:00
*
2014-02-28 09:30:53 +00:00
* @ method begin
2014-04-01 02:02:36 +00:00
* @ param renderSession { RenderSession }
* @ param buffer { ArrayBuffer }
2014-02-28 09:30:53 +00:00
* /
PIXI . WebGLFilterManager . prototype . begin = function ( renderSession , buffer )
{
this . renderSession = renderSession ;
this . defaultShader = renderSession . shaderManager . defaultShader ;
var projection = this . renderSession . projection ;
// console.log(this.width)
this . width = projection . x * 2 ;
this . height = - projection . y * 2 ;
this . buffer = buffer ;
} ;
/ * *
* Applies the filter and adds it to the current filter stack
* @ method pushFilter
* @ param filterBlock { Object } the filter that will be pushed to the current filter stack
* /
PIXI . WebGLFilterManager . prototype . pushFilter = function ( filterBlock )
{
var gl = this . gl ;
var projection = this . renderSession . projection ;
var offset = this . renderSession . offset ;
2014-04-01 02:02:36 +00:00
filterBlock . _filterArea = filterBlock . target . filterArea || filterBlock . target . getBounds ( ) ;
2014-02-28 09:30:53 +00:00
// filter program
// OPTIMISATION - the first filter is free if its a simple color change?
this . filterStack . push ( filterBlock ) ;
var filter = filterBlock . filterPasses [ 0 ] ;
2014-04-01 02:02:36 +00:00
this . offsetX += filterBlock . _filterArea . x ;
this . offsetY += filterBlock . _filterArea . y ;
2014-02-28 09:30:53 +00:00
var texture = this . texturePool . pop ( ) ;
if ( ! texture )
{
texture = new PIXI . FilterTexture ( this . gl , this . width , this . height ) ;
}
else
{
texture . resize ( this . width , this . height ) ;
}
gl . bindTexture ( gl . TEXTURE _2D , texture . texture ) ;
2014-04-01 02:02:36 +00:00
var filterArea = filterBlock . _filterArea ; // filterBlock.target.getBounds();///filterBlock.target.filterArea;
2014-02-28 09:30:53 +00:00
var padidng = filter . padding ;
filterArea . x -= padidng ;
filterArea . y -= padidng ;
filterArea . width += padidng * 2 ;
filterArea . height += padidng * 2 ;
// cap filter to screen size..
if ( filterArea . x < 0 ) filterArea . x = 0 ;
if ( filterArea . width > this . width ) filterArea . width = this . width ;
if ( filterArea . y < 0 ) filterArea . y = 0 ;
if ( filterArea . height > this . height ) filterArea . height = this . height ;
//gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, filterArea.width, filterArea.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
gl . bindFramebuffer ( gl . FRAMEBUFFER , texture . frameBuffer ) ;
// set view port
gl . viewport ( 0 , 0 , filterArea . width , filterArea . height ) ;
projection . x = filterArea . width / 2 ;
projection . y = - filterArea . height / 2 ;
offset . x = - filterArea . x ;
offset . y = - filterArea . y ;
// update projection
gl . uniform2f ( this . defaultShader . projectionVector , filterArea . width / 2 , - filterArea . height / 2 ) ;
gl . uniform2f ( this . defaultShader . offsetVector , - filterArea . x , - filterArea . y ) ;
gl . colorMask ( true , true , true , true ) ;
gl . clearColor ( 0 , 0 , 0 , 0 ) ;
gl . clear ( gl . COLOR _BUFFER _BIT ) ;
filterBlock . _glFilterTexture = texture ;
} ;
/ * *
* Removes the last filter from the filter stack and doesn ' t return it
* @ method popFilter
* /
PIXI . WebGLFilterManager . prototype . popFilter = function ( )
{
var gl = this . gl ;
var filterBlock = this . filterStack . pop ( ) ;
2014-04-01 02:02:36 +00:00
var filterArea = filterBlock . _filterArea ;
2014-02-28 09:30:53 +00:00
var texture = filterBlock . _glFilterTexture ;
var projection = this . renderSession . projection ;
var offset = this . renderSession . offset ;
if ( filterBlock . filterPasses . length > 1 )
{
gl . viewport ( 0 , 0 , filterArea . width , filterArea . height ) ;
gl . bindBuffer ( gl . ARRAY _BUFFER , this . vertexBuffer ) ;
this . vertexArray [ 0 ] = 0 ;
this . vertexArray [ 1 ] = filterArea . height ;
this . vertexArray [ 2 ] = filterArea . width ;
this . vertexArray [ 3 ] = filterArea . height ;
this . vertexArray [ 4 ] = 0 ;
this . vertexArray [ 5 ] = 0 ;
this . vertexArray [ 6 ] = filterArea . width ;
this . vertexArray [ 7 ] = 0 ;
gl . bufferSubData ( gl . ARRAY _BUFFER , 0 , this . vertexArray ) ;
gl . bindBuffer ( gl . ARRAY _BUFFER , this . uvBuffer ) ;
// now set the uvs..
this . uvArray [ 2 ] = filterArea . width / this . width ;
this . uvArray [ 5 ] = filterArea . height / this . height ;
this . uvArray [ 6 ] = filterArea . width / this . width ;
this . uvArray [ 7 ] = filterArea . height / this . height ;
gl . bufferSubData ( gl . ARRAY _BUFFER , 0 , this . uvArray ) ;
var inputTexture = texture ;
var outputTexture = this . texturePool . pop ( ) ;
if ( ! outputTexture ) outputTexture = new PIXI . FilterTexture ( this . gl , this . width , this . height ) ;
outputTexture . resize ( this . width , this . height ) ;
// need to clear this FBO as it may have some left over elements from a previous filter.
gl . bindFramebuffer ( gl . FRAMEBUFFER , outputTexture . frameBuffer ) ;
gl . clear ( gl . COLOR _BUFFER _BIT ) ;
gl . disable ( gl . BLEND ) ;
for ( var i = 0 ; i < filterBlock . filterPasses . length - 1 ; i ++ )
{
var filterPass = filterBlock . filterPasses [ i ] ;
gl . bindFramebuffer ( gl . FRAMEBUFFER , outputTexture . frameBuffer ) ;
// set texture
gl . activeTexture ( gl . TEXTURE0 ) ;
gl . bindTexture ( gl . TEXTURE _2D , inputTexture . texture ) ;
// draw texture..
//filterPass.applyFilterPass(filterArea.width, filterArea.height);
this . applyFilterPass ( filterPass , filterArea , filterArea . width , filterArea . height ) ;
// swap the textures..
var temp = inputTexture ;
inputTexture = outputTexture ;
outputTexture = temp ;
}
gl . enable ( gl . BLEND ) ;
texture = inputTexture ;
this . texturePool . push ( outputTexture ) ;
}
var filter = filterBlock . filterPasses [ filterBlock . filterPasses . length - 1 ] ;
this . offsetX -= filterArea . x ;
this . offsetY -= filterArea . y ;
var sizeX = this . width ;
var sizeY = this . height ;
var offsetX = 0 ;
var offsetY = 0 ;
var buffer = this . buffer ;
// time to render the filters texture to the previous scene
if ( this . filterStack . length === 0 )
{
gl . colorMask ( true , true , true , true ) ; //this.transparent);
}
else
{
var currentFilter = this . filterStack [ this . filterStack . length - 1 ] ;
2014-04-01 02:02:36 +00:00
filterArea = currentFilter . _filterArea ;
2014-02-28 09:30:53 +00:00
sizeX = filterArea . width ;
sizeY = filterArea . height ;
offsetX = filterArea . x ;
offsetY = filterArea . y ;
buffer = currentFilter . _glFilterTexture . frameBuffer ;
}
// TODO need toremove thease global elements..
projection . x = sizeX / 2 ;
projection . y = - sizeY / 2 ;
offset . x = offsetX ;
offset . y = offsetY ;
2014-04-01 02:02:36 +00:00
filterArea = filterBlock . _filterArea ;
2014-02-28 09:30:53 +00:00
var x = filterArea . x - offsetX ;
var y = filterArea . y - offsetY ;
// update the buffers..
// make sure to flip the y!
gl . bindBuffer ( gl . ARRAY _BUFFER , this . vertexBuffer ) ;
this . vertexArray [ 0 ] = x ;
this . vertexArray [ 1 ] = y + filterArea . height ;
this . vertexArray [ 2 ] = x + filterArea . width ;
this . vertexArray [ 3 ] = y + filterArea . height ;
this . vertexArray [ 4 ] = x ;
this . vertexArray [ 5 ] = y ;
this . vertexArray [ 6 ] = x + filterArea . width ;
this . vertexArray [ 7 ] = y ;
gl . bufferSubData ( gl . ARRAY _BUFFER , 0 , this . vertexArray ) ;
gl . bindBuffer ( gl . ARRAY _BUFFER , this . uvBuffer ) ;
this . uvArray [ 2 ] = filterArea . width / this . width ;
this . uvArray [ 5 ] = filterArea . height / this . height ;
this . uvArray [ 6 ] = filterArea . width / this . width ;
this . uvArray [ 7 ] = filterArea . height / this . height ;
gl . bufferSubData ( gl . ARRAY _BUFFER , 0 , this . uvArray ) ;
//console.log(this.vertexArray)
//console.log(this.uvArray)
//console.log(sizeX + " : " + sizeY)
gl . viewport ( 0 , 0 , sizeX , sizeY ) ;
// bind the buffer
gl . bindFramebuffer ( gl . FRAMEBUFFER , buffer ) ;
2014-04-01 02:02:36 +00:00
// set the blend mode!
2014-02-28 09:30:53 +00:00
//gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA)
// set texture
gl . activeTexture ( gl . TEXTURE0 ) ;
gl . bindTexture ( gl . TEXTURE _2D , texture . texture ) ;
// apply!
this . applyFilterPass ( filter , filterArea , sizeX , sizeY ) ;
// now restore the regular shader..
gl . useProgram ( this . defaultShader . program ) ;
gl . uniform2f ( this . defaultShader . projectionVector , sizeX / 2 , - sizeY / 2 ) ;
gl . uniform2f ( this . defaultShader . offsetVector , - offsetX , - offsetY ) ;
// return the texture to the pool
this . texturePool . push ( texture ) ;
filterBlock . _glFilterTexture = null ;
} ;
/ * *
* Applies the filter to the specified area
* @ method applyFilterPass
* @ param filter { AbstractFilter } the filter that needs to be applied
* @ param filterArea { texture } TODO - might need an update
* @ param width { Number } the horizontal range of the filter
* @ param height { Number } the vertical range of the filter
* /
PIXI . WebGLFilterManager . prototype . applyFilterPass = function ( filter , filterArea , width , height )
{
// use program
var gl = this . gl ;
var shader = filter . shaders [ gl . id ] ;
if ( ! shader )
{
shader = new PIXI . PixiShader ( gl ) ;
shader . fragmentSrc = filter . fragmentSrc ;
shader . uniforms = filter . uniforms ;
shader . init ( ) ;
filter . shaders [ gl . id ] = shader ;
}
// set the shader
gl . useProgram ( shader . program ) ;
gl . uniform2f ( shader . projectionVector , width / 2 , - height / 2 ) ;
gl . uniform2f ( shader . offsetVector , 0 , 0 ) ;
if ( filter . uniforms . dimensions )
{
filter . uniforms . dimensions . value [ 0 ] = this . width ; //width;
filter . uniforms . dimensions . value [ 1 ] = this . height ; //height;
filter . uniforms . dimensions . value [ 2 ] = this . vertexArray [ 0 ] ;
filter . uniforms . dimensions . value [ 3 ] = this . vertexArray [ 5 ] ; //filterArea.height;
}
// console.log(this.uvArray )
shader . syncUniforms ( ) ;
gl . bindBuffer ( gl . ARRAY _BUFFER , this . vertexBuffer ) ;
gl . vertexAttribPointer ( shader . aVertexPosition , 2 , gl . FLOAT , false , 0 , 0 ) ;
gl . bindBuffer ( gl . ARRAY _BUFFER , this . uvBuffer ) ;
gl . vertexAttribPointer ( shader . aTextureCoord , 2 , gl . FLOAT , false , 0 , 0 ) ;
gl . bindBuffer ( gl . ARRAY _BUFFER , this . colorBuffer ) ;
gl . vertexAttribPointer ( shader . colorAttribute , 2 , gl . FLOAT , false , 0 , 0 ) ;
gl . bindBuffer ( gl . ELEMENT _ARRAY _BUFFER , this . indexBuffer ) ;
// draw the filter...
gl . drawElements ( gl . TRIANGLES , 6 , gl . UNSIGNED _SHORT , 0 ) ;
this . renderSession . drawCount ++ ;
} ;
/ * *
* Initialises the shader buffers
* @ method initShaderBuffers
* /
PIXI . WebGLFilterManager . prototype . initShaderBuffers = function ( )
{
var gl = this . gl ;
// create some buffers
this . vertexBuffer = gl . createBuffer ( ) ;
this . uvBuffer = gl . createBuffer ( ) ;
this . colorBuffer = gl . createBuffer ( ) ;
this . indexBuffer = gl . createBuffer ( ) ;
// bind and upload the vertexs..
// keep a reference to the vertexFloatData..
this . vertexArray = new Float32Array ( [ 0.0 , 0.0 ,
1.0 , 0.0 ,
0.0 , 1.0 ,
1.0 , 1.0 ] ) ;
gl . bindBuffer ( gl . ARRAY _BUFFER , this . vertexBuffer ) ;
gl . bufferData (
gl . ARRAY _BUFFER ,
this . vertexArray ,
gl . STATIC _DRAW ) ;
// bind and upload the uv buffer
this . uvArray = new Float32Array ( [ 0.0 , 0.0 ,
1.0 , 0.0 ,
0.0 , 1.0 ,
1.0 , 1.0 ] ) ;
gl . bindBuffer ( gl . ARRAY _BUFFER , this . uvBuffer ) ;
gl . bufferData (
gl . ARRAY _BUFFER ,
this . uvArray ,
gl . STATIC _DRAW ) ;
this . colorArray = new Float32Array ( [ 1.0 , 0xFFFFFF ,
1.0 , 0xFFFFFF ,
1.0 , 0xFFFFFF ,
1.0 , 0xFFFFFF ] ) ;
gl . bindBuffer ( gl . ARRAY _BUFFER , this . colorBuffer ) ;
gl . bufferData (
gl . ARRAY _BUFFER ,
this . colorArray ,
gl . STATIC _DRAW ) ;
// bind and upload the index
gl . bindBuffer ( gl . ELEMENT _ARRAY _BUFFER , this . indexBuffer ) ;
gl . bufferData (
gl . ELEMENT _ARRAY _BUFFER ,
new Uint16Array ( [ 0 , 1 , 2 , 1 , 3 , 2 ] ) ,
gl . STATIC _DRAW ) ;
} ;
/ * *
* Destroys the filter and removes it from the filter stack
* @ method destroy
* /
PIXI . WebGLFilterManager . prototype . destroy = function ( )
{
var gl = this . gl ;
this . filterStack = null ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
this . offsetX = 0 ;
this . offsetY = 0 ;
// destroy textures
for ( var i = 0 ; i < this . texturePool . length ; i ++ ) {
this . texturePool . destroy ( ) ;
}
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
this . texturePool = null ;
//destroy buffers..
gl . deleteBuffer ( this . vertexBuffer ) ;
gl . deleteBuffer ( this . uvBuffer ) ;
gl . deleteBuffer ( this . colorBuffer ) ;
gl . deleteBuffer ( this . indexBuffer ) ;
} ;
/ * *
* @ author Mat Groves http : //matgroves.com/ @Doormat23
* /
/ * *
* @ class FilterTexture
* @ constructor
* @ param gl { WebGLContext } the current WebGL drawing context
* @ param width { Number } the horizontal range of the filter
* @ param height { Number } the vertical range of the filter
* @ private
* /
PIXI . FilterTexture = function ( gl , width , height )
{
/ * *
* @ property gl
* @ type WebGLContext
* /
this . gl = gl ;
// next time to create a frame buffer and texture
this . frameBuffer = gl . createFramebuffer ( ) ;
this . texture = gl . createTexture ( ) ;
gl . bindTexture ( gl . TEXTURE _2D , this . texture ) ;
gl . texParameteri ( gl . TEXTURE _2D , gl . TEXTURE _MAG _FILTER , gl . LINEAR ) ;
gl . texParameteri ( gl . TEXTURE _2D , gl . TEXTURE _MIN _FILTER , gl . LINEAR ) ;
gl . texParameteri ( gl . TEXTURE _2D , gl . TEXTURE _WRAP _S , gl . CLAMP _TO _EDGE ) ;
gl . texParameteri ( gl . TEXTURE _2D , gl . TEXTURE _WRAP _T , gl . CLAMP _TO _EDGE ) ;
gl . bindFramebuffer ( gl . FRAMEBUFFER , this . framebuffer ) ;
gl . bindFramebuffer ( gl . FRAMEBUFFER , this . frameBuffer ) ;
gl . framebufferTexture2D ( gl . FRAMEBUFFER , gl . COLOR _ATTACHMENT0 , gl . TEXTURE _2D , this . texture , 0 ) ;
this . resize ( width , height ) ;
} ;
/ * *
* Clears the filter texture
* @ method clear
* /
PIXI . FilterTexture . prototype . clear = function ( )
{
var gl = this . gl ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
gl . clearColor ( 0 , 0 , 0 , 0 ) ;
gl . clear ( gl . COLOR _BUFFER _BIT ) ;
} ;
/ * *
* Resizes the texture to the specified width and height
*
* @ method resize
* @ param width { Number } the new width of the texture
* @ param height { Number } the new height of the texture
* /
PIXI . FilterTexture . prototype . resize = function ( width , height )
{
if ( this . width === width && this . height === height ) return ;
this . width = width ;
this . height = height ;
var gl = this . gl ;
gl . bindTexture ( gl . TEXTURE _2D , this . texture ) ;
gl . texImage2D ( gl . TEXTURE _2D , 0 , gl . RGBA , width , height , 0 , gl . RGBA , gl . UNSIGNED _BYTE , null ) ;
} ;
/ * *
* Destroys the filter texture
* @ method destroy
* /
PIXI . FilterTexture . prototype . destroy = function ( )
{
var gl = this . gl ;
gl . deleteFramebuffer ( this . frameBuffer ) ;
gl . deleteTexture ( this . texture ) ;
this . frameBuffer = null ;
this . texture = null ;
} ;
/ * *
* @ author Mat Groves
2014-04-01 02:02:36 +00:00
*
*
2014-02-28 09:30:53 +00:00
* /
/ * *
* A set of functions used to handle masking
*
* @ class CanvasMaskManager
* /
PIXI . CanvasMaskManager = function ( )
{
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
} ;
/ * *
* This method adds it to the current stack of masks
*
* @ method pushMask
* @ param maskData the maskData that will be pushed
* @ param context { Context2D } the 2 d drawing method of the canvas
* /
PIXI . CanvasMaskManager . prototype . pushMask = function ( maskData , context )
{
context . save ( ) ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
var cacheAlpha = maskData . alpha ;
var transform = maskData . worldTransform ;
context . setTransform ( transform . a , transform . c , transform . b , transform . d , transform . tx , transform . ty ) ;
PIXI . CanvasGraphics . renderGraphicsMask ( maskData , context ) ;
context . clip ( ) ;
maskData . worldAlpha = cacheAlpha ;
} ;
/ * *
* Restores the current drawing context to the state it was before the mask was applied
*
* @ method popMask
* @ param context { Context2D } the 2 d drawing method of the canvas
* /
PIXI . CanvasMaskManager . prototype . popMask = function ( context )
{
context . restore ( ) ;
} ;
/ * *
* @ author Mat Groves
2014-04-01 02:02:36 +00:00
*
*
2014-02-28 09:30:53 +00:00
* /
/ * *
* @ class CanvasTinter
* @ constructor
* @ static
* /
PIXI . CanvasTinter = function ( )
{
/// this.textureCach
} ;
//PIXI.CanvasTinter.cachTint = true;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
/ * *
2014-04-01 02:02:36 +00:00
* Basically this method just needs a sprite and a color and tints the sprite
2014-02-28 09:30:53 +00:00
* with the given color
2014-04-01 02:02:36 +00:00
*
* @ method getTintedTexture
2014-02-28 09:30:53 +00:00
* @ param sprite { Sprite } the sprite to tint
* @ param color { Number } the color to use to tint the sprite with
* /
PIXI . CanvasTinter . getTintedTexture = function ( sprite , color )
{
var texture = sprite . texture ;
color = PIXI . CanvasTinter . roundColor ( color ) ;
var stringColor = "#" + ( "00000" + ( color | 0 ) . toString ( 16 ) ) . substr ( - 6 ) ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
texture . tintCache = texture . tintCache || { } ;
if ( texture . tintCache [ stringColor ] ) return texture . tintCache [ stringColor ] ;
// clone texture..
var canvas = PIXI . CanvasTinter . canvas || document . createElement ( "canvas" ) ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
//PIXI.CanvasTinter.tintWithPerPixel(texture, stringColor, canvas);
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
PIXI . CanvasTinter . tintMethod ( texture , color , canvas ) ;
if ( PIXI . CanvasTinter . convertTintToImage )
{
// is this better?
var tintImage = new Image ( ) ;
tintImage . src = canvas . toDataURL ( ) ;
texture . tintCache [ stringColor ] = tintImage ;
}
else
{
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
texture . tintCache [ stringColor ] = canvas ;
// if we are not converting the texture to an image then we need to lose the reference to the canvas
PIXI . CanvasTinter . canvas = null ;
}
return canvas ;
} ;
/ * *
* Tint a texture using the "multiply" operation
* @ method tintWithMultiply
* @ param texture { texture } the texture to tint
* @ param color { Number } the color to use to tint the sprite with
* @ param canvas { HTMLCanvasElement } the current canvas
* /
PIXI . CanvasTinter . tintWithMultiply = function ( texture , color , canvas )
{
var context = canvas . getContext ( "2d" ) ;
var frame = texture . frame ;
canvas . width = frame . width ;
canvas . height = frame . height ;
context . fillStyle = "#" + ( "00000" + ( color | 0 ) . toString ( 16 ) ) . substr ( - 6 ) ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
context . fillRect ( 0 , 0 , frame . width , frame . height ) ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
context . globalCompositeOperation = "multiply" ;
context . drawImage ( texture . baseTexture . source ,
frame . x ,
frame . y ,
frame . width ,
frame . height ,
0 ,
0 ,
frame . width ,
frame . height ) ;
context . globalCompositeOperation = "destination-atop" ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
context . drawImage ( texture . baseTexture . source ,
frame . x ,
frame . y ,
frame . width ,
frame . height ,
0 ,
0 ,
frame . width ,
frame . height ) ;
} ;
/ * *
* Tint a texture using the "overlay" operation
* @ method tintWithOverlay
* @ param texture { texture } the texture to tint
* @ param color { Number } the color to use to tint the sprite with
* @ param canvas { HTMLCanvasElement } the current canvas
* /
PIXI . CanvasTinter . tintWithOverlay = function ( texture , color , canvas )
{
var context = canvas . getContext ( "2d" ) ;
var frame = texture . frame ;
canvas . width = frame . width ;
canvas . height = frame . height ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
context . globalCompositeOperation = "copy" ;
context . fillStyle = "#" + ( "00000" + ( color | 0 ) . toString ( 16 ) ) . substr ( - 6 ) ;
context . fillRect ( 0 , 0 , frame . width , frame . height ) ;
context . globalCompositeOperation = "destination-atop" ;
context . drawImage ( texture . baseTexture . source ,
frame . x ,
frame . y ,
frame . width ,
frame . height ,
0 ,
0 ,
frame . width ,
frame . height ) ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
//context.globalCompositeOperation = "copy";
} ;
/ * *
* Tint a texture pixel per pixel
* @ method tintPerPixel
* @ param texture { texture } the texture to tint
* @ param color { Number } the color to use to tint the sprite with
* @ param canvas { HTMLCanvasElement } the current canvas
* /
PIXI . CanvasTinter . tintWithPerPixel = function ( texture , color , canvas )
{
var context = canvas . getContext ( "2d" ) ;
var frame = texture . frame ;
canvas . width = frame . width ;
canvas . height = frame . height ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
context . globalCompositeOperation = "copy" ;
context . drawImage ( texture . baseTexture . source ,
frame . x ,
frame . y ,
frame . width ,
frame . height ,
0 ,
0 ,
frame . width ,
frame . height ) ;
var rgbValues = PIXI . hex2rgb ( color ) ;
var r = rgbValues [ 0 ] , g = rgbValues [ 1 ] , b = rgbValues [ 2 ] ;
var pixelData = context . getImageData ( 0 , 0 , frame . width , frame . height ) ;
var pixels = pixelData . data ;
for ( var i = 0 ; i < pixels . length ; i += 4 )
{
pixels [ i + 0 ] *= r ;
pixels [ i + 1 ] *= g ;
pixels [ i + 2 ] *= b ;
}
context . putImageData ( pixelData , 0 , 0 ) ;
} ;
/ * *
* Rounds the specified color according to the PIXI . CanvasTinter . cacheStepsPerColorChannel
* @ method roundColor
* @ param color { number } the color to round , should be a hex color
* /
PIXI . CanvasTinter . roundColor = function ( color )
{
var step = PIXI . CanvasTinter . cacheStepsPerColorChannel ;
var rgbValues = PIXI . hex2rgb ( color ) ;
rgbValues [ 0 ] = Math . min ( 255 , ( rgbValues [ 0 ] / step ) * step ) ;
rgbValues [ 1 ] = Math . min ( 255 , ( rgbValues [ 1 ] / step ) * step ) ;
rgbValues [ 2 ] = Math . min ( 255 , ( rgbValues [ 2 ] / step ) * step ) ;
return PIXI . rgb2hex ( rgbValues ) ;
} ;
/ * *
2014-04-01 02:02:36 +00:00
*
2014-02-28 09:30:53 +00:00
* Number of steps which will be used as a cap when rounding colors
*
* @ property cacheStepsPerColorChannel
* @ type Number
* /
PIXI . CanvasTinter . cacheStepsPerColorChannel = 8 ;
/ * *
2014-04-01 02:02:36 +00:00
*
2014-02-28 09:30:53 +00:00
* Number of steps which will be used as a cap when rounding colors
*
* @ property convertTintToImage
* @ type Boolean
* /
PIXI . CanvasTinter . convertTintToImage = false ;
/ * *
* Whether or not the Canvas BlendModes are supported , consequently the ability to tint using the multiply method
*
* @ property canUseMultiply
* @ type Boolean
* /
PIXI . CanvasTinter . canUseMultiply = PIXI . canUseNewCanvasBlendModes ( ) ;
PIXI . CanvasTinter . tintMethod = PIXI . CanvasTinter . canUseMultiply ? PIXI . CanvasTinter . tintWithMultiply : PIXI . CanvasTinter . tintWithPerPixel ;
/ * *
* @ author Mat Groves http : //matgroves.com/ @Doormat23
* /
/ * *
* the CanvasRenderer draws the stage and all its content onto a 2 d canvas . This renderer should be used for browsers that do not support webGL .
* Dont forget to add the view to your DOM or you will not see anything : )
*
* @ class CanvasRenderer
* @ constructor
* @ param width = 800 { Number } the width of the canvas view
* @ param height = 600 { Number } the height of the canvas view
* @ param [ view ] { HTMLCanvasElement } the canvas to use as a view , optional
* @ param [ transparent = false ] { Boolean } the transparency of the render view , default false
* /
PIXI . CanvasRenderer = function ( width , height , view , transparent )
{
PIXI . defaultRenderer = PIXI . defaultRenderer || this ;
this . type = PIXI . CANVAS _RENDERER ;
/ * *
* This sets if the CanvasRenderer will clear the canvas or not before the new render pass .
* If the Stage is NOT transparent Pixi will use a canvas sized fillRect operation every frame to set the canvas background color .
* If the Stage is transparent Pixi will use clearRect to clear the canvas every frame .
* Disable this by setting this to false . For example if your game has a canvas filling background image you often don ' t need this set .
*
* @ property clearBeforeRender
* @ type Boolean
* @ default
* /
this . clearBeforeRender = true ;
/ * *
* If true Pixi will Math . floor ( ) x / y values when rendering , stopping pixel interpolation .
* Handy for crisp pixel art and speed on legacy devices .
*
* @ property roundPixels
* @ type Boolean
* @ default
* /
this . roundPixels = false ;
/ * *
* Whether the render view is transparent
*
* @ property transparent
* @ type Boolean
* /
this . transparent = ! ! transparent ;
if ( ! PIXI . blendModesCanvas )
{
PIXI . blendModesCanvas = [ ] ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
if ( PIXI . canUseNewCanvasBlendModes ( ) )
{
PIXI . blendModesCanvas [ PIXI . blendModes . NORMAL ] = "source-over" ;
PIXI . blendModesCanvas [ PIXI . blendModes . ADD ] = "lighter" ; //IS THIS OK???
PIXI . blendModesCanvas [ PIXI . blendModes . MULTIPLY ] = "multiply" ;
PIXI . blendModesCanvas [ PIXI . blendModes . SCREEN ] = "screen" ;
PIXI . blendModesCanvas [ PIXI . blendModes . OVERLAY ] = "overlay" ;
PIXI . blendModesCanvas [ PIXI . blendModes . DARKEN ] = "darken" ;
PIXI . blendModesCanvas [ PIXI . blendModes . LIGHTEN ] = "lighten" ;
PIXI . blendModesCanvas [ PIXI . blendModes . COLOR _DODGE ] = "color-dodge" ;
PIXI . blendModesCanvas [ PIXI . blendModes . COLOR _BURN ] = "color-burn" ;
PIXI . blendModesCanvas [ PIXI . blendModes . HARD _LIGHT ] = "hard-light" ;
PIXI . blendModesCanvas [ PIXI . blendModes . SOFT _LIGHT ] = "soft-light" ;
PIXI . blendModesCanvas [ PIXI . blendModes . DIFFERENCE ] = "difference" ;
PIXI . blendModesCanvas [ PIXI . blendModes . EXCLUSION ] = "exclusion" ;
PIXI . blendModesCanvas [ PIXI . blendModes . HUE ] = "hue" ;
PIXI . blendModesCanvas [ PIXI . blendModes . SATURATION ] = "saturation" ;
PIXI . blendModesCanvas [ PIXI . blendModes . COLOR ] = "color" ;
PIXI . blendModesCanvas [ PIXI . blendModes . LUMINOSITY ] = "luminosity" ;
}
else
{
// this means that the browser does not support the cool new blend modes in canvas "cough" ie "cough"
PIXI . blendModesCanvas [ PIXI . blendModes . NORMAL ] = "source-over" ;
PIXI . blendModesCanvas [ PIXI . blendModes . ADD ] = "lighter" ; //IS THIS OK???
PIXI . blendModesCanvas [ PIXI . blendModes . MULTIPLY ] = "source-over" ;
PIXI . blendModesCanvas [ PIXI . blendModes . SCREEN ] = "source-over" ;
PIXI . blendModesCanvas [ PIXI . blendModes . OVERLAY ] = "source-over" ;
PIXI . blendModesCanvas [ PIXI . blendModes . DARKEN ] = "source-over" ;
PIXI . blendModesCanvas [ PIXI . blendModes . LIGHTEN ] = "source-over" ;
PIXI . blendModesCanvas [ PIXI . blendModes . COLOR _DODGE ] = "source-over" ;
PIXI . blendModesCanvas [ PIXI . blendModes . COLOR _BURN ] = "source-over" ;
PIXI . blendModesCanvas [ PIXI . blendModes . HARD _LIGHT ] = "source-over" ;
PIXI . blendModesCanvas [ PIXI . blendModes . SOFT _LIGHT ] = "source-over" ;
PIXI . blendModesCanvas [ PIXI . blendModes . DIFFERENCE ] = "source-over" ;
PIXI . blendModesCanvas [ PIXI . blendModes . EXCLUSION ] = "source-over" ;
PIXI . blendModesCanvas [ PIXI . blendModes . HUE ] = "source-over" ;
PIXI . blendModesCanvas [ PIXI . blendModes . SATURATION ] = "source-over" ;
PIXI . blendModesCanvas [ PIXI . blendModes . COLOR ] = "source-over" ;
PIXI . blendModesCanvas [ PIXI . blendModes . LUMINOSITY ] = "source-over" ;
}
}
/ * *
* The width of the canvas view
*
* @ property width
* @ type Number
* @ default 800
* /
this . width = width || 800 ;
/ * *
* The height of the canvas view
*
* @ property height
* @ type Number
* @ default 600
* /
this . height = height || 600 ;
/ * *
* The canvas element that everything is drawn to
*
* @ property view
* @ type HTMLCanvasElement
* /
this . view = view || document . createElement ( "canvas" ) ;
/ * *
* The canvas 2 d context that everything is drawn with
* @ property context
* @ type HTMLCanvasElement 2 d Context
* /
this . context = this . view . getContext ( "2d" , { alpha : this . transparent } ) ;
this . refresh = true ;
// hack to enable some hardware acceleration!
//this.view.style["transform"] = "translatez(0)";
this . view . width = this . width ;
this . view . height = this . height ;
this . count = 0 ;
/ * *
* Instance of a PIXI . CanvasMaskManager , handles masking when using the canvas renderer
* @ property CanvasMaskManager
* @ type CanvasMaskManager
* /
this . maskManager = new PIXI . CanvasMaskManager ( ) ;
/ * *
* The render session is just a bunch of parameter used for rendering
* @ property renderSession
* @ type Object
* /
this . renderSession = {
context : this . context ,
maskManager : this . maskManager ,
scaleMode : null ,
smoothProperty : null
} ;
if ( "imageSmoothingEnabled" in this . context )
this . renderSession . smoothProperty = "imageSmoothingEnabled" ;
else if ( "webkitImageSmoothingEnabled" in this . context )
this . renderSession . smoothProperty = "webkitImageSmoothingEnabled" ;
else if ( "mozImageSmoothingEnabled" in this . context )
this . renderSession . smoothProperty = "mozImageSmoothingEnabled" ;
else if ( "oImageSmoothingEnabled" in this . context )
this . renderSession . smoothProperty = "oImageSmoothingEnabled" ;
} ;
// constructor
PIXI . CanvasRenderer . prototype . constructor = PIXI . CanvasRenderer ;
/ * *
* Renders the stage to its canvas view
*
* @ method render
* @ param stage { Stage } the Stage element to be rendered
* /
PIXI . CanvasRenderer . prototype . render = function ( stage )
{
// update textures if need be
PIXI . texturesToUpdate . length = 0 ;
PIXI . texturesToDestroy . length = 0 ;
stage . updateTransform ( ) ;
this . context . setTransform ( 1 , 0 , 0 , 1 , 0 , 0 ) ;
this . context . globalAlpha = 1 ;
if ( ! this . transparent && this . clearBeforeRender )
{
this . context . fillStyle = stage . backgroundColorString ;
this . context . fillRect ( 0 , 0 , this . width , this . height ) ;
}
else if ( this . transparent && this . clearBeforeRender )
{
this . context . clearRect ( 0 , 0 , this . width , this . height ) ;
}
this . renderDisplayObject ( stage ) ;
// run interaction!
if ( stage . interactive )
{
//need to add some events!
if ( ! stage . _interactiveEventsAdded )
{
stage . _interactiveEventsAdded = true ;
stage . interactionManager . setTarget ( this ) ;
}
}
// remove frame updates..
if ( PIXI . Texture . frameUpdates . length > 0 )
{
PIXI . Texture . frameUpdates . length = 0 ;
}
} ;
/ * *
* Resizes the canvas view to the specified width and height
*
* @ method resize
* @ param width { Number } the new width of the canvas view
* @ param height { Number } the new height of the canvas view
* /
PIXI . CanvasRenderer . prototype . resize = function ( width , height )
{
this . width = width ;
this . height = height ;
this . view . width = width ;
this . view . height = height ;
} ;
/ * *
* Renders a display object
*
* @ method renderDisplayObject
* @ param displayObject { DisplayObject } The displayObject to render
* @ param context { Context2D } the context 2 d method of the canvas
* @ private
* /
PIXI . CanvasRenderer . prototype . renderDisplayObject = function ( displayObject , context )
{
// no longer recursive!
//var transform;
//var context = this.context;
this . renderSession . context = context || this . context ;
displayObject . _renderCanvas ( this . renderSession ) ;
} ;
/ * *
* Renders a flat strip
*
* @ method renderStripFlat
* @ param strip { Strip } The Strip to render
* @ private
* /
PIXI . CanvasRenderer . prototype . renderStripFlat = function ( strip )
{
var context = this . context ;
var verticies = strip . verticies ;
var length = verticies . length / 2 ;
this . count ++ ;
context . beginPath ( ) ;
for ( var i = 1 ; i < length - 2 ; i ++ )
{
// draw some triangles!
var index = i * 2 ;
var x0 = verticies [ index ] , x1 = verticies [ index + 2 ] , x2 = verticies [ index + 4 ] ;
var y0 = verticies [ index + 1 ] , y1 = verticies [ index + 3 ] , y2 = verticies [ index + 5 ] ;
context . moveTo ( x0 , y0 ) ;
context . lineTo ( x1 , y1 ) ;
context . lineTo ( x2 , y2 ) ;
}
context . fillStyle = "#FF0000" ;
context . fill ( ) ;
context . closePath ( ) ;
} ;
/ * *
* Renders a strip
*
* @ method renderStrip
* @ param strip { Strip } The Strip to render
* @ private
* /
PIXI . CanvasRenderer . prototype . renderStrip = function ( strip )
{
var context = this . context ;
// draw triangles!!
var verticies = strip . verticies ;
var uvs = strip . uvs ;
var length = verticies . length / 2 ;
this . count ++ ;
for ( var i = 1 ; i < length - 2 ; i ++ )
{
// draw some triangles!
var index = i * 2 ;
var x0 = verticies [ index ] , x1 = verticies [ index + 2 ] , x2 = verticies [ index + 4 ] ;
var y0 = verticies [ index + 1 ] , y1 = verticies [ index + 3 ] , y2 = verticies [ index + 5 ] ;
var u0 = uvs [ index ] * strip . texture . width , u1 = uvs [ index + 2 ] * strip . texture . width , u2 = uvs [ index + 4 ] * strip . texture . width ;
var v0 = uvs [ index + 1 ] * strip . texture . height , v1 = uvs [ index + 3 ] * strip . texture . height , v2 = uvs [ index + 5 ] * strip . texture . height ;
context . save ( ) ;
context . beginPath ( ) ;
context . moveTo ( x0 , y0 ) ;
context . lineTo ( x1 , y1 ) ;
context . lineTo ( x2 , y2 ) ;
context . closePath ( ) ;
context . clip ( ) ;
// Compute matrix transform
var delta = u0 * v1 + v0 * u2 + u1 * v2 - v1 * u2 - v0 * u1 - u0 * v2 ;
var deltaA = x0 * v1 + v0 * x2 + x1 * v2 - v1 * x2 - v0 * x1 - x0 * v2 ;
var deltaB = u0 * x1 + x0 * u2 + u1 * x2 - x1 * u2 - x0 * u1 - u0 * x2 ;
var deltaC = u0 * v1 * x2 + v0 * x1 * u2 + x0 * u1 * v2 - x0 * v1 * u2 - v0 * u1 * x2 - u0 * x1 * v2 ;
var deltaD = y0 * v1 + v0 * y2 + y1 * v2 - v1 * y2 - v0 * y1 - y0 * v2 ;
var deltaE = u0 * y1 + y0 * u2 + u1 * y2 - y1 * u2 - y0 * u1 - u0 * y2 ;
var deltaF = u0 * v1 * y2 + v0 * y1 * u2 + y0 * u1 * v2 - y0 * v1 * u2 - v0 * u1 * y2 - u0 * y1 * v2 ;
context . transform ( deltaA / delta , deltaD / delta ,
deltaB / delta , deltaE / delta ,
deltaC / delta , deltaF / delta ) ;
context . drawImage ( strip . texture . baseTexture . source , 0 , 0 ) ;
context . restore ( ) ;
}
} ;
/ * *
* Creates a Canvas element of the given size
*
* @ method CanvasBuffer
* @ param width { Number } the width for the newly created canvas
* @ param height { Number } the height for the newly created canvas
* @ static
* @ private
* /
PIXI . CanvasBuffer = function ( width , height )
{
this . width = width ;
this . height = height ;
this . canvas = document . createElement ( "canvas" ) ;
this . context = this . canvas . getContext ( "2d" ) ;
this . canvas . width = width ;
this . canvas . height = height ;
} ;
/ * *
* Clears the canvas that was created by the CanvasBuffer class
*
* @ method clear
* @ private
* /
PIXI . CanvasBuffer . prototype . clear = function ( )
{
this . context . clearRect ( 0 , 0 , this . width , this . height ) ;
} ;
/ * *
* Resizes the canvas that was created by the CanvasBuffer class to the specified width and height
*
* @ method resize
* @ param width { Number } the new width of the canvas
* @ param height { Number } the new height of the canvas
* @ private
* /
PIXI . CanvasBuffer . prototype . resize = function ( width , height )
{
this . width = this . canvas . width = width ;
this . height = this . canvas . height = height ;
} ;
/ * *
* @ author Mat Groves http : //matgroves.com/ @Doormat23
* /
/ * *
* A set of functions used by the canvas renderer to draw the primitive graphics data
*
* @ class CanvasGraphics
* /
PIXI . CanvasGraphics = function ( )
{
} ;
/ *
* Renders the graphics object
*
* @ static
* @ private
* @ method renderGraphics
* @ param graphics { Graphics } the actual graphics object to render
* @ param context { Context2D } the 2 d drawing method of the canvas
* /
PIXI . CanvasGraphics . renderGraphics = function ( graphics , context )
{
var worldAlpha = graphics . worldAlpha ;
var color = '' ;
for ( var i = 0 ; i < graphics . graphicsData . length ; i ++ )
{
var data = graphics . graphicsData [ i ] ;
var points = data . points ;
context . strokeStyle = color = '#' + ( '00000' + ( data . lineColor | 0 ) . toString ( 16 ) ) . substr ( - 6 ) ;
context . lineWidth = data . lineWidth ;
if ( data . type === PIXI . Graphics . POLY )
{
context . beginPath ( ) ;
context . moveTo ( points [ 0 ] , points [ 1 ] ) ;
for ( var j = 1 ; j < points . length / 2 ; j ++ )
{
context . lineTo ( points [ j * 2 ] , points [ j * 2 + 1 ] ) ;
}
// if the first and last point are the same close the path - much neater :)
if ( points [ 0 ] === points [ points . length - 2 ] && points [ 1 ] === points [ points . length - 1 ] )
{
context . closePath ( ) ;
}
if ( data . fill )
{
context . globalAlpha = data . fillAlpha * worldAlpha ;
context . fillStyle = color = '#' + ( '00000' + ( data . fillColor | 0 ) . toString ( 16 ) ) . substr ( - 6 ) ;
context . fill ( ) ;
}
if ( data . lineWidth )
{
context . globalAlpha = data . lineAlpha * worldAlpha ;
context . stroke ( ) ;
}
}
else if ( data . type === PIXI . Graphics . RECT )
{
if ( data . fillColor || data . fillColor === 0 )
{
context . globalAlpha = data . fillAlpha * worldAlpha ;
context . fillStyle = color = '#' + ( '00000' + ( data . fillColor | 0 ) . toString ( 16 ) ) . substr ( - 6 ) ;
context . fillRect ( points [ 0 ] , points [ 1 ] , points [ 2 ] , points [ 3 ] ) ;
}
if ( data . lineWidth )
{
context . globalAlpha = data . lineAlpha * worldAlpha ;
context . strokeRect ( points [ 0 ] , points [ 1 ] , points [ 2 ] , points [ 3 ] ) ;
}
}
else if ( data . type === PIXI . Graphics . CIRC )
{
// TODO - need to be Undefined!
context . beginPath ( ) ;
context . arc ( points [ 0 ] , points [ 1 ] , points [ 2 ] , 0 , 2 * Math . PI ) ;
context . closePath ( ) ;
if ( data . fill )
{
context . globalAlpha = data . fillAlpha * worldAlpha ;
context . fillStyle = color = '#' + ( '00000' + ( data . fillColor | 0 ) . toString ( 16 ) ) . substr ( - 6 ) ;
context . fill ( ) ;
}
if ( data . lineWidth )
{
context . globalAlpha = data . lineAlpha * worldAlpha ;
context . stroke ( ) ;
}
}
else if ( data . type === PIXI . Graphics . ELIP )
{
// ellipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas
var ellipseData = data . points ;
var w = ellipseData [ 2 ] * 2 ;
var h = ellipseData [ 3 ] * 2 ;
var x = ellipseData [ 0 ] - w / 2 ;
var y = ellipseData [ 1 ] - h / 2 ;
context . beginPath ( ) ;
var kappa = 0.5522848 ,
ox = ( w / 2 ) * kappa , // control point offset horizontal
oy = ( h / 2 ) * kappa , // control point offset vertical
xe = x + w , // x-end
ye = y + h , // y-end
xm = x + w / 2 , // x-middle
ym = y + h / 2 ; // y-middle
context . moveTo ( x , ym ) ;
context . bezierCurveTo ( x , ym - oy , xm - ox , y , xm , y ) ;
context . bezierCurveTo ( xm + ox , y , xe , ym - oy , xe , ym ) ;
context . bezierCurveTo ( xe , ym + oy , xm + ox , ye , xm , ye ) ;
context . bezierCurveTo ( xm - ox , ye , x , ym + oy , x , ym ) ;
context . closePath ( ) ;
if ( data . fill )
{
context . globalAlpha = data . fillAlpha * worldAlpha ;
context . fillStyle = color = '#' + ( '00000' + ( data . fillColor | 0 ) . toString ( 16 ) ) . substr ( - 6 ) ;
context . fill ( ) ;
}
if ( data . lineWidth )
{
context . globalAlpha = data . lineAlpha * worldAlpha ;
context . stroke ( ) ;
}
}
}
} ;
/ *
* Renders a graphics mask
*
* @ static
* @ private
* @ method renderGraphicsMask
* @ param graphics { Graphics } the graphics which will be used as a mask
* @ param context { Context2D } the context 2 d method of the canvas
* /
PIXI . CanvasGraphics . renderGraphicsMask = function ( graphics , context )
{
var len = graphics . graphicsData . length ;
if ( len === 0 ) return ;
if ( len > 1 )
{
len = 1 ;
window . console . log ( 'Pixi.js warning: masks in canvas can only mask using the first path in the graphics object' ) ;
}
for ( var i = 0 ; i < 1 ; i ++ )
{
var data = graphics . graphicsData [ i ] ;
var points = data . points ;
if ( data . type === PIXI . Graphics . POLY )
{
context . beginPath ( ) ;
context . moveTo ( points [ 0 ] , points [ 1 ] ) ;
for ( var j = 1 ; j < points . length / 2 ; j ++ )
{
context . lineTo ( points [ j * 2 ] , points [ j * 2 + 1 ] ) ;
}
// if the first and last point are the same close the path - much neater :)
if ( points [ 0 ] === points [ points . length - 2 ] && points [ 1 ] === points [ points . length - 1 ] )
{
context . closePath ( ) ;
}
}
else if ( data . type === PIXI . Graphics . RECT )
{
context . beginPath ( ) ;
context . rect ( points [ 0 ] , points [ 1 ] , points [ 2 ] , points [ 3 ] ) ;
context . closePath ( ) ;
}
else if ( data . type === PIXI . Graphics . CIRC )
{
// TODO - need to be Undefined!
context . beginPath ( ) ;
context . arc ( points [ 0 ] , points [ 1 ] , points [ 2 ] , 0 , 2 * Math . PI ) ;
context . closePath ( ) ;
}
else if ( data . type === PIXI . Graphics . ELIP )
{
// ellipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas
var ellipseData = data . points ;
var w = ellipseData [ 2 ] * 2 ;
var h = ellipseData [ 3 ] * 2 ;
var x = ellipseData [ 0 ] - w / 2 ;
var y = ellipseData [ 1 ] - h / 2 ;
context . beginPath ( ) ;
var kappa = 0.5522848 ,
ox = ( w / 2 ) * kappa , // control point offset horizontal
oy = ( h / 2 ) * kappa , // control point offset vertical
xe = x + w , // x-end
ye = y + h , // y-end
xm = x + w / 2 , // x-middle
ym = y + h / 2 ; // y-middle
context . moveTo ( x , ym ) ;
context . bezierCurveTo ( x , ym - oy , xm - ox , y , xm , y ) ;
context . bezierCurveTo ( xm + ox , y , xe , ym - oy , xe , ym ) ;
context . bezierCurveTo ( xe , ym + oy , xm + ox , ye , xm , ye ) ;
context . bezierCurveTo ( xm - ox , ye , x , ym + oy , x , ym ) ;
context . closePath ( ) ;
}
}
} ;
/ * *
* @ author Mat Groves http : //matgroves.com/ @Doormat23
* /
/ * *
* The Graphics class contains a set of methods that you can use to create primitive shapes and lines .
* It is important to know that with the webGL renderer only simple polygons can be filled at this stage
* Complex polygons will not be filled . Heres an example of a complex polygon : http : //www.goodboydigital.com/wp-content/uploads/2013/06/complexPolygon.png
*
* @ class Graphics
* @ extends DisplayObjectContainer
* @ constructor
* /
PIXI . Graphics = function ( )
{
PIXI . DisplayObjectContainer . call ( this ) ;
this . renderable = true ;
/ * *
* The alpha of the fill of this graphics object
*
* @ property fillAlpha
* @ type Number
* /
this . fillAlpha = 1 ;
/ * *
* The width of any lines drawn
*
* @ property lineWidth
* @ type Number
* /
this . lineWidth = 0 ;
/ * *
* The color of any lines drawn
*
* @ property lineColor
* @ type String
* /
this . lineColor = "black" ;
/ * *
* Graphics data
*
* @ property graphicsData
* @ type Array
* @ private
* /
this . graphicsData = [ ] ;
/ * *
* The tint applied to the graphic shape . This is a hex value
*
* @ property tint
* @ type Number
* @ default 0xFFFFFF
* /
this . tint = 0xFFFFFF ; // * Math.random();
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
/ * *
* The blend mode to be applied to the graphic shape
*
* @ property blendMode
* @ type Number
* @ default PIXI . blendModes . NORMAL ;
* /
this . blendMode = PIXI . blendModes . NORMAL ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
/ * *
* Current path
*
* @ property currentPath
* @ type Object
* @ private
* /
this . currentPath = { points : [ ] } ;
/ * *
* Array containing some WebGL - related properties used by the WebGL renderer
*
* @ property _webGL
* @ type Array
* @ private
* /
this . _webGL = [ ] ;
/ * *
* Whether this shape is being used as a mask
*
* @ property isMask
* @ type isMask
* /
this . isMask = false ;
/ * *
* The bounds of the graphic shape as rectangle object
*
* @ property bounds
* @ type Rectangle
* /
this . bounds = null ;
/ * *
* the bounds ' padding used for bounds calculation
*
* @ property bounds
* @ type Number
* /
this . boundsPadding = 10 ;
} ;
// constructor
PIXI . Graphics . prototype = Object . create ( PIXI . DisplayObjectContainer . prototype ) ;
PIXI . Graphics . prototype . constructor = PIXI . Graphics ;
/ * *
* If cacheAsBitmap is true the graphics object will then be rendered as if it was a sprite .
* This is useful if your graphics element does not change often as it will speed up the rendering of the object
* It is also usful as the graphics object will always be antialiased because it will be rendered using canvas
* Not recommended if you are constanly redrawing the graphics element .
*
* @ property cacheAsBitmap
* @ default false
* @ type Boolean
* @ private
* /
Object . defineProperty ( PIXI . Graphics . prototype , "cacheAsBitmap" , {
get : function ( ) {
return this . _cacheAsBitmap ;
} ,
set : function ( value ) {
this . _cacheAsBitmap = value ;
if ( this . _cacheAsBitmap )
{
this . _generateCachedSprite ( ) ;
}
else
{
this . destroyCachedSprite ( ) ;
this . dirty = true ;
}
}
} ) ;
/ * *
* Specifies the line style used for subsequent calls to Graphics methods such as the lineTo ( ) method or the drawCircle ( ) method .
*
* @ method lineStyle
* @ param lineWidth { Number } width of the line to draw , will update the object ' s stored style
* @ param color { Number } color of the line to draw , will update the object ' s stored style
* @ param alpha { Number } alpha of the line to draw , will update the object ' s stored style
* /
PIXI . Graphics . prototype . lineStyle = function ( lineWidth , color , alpha )
{
if ( ! this . currentPath . points . length ) this . graphicsData . pop ( ) ;
this . lineWidth = lineWidth || 0 ;
this . lineColor = color || 0 ;
this . lineAlpha = ( arguments . length < 3 ) ? 1 : alpha ;
this . currentPath = { lineWidth : this . lineWidth , lineColor : this . lineColor , lineAlpha : this . lineAlpha ,
fillColor : this . fillColor , fillAlpha : this . fillAlpha , fill : this . filling , points : [ ] , type : PIXI . Graphics . POLY } ;
this . graphicsData . push ( this . currentPath ) ;
return this ;
} ;
/ * *
* Moves the current drawing position to ( x , y ) .
*
* @ method moveTo
* @ param x { Number } the X coordinate to move to
* @ param y { Number } the Y coordinate to move to
* /
PIXI . Graphics . prototype . moveTo = function ( x , y )
{
if ( ! this . currentPath . points . length ) this . graphicsData . pop ( ) ;
this . currentPath = this . currentPath = { lineWidth : this . lineWidth , lineColor : this . lineColor , lineAlpha : this . lineAlpha ,
fillColor : this . fillColor , fillAlpha : this . fillAlpha , fill : this . filling , points : [ ] , type : PIXI . Graphics . POLY } ;
this . currentPath . points . push ( x , y ) ;
this . graphicsData . push ( this . currentPath ) ;
return this ;
} ;
/ * *
* Draws a line using the current line style from the current drawing position to ( x , y ) ;
* the current drawing position is then set to ( x , y ) .
*
* @ method lineTo
* @ param x { Number } the X coordinate to draw to
* @ param y { Number } the Y coordinate to draw to
* /
PIXI . Graphics . prototype . lineTo = function ( x , y )
{
this . currentPath . points . push ( x , y ) ;
this . dirty = true ;
return this ;
} ;
/ * *
* Specifies a simple one - color fill that subsequent calls to other Graphics methods
* ( such as lineTo ( ) or drawCircle ( ) ) use when drawing .
*
* @ method beginFill
* @ param color { Number } the color of the fill
* @ param alpha { Number } the alpha of the fill
* /
PIXI . Graphics . prototype . beginFill = function ( color , alpha )
{
this . filling = true ;
this . fillColor = color || 0 ;
this . fillAlpha = ( arguments . length < 2 ) ? 1 : alpha ;
return this ;
} ;
/ * *
* Applies a fill to the lines and shapes that were added since the last call to the beginFill ( ) method .
*
* @ method endFill
* /
PIXI . Graphics . prototype . endFill = function ( )
{
this . filling = false ;
this . fillColor = null ;
this . fillAlpha = 1 ;
return this ;
} ;
/ * *
* @ method drawRect
*
* @ param x { Number } The X coord of the top - left of the rectangle
* @ param y { Number } The Y coord of the top - left of the rectangle
* @ param width { Number } The width of the rectangle
* @ param height { Number } The height of the rectangle
* /
PIXI . Graphics . prototype . drawRect = function ( x , y , width , height )
{
if ( ! this . currentPath . points . length ) this . graphicsData . pop ( ) ;
this . currentPath = { lineWidth : this . lineWidth , lineColor : this . lineColor , lineAlpha : this . lineAlpha ,
fillColor : this . fillColor , fillAlpha : this . fillAlpha , fill : this . filling ,
points : [ x , y , width , height ] , type : PIXI . Graphics . RECT } ;
this . graphicsData . push ( this . currentPath ) ;
this . dirty = true ;
return this ;
} ;
/ * *
* Draws a circle .
*
* @ method drawCircle
* @ param x { Number } The X coordinate of the center of the circle
* @ param y { Number } The Y coordinate of the center of the circle
* @ param radius { Number } The radius of the circle
* /
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 ,
fillColor : this . fillColor , fillAlpha : this . fillAlpha , fill : this . filling ,
points : [ x , y , radius , radius ] , type : PIXI . Graphics . CIRC } ;
this . graphicsData . push ( this . currentPath ) ;
this . dirty = true ;
return this ;
} ;
/ * *
* Draws an ellipse .
*
* @ method drawEllipse
* @ param x { Number } The X coordinate of the upper - left corner of the framing rectangle of this ellipse
* @ param y { Number } The Y coordinate of the upper - left corner of the framing rectangle of this ellipse
* @ param width { Number } The width of the ellipse
* @ param height { Number } The height of the ellipse
* /
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 ,
fillColor : this . fillColor , fillAlpha : this . fillAlpha , fill : this . filling ,
points : [ x , y , width , height ] , type : PIXI . Graphics . ELIP } ;
this . graphicsData . push ( this . currentPath ) ;
this . dirty = true ;
return this ;
} ;
/ * *
* Clears the graphics that were drawn to this Graphics object , and resets fill and line style settings .
*
* @ method clear
* /
PIXI . Graphics . prototype . clear = function ( )
{
this . lineWidth = 0 ;
this . filling = false ;
this . dirty = true ;
this . clearDirty = true ;
this . graphicsData = [ ] ;
this . bounds = null ; //new PIXI.Rectangle();
return this ;
} ;
/ * *
* Useful function that returns a texture of the graphics object that can then be used to create sprites
* This can be quite useful if your geometry is complicated and needs to be reused multiple times .
*
* @ method generateTexture
* @ return { Texture } a texture of the graphics object
* /
PIXI . Graphics . prototype . generateTexture = function ( )
{
var bounds = this . getBounds ( ) ;
var canvasBuffer = new PIXI . CanvasBuffer ( bounds . width , bounds . height ) ;
var texture = PIXI . Texture . fromCanvas ( canvasBuffer . canvas ) ;
canvasBuffer . context . translate ( - bounds . x , - bounds . y ) ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
PIXI . CanvasGraphics . renderGraphics ( this , canvasBuffer . context ) ;
return texture ;
} ;
/ * *
* Renders the object using the WebGL renderer
*
* @ method _renderWebGL
2014-04-01 02:02:36 +00:00
* @ param renderSession { RenderSession }
2014-02-28 09:30:53 +00:00
* @ private
* /
PIXI . Graphics . prototype . _renderWebGL = function ( renderSession )
{
// if the sprite is not visible or the alpha is 0 then no need to render this element
if ( this . visible === false || this . alpha === 0 || this . isMask === true ) return ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
if ( this . _cacheAsBitmap )
{
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
if ( this . dirty )
{
this . _generateCachedSprite ( ) ;
// we will also need to update the texture on the gpu too!
PIXI . updateWebGLTexture ( this . _cachedSprite . texture . baseTexture , renderSession . gl ) ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
this . dirty = false ;
}
2014-04-01 02:02:36 +00:00
this . _cachedSprite . alpha = this . alpha ;
2014-02-28 09:30:53 +00:00
PIXI . Sprite . prototype . _renderWebGL . call ( this . _cachedSprite , renderSession ) ;
return ;
}
else
{
renderSession . spriteBatch . stop ( ) ;
if ( this . _mask ) renderSession . maskManager . pushMask ( this . mask , renderSession ) ;
if ( this . _filters ) renderSession . filterManager . pushFilter ( this . _filterBlock ) ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
// check blend mode
if ( this . blendMode !== renderSession . spriteBatch . currentBlendMode )
{
renderSession . spriteBatch . currentBlendMode = this . blendMode ;
var blendModeWebGL = PIXI . blendModesWebGL [ renderSession . spriteBatch . currentBlendMode ] ;
renderSession . spriteBatch . gl . blendFunc ( blendModeWebGL [ 0 ] , blendModeWebGL [ 1 ] ) ;
}
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
PIXI . WebGLGraphics . renderGraphics ( this , renderSession ) ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
// only render if it has children!
if ( this . children . length )
{
renderSession . spriteBatch . start ( ) ;
// simple render children!
for ( var i = 0 , j = this . children . length ; i < j ; i ++ )
{
this . children [ i ] . _renderWebGL ( renderSession ) ;
}
renderSession . spriteBatch . stop ( ) ;
}
if ( this . _filters ) renderSession . filterManager . popFilter ( ) ;
if ( this . _mask ) renderSession . maskManager . popMask ( renderSession ) ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
renderSession . drawCount ++ ;
renderSession . spriteBatch . start ( ) ;
}
} ;
/ * *
* Renders the object using the Canvas renderer
*
* @ method _renderCanvas
2014-04-01 02:02:36 +00:00
* @ param renderSession { RenderSession }
2014-02-28 09:30:53 +00:00
* @ private
* /
PIXI . Graphics . prototype . _renderCanvas = function ( renderSession )
{
// if the sprite is not visible or the alpha is 0 then no need to render this element
if ( this . visible === false || this . alpha === 0 || this . isMask === true ) return ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
var context = renderSession . context ;
var transform = this . worldTransform ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
if ( this . blendMode !== renderSession . currentBlendMode )
{
renderSession . currentBlendMode = this . blendMode ;
context . globalCompositeOperation = PIXI . blendModesCanvas [ renderSession . currentBlendMode ] ;
}
context . setTransform ( transform . a , transform . c , transform . b , transform . d , transform . tx , transform . ty ) ;
PIXI . CanvasGraphics . renderGraphics ( this , context ) ;
// simple render children!
for ( var i = 0 , j = this . children . length ; i < j ; i ++ )
{
this . children [ i ] . _renderCanvas ( renderSession ) ;
}
} ;
/ * *
* Retrieves the bounds of the graphic shape as a rectangle object
*
* @ method getBounds
* @ return { Rectangle } the rectangular bounding area
* /
PIXI . Graphics . prototype . getBounds = function ( matrix )
{
if ( ! this . bounds ) this . updateBounds ( ) ;
var w0 = this . bounds . x ;
var w1 = this . bounds . width + this . bounds . x ;
var h0 = this . bounds . y ;
var h1 = this . bounds . height + this . bounds . y ;
var worldTransform = matrix || this . worldTransform ;
var a = worldTransform . a ;
var b = worldTransform . c ;
var c = worldTransform . b ;
var d = worldTransform . d ;
var tx = worldTransform . tx ;
var ty = worldTransform . ty ;
var x1 = a * w1 + c * h1 + tx ;
var y1 = d * h1 + b * w1 + ty ;
var x2 = a * w0 + c * h1 + tx ;
var y2 = d * h1 + b * w0 + ty ;
var x3 = a * w0 + c * h0 + tx ;
var y3 = d * h0 + b * w0 + ty ;
var x4 = a * w1 + c * h0 + tx ;
var y4 = d * h0 + b * w1 + ty ;
var maxX = - Infinity ;
var maxY = - Infinity ;
var minX = Infinity ;
var minY = Infinity ;
minX = x1 < minX ? x1 : minX ;
minX = x2 < minX ? x2 : minX ;
minX = x3 < minX ? x3 : minX ;
minX = x4 < minX ? x4 : minX ;
minY = y1 < minY ? y1 : minY ;
minY = y2 < minY ? y2 : minY ;
minY = y3 < minY ? y3 : minY ;
minY = y4 < minY ? y4 : minY ;
maxX = x1 > maxX ? x1 : maxX ;
maxX = x2 > maxX ? x2 : maxX ;
maxX = x3 > maxX ? x3 : maxX ;
maxX = x4 > maxX ? x4 : maxX ;
maxY = y1 > maxY ? y1 : maxY ;
maxY = y2 > maxY ? y2 : maxY ;
maxY = y3 > maxY ? y3 : maxY ;
maxY = y4 > maxY ? y4 : maxY ;
var bounds = this . _bounds ;
bounds . x = minX ;
bounds . width = maxX - minX ;
bounds . y = minY ;
bounds . height = maxY - minY ;
return bounds ;
} ;
/ * *
* Update the bounds of the object
*
* @ method updateBounds
* /
PIXI . Graphics . prototype . updateBounds = function ( )
{
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
var minX = Infinity ;
var maxX = - Infinity ;
var minY = Infinity ;
var maxY = - Infinity ;
var points , x , y , w , h ;
for ( var i = 0 ; i < this . graphicsData . length ; i ++ ) {
var data = this . graphicsData [ i ] ;
var type = data . type ;
var lineWidth = data . lineWidth ;
points = data . points ;
if ( type === PIXI . Graphics . RECT )
{
x = points [ 0 ] - lineWidth / 2 ;
y = points [ 1 ] - lineWidth / 2 ;
w = points [ 2 ] + lineWidth ;
h = points [ 3 ] + lineWidth ;
minX = x < minX ? x : minX ;
maxX = x + w > maxX ? x + w : maxX ;
minY = y < minY ? x : minY ;
maxY = y + h > maxY ? y + h : maxY ;
}
else if ( type === PIXI . Graphics . CIRC || type === PIXI . Graphics . ELIP )
{
x = points [ 0 ] ;
y = points [ 1 ] ;
w = points [ 2 ] + lineWidth / 2 ;
h = points [ 3 ] + lineWidth / 2 ;
minX = x - w < minX ? x - w : minX ;
maxX = x + w > maxX ? x + w : maxX ;
minY = y - h < minY ? y - h : minY ;
maxY = y + h > maxY ? y + h : maxY ;
}
else
{
// POLY
for ( var j = 0 ; j < points . length ; j += 2 )
{
x = points [ j ] ;
y = points [ j + 1 ] ;
minX = x - lineWidth < minX ? x - lineWidth : minX ;
maxX = x + lineWidth > maxX ? x + lineWidth : maxX ;
minY = y - lineWidth < minY ? y - lineWidth : minY ;
maxY = y + lineWidth > maxY ? y + lineWidth : maxY ;
}
}
}
var padding = this . boundsPadding ;
this . bounds = new PIXI . Rectangle ( minX - padding , minY - padding , ( maxX - minX ) + padding * 2 , ( maxY - minY ) + padding * 2 ) ;
} ;
/ * *
* Generates the cached sprite when the sprite has cacheAsBitmap = true
*
* @ method _generateCachedSprite
* @ private
* /
PIXI . Graphics . prototype . _generateCachedSprite = function ( )
{
var bounds = this . getLocalBounds ( ) ;
if ( ! this . _cachedSprite )
{
var canvasBuffer = new PIXI . CanvasBuffer ( bounds . width , bounds . height ) ;
var texture = PIXI . Texture . fromCanvas ( canvasBuffer . canvas ) ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
this . _cachedSprite = new PIXI . Sprite ( texture ) ;
this . _cachedSprite . buffer = canvasBuffer ;
this . _cachedSprite . worldTransform = this . worldTransform ;
}
else
{
this . _cachedSprite . buffer . resize ( bounds . width , bounds . height ) ;
}
// leverage the anchor to account for the offset of the element
this . _cachedSprite . anchor . x = - ( bounds . x / bounds . width ) ;
this . _cachedSprite . anchor . y = - ( bounds . y / bounds . height ) ;
// this._cachedSprite.buffer.context.save();
this . _cachedSprite . buffer . context . translate ( - bounds . x , - bounds . y ) ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
PIXI . CanvasGraphics . renderGraphics ( this , this . _cachedSprite . buffer . context ) ;
2014-04-01 02:02:36 +00:00
this . _cachedSprite . alpha = this . alpha ;
2014-02-28 09:30:53 +00:00
// this._cachedSprite.buffer.context.restore();
} ;
PIXI . Graphics . prototype . destroyCachedSprite = function ( )
{
this . _cachedSprite . texture . destroy ( true ) ;
// let the gc collect the unused sprite
// TODO could be object pooled!
this . _cachedSprite = null ;
} ;
// SOME TYPES:
PIXI . Graphics . POLY = 0 ;
PIXI . Graphics . RECT = 1 ;
PIXI . Graphics . CIRC = 2 ;
PIXI . Graphics . ELIP = 3 ;
/ * *
* @ author Mat Groves http : //matgroves.com/
* /
/ * *
* A tiling sprite is a fast way of rendering a tiling image
*
* @ class TilingSprite
2014-02-28 18:55:07 +00:00
* @ extends Sprite
2014-02-28 09:30:53 +00:00
* @ constructor
* @ param texture { Texture } the texture of the tiling sprite
* @ param width { Number } the width of the tiling sprite
* @ param height { Number } the height of the tiling sprite
* /
PIXI . TilingSprite = function ( texture , width , height )
{
PIXI . Sprite . call ( this , texture ) ;
/ * *
* The with of the tiling sprite
*
* @ property width
* @ type Number
* /
this . width = width || 100 ;
2014-02-28 18:55:07 +00:00
2014-02-28 09:30:53 +00:00
/ * *
* The height of the tiling sprite
*
* @ property height
* @ type Number
* /
this . height = height || 100 ;
/ * *
* The scaling of the image that is being tiled
*
* @ property tileScale
* @ type Point
* /
this . tileScale = new PIXI . Point ( 1 , 1 ) ;
/ * *
* A point that represents the scale of the texture object
*
* @ property tileScaleOffset
* @ type Point
* /
this . tileScaleOffset = new PIXI . Point ( 1 , 1 ) ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
/ * *
* The offset position of the image that is being tiled
*
* @ property tilePosition
* @ type Point
* /
this . tilePosition = new PIXI . Point ( 0 , 0 ) ;
/ * *
* Whether this sprite is renderable or not
*
* @ property renderable
* @ type Boolean
* @ default true
* /
this . renderable = true ;
/ * *
* The tint applied to the sprite . This is a hex value
*
* @ property tint
* @ type Number
* @ default 0xFFFFFF
* /
this . tint = 0xFFFFFF ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
/ * *
* The blend mode to be applied to the sprite
*
* @ property blendMode
* @ type Number
* @ default PIXI . blendModes . NORMAL ;
* /
this . blendMode = PIXI . blendModes . NORMAL ;
} ;
// constructor
PIXI . TilingSprite . prototype = Object . create ( PIXI . Sprite . prototype ) ;
PIXI . TilingSprite . prototype . constructor = PIXI . TilingSprite ;
/ * *
* The width of the sprite , setting this will actually modify the scale to achieve the value set
*
* @ property width
* @ type Number
* /
Object . defineProperty ( PIXI . TilingSprite . prototype , 'width' , {
get : function ( ) {
return this . _width ;
} ,
set : function ( value ) {
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
this . _width = value ;
}
} ) ;
/ * *
* The height of the TilingSprite , setting this will actually modify the scale to achieve the value set
*
* @ property height
* @ type Number
* /
Object . defineProperty ( PIXI . TilingSprite . prototype , 'height' , {
get : function ( ) {
return this . _height ;
} ,
set : function ( value ) {
this . _height = value ;
}
} ) ;
/ * *
* When the texture is updated , this event will be fired to update the scale and frame
*
* @ method onTextureUpdate
* @ param event
* @ private
* /
PIXI . TilingSprite . prototype . onTextureUpdate = function ( )
{
this . updateFrame = true ;
} ;
PIXI . TilingSprite . prototype . setTexture = function ( texture )
{
if ( this . texture === texture ) return ;
this . texture = texture ;
this . refreshTexture = true ;
/ *
if ( this . tilingTexture )
{
this . generateTilingTexture ( true ) ;
}
* /
/ *
// stop current texture;
if ( this . texture . baseTexture !== texture . baseTexture )
{
this . textureChange = true ;
this . texture = texture ;
}
else
{
this . texture = texture ;
}
this . updateFrame = true ; * /
this . cachedTint = 0xFFFFFF ;
} ;
/ * *
* Renders the object using the WebGL renderer
*
* @ method _renderWebGL
2014-04-01 02:02:36 +00:00
* @ param renderSession { RenderSession }
2014-02-28 09:30:53 +00:00
* @ private
* /
PIXI . TilingSprite . prototype . _renderWebGL = function ( renderSession )
{
if ( this . visible === false || this . alpha === 0 ) return ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
var i , j ;
2014-02-28 18:55:07 +00:00
if ( this . mask )
2014-02-28 09:30:53 +00:00
{
2014-02-28 18:55:07 +00:00
renderSession . spriteBatch . stop ( ) ;
renderSession . maskManager . pushMask ( this . mask , renderSession ) ;
renderSession . spriteBatch . start ( ) ;
}
2014-02-28 09:30:53 +00:00
2014-02-28 18:55:07 +00:00
if ( this . filters )
{
renderSession . spriteBatch . flush ( ) ;
renderSession . filterManager . pushFilter ( this . _filterBlock ) ;
}
2014-02-28 09:30:53 +00:00
2014-02-28 18:55:07 +00:00
if ( ! this . tilingTexture || this . refreshTexture )
{
this . generateTilingTexture ( true ) ;
if ( this . tilingTexture && this . tilingTexture . needsUpdate )
2014-02-28 09:30:53 +00:00
{
2014-02-28 18:55:07 +00:00
//TODO - tweaking
PIXI . updateWebGLTexture ( this . tilingTexture . baseTexture , renderSession . gl ) ;
this . tilingTexture . needsUpdate = false ;
// this.tilingTexture._uvs = null;
2014-02-28 09:30:53 +00:00
}
}
2014-02-28 18:55:07 +00:00
else renderSession . spriteBatch . renderTilingSprite ( this ) ;
2014-04-01 02:02:36 +00:00
2014-02-28 18:55:07 +00:00
// simple render children!
for ( i = 0 , j = this . children . length ; i < j ; i ++ )
2014-02-28 09:30:53 +00:00
{
2014-02-28 18:55:07 +00:00
this . children [ i ] . _renderWebGL ( renderSession ) ;
2014-02-28 09:30:53 +00:00
}
2014-02-28 18:55:07 +00:00
renderSession . spriteBatch . stop ( ) ;
if ( this . filters ) renderSession . filterManager . popFilter ( ) ;
if ( this . mask ) renderSession . maskManager . popMask ( renderSession ) ;
2014-04-01 02:02:36 +00:00
2014-02-28 18:55:07 +00:00
renderSession . spriteBatch . start ( ) ;
2014-02-28 09:30:53 +00:00
} ;
/ * *
* Renders the object using the Canvas renderer
*
* @ method _renderCanvas
2014-04-01 02:02:36 +00:00
* @ param renderSession { RenderSession }
2014-02-28 09:30:53 +00:00
* @ private
* /
PIXI . TilingSprite . prototype . _renderCanvas = function ( renderSession )
{
if ( this . visible === false || this . alpha === 0 ) return ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
var context = renderSession . context ;
if ( this . _mask )
{
renderSession . maskManager . pushMask ( this . _mask , context ) ;
}
context . globalAlpha = this . worldAlpha ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
var transform = this . worldTransform ;
// allow for trimming
2014-04-01 02:02:36 +00:00
//(this.anchor.x) * -frame.width,
// (this.anchor.y) * -frame.height,
2014-02-28 09:30:53 +00:00
2014-04-01 02:02:36 +00:00
context . setTransform ( transform . a , transform . c , transform . b , transform . d , transform . tx , transform . ty ) ;
2014-02-28 09:30:53 +00:00
if ( ! this . _ _tilePattern || this . refreshTexture )
{
this . generateTilingTexture ( false ) ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
if ( this . tilingTexture )
{
this . _ _tilePattern = context . createPattern ( this . tilingTexture . baseTexture . source , 'repeat' ) ;
}
2014-04-01 02:02:36 +00:00
else
{
return ;
}
2014-02-28 09:30:53 +00:00
}
// check blend mode
if ( this . blendMode !== renderSession . currentBlendMode )
{
renderSession . currentBlendMode = this . blendMode ;
context . globalCompositeOperation = PIXI . blendModesCanvas [ renderSession . currentBlendMode ] ;
}
context . beginPath ( ) ;
var tilePosition = this . tilePosition ;
var tileScale = this . tileScale ;
tilePosition . x %= this . tilingTexture . baseTexture . width ;
tilePosition . y %= this . tilingTexture . baseTexture . height ;
// offset
context . scale ( tileScale . x , tileScale . y ) ;
context . translate ( tilePosition . x , tilePosition . y ) ;
context . fillStyle = this . _ _tilePattern ;
2014-04-01 02:02:36 +00:00
// make sure to account for the anchor point..
context . fillRect ( - tilePosition . x + ( this . anchor . x * - this . _width ) , - tilePosition . y + ( this . anchor . y * - this . _height ) ,
this . _width / tileScale . x , this . _height / tileScale . y ) ;
2014-02-28 09:30:53 +00:00
context . scale ( 1 / tileScale . x , 1 / tileScale . y ) ;
context . translate ( - tilePosition . x , - tilePosition . y ) ;
context . closePath ( ) ;
if ( this . _mask )
{
renderSession . maskManager . popMask ( renderSession . context ) ;
}
} ;
/ * *
* Returns the framing rectangle of the sprite as a PIXI . Rectangle object
*
* @ method getBounds
* @ return { Rectangle } the framing rectangle
* /
PIXI . TilingSprite . prototype . getBounds = function ( )
{
var width = this . _width ;
var height = this . _height ;
var w0 = width * ( 1 - this . anchor . x ) ;
var w1 = width * - this . anchor . x ;
var h0 = height * ( 1 - this . anchor . y ) ;
var h1 = height * - this . anchor . y ;
var worldTransform = this . worldTransform ;
var a = worldTransform . a ;
var b = worldTransform . c ;
var c = worldTransform . b ;
var d = worldTransform . d ;
var tx = worldTransform . tx ;
var ty = worldTransform . ty ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
var x1 = a * w1 + c * h1 + tx ;
var y1 = d * h1 + b * w1 + ty ;
var x2 = a * w0 + c * h1 + tx ;
var y2 = d * h1 + b * w0 + ty ;
var x3 = a * w0 + c * h0 + tx ;
var y3 = d * h0 + b * w0 + ty ;
var x4 = a * w1 + c * h0 + tx ;
var y4 = d * h0 + b * w1 + ty ;
var maxX = - Infinity ;
var maxY = - Infinity ;
var minX = Infinity ;
var minY = Infinity ;
minX = x1 < minX ? x1 : minX ;
minX = x2 < minX ? x2 : minX ;
minX = x3 < minX ? x3 : minX ;
minX = x4 < minX ? x4 : minX ;
minY = y1 < minY ? y1 : minY ;
minY = y2 < minY ? y2 : minY ;
minY = y3 < minY ? y3 : minY ;
minY = y4 < minY ? y4 : minY ;
maxX = x1 > maxX ? x1 : maxX ;
maxX = x2 > maxX ? x2 : maxX ;
maxX = x3 > maxX ? x3 : maxX ;
maxX = x4 > maxX ? x4 : maxX ;
maxY = y1 > maxY ? y1 : maxY ;
maxY = y2 > maxY ? y2 : maxY ;
maxY = y3 > maxY ? y3 : maxY ;
maxY = y4 > maxY ? y4 : maxY ;
var bounds = this . _bounds ;
bounds . x = minX ;
bounds . width = maxX - minX ;
bounds . y = minY ;
bounds . height = maxY - minY ;
// store a reference so that if this function gets called again in the render cycle we do not have to recalculate
this . _currentBounds = bounds ;
return bounds ;
} ;
/ * *
2014-04-01 02:02:36 +00:00
*
2014-02-28 09:30:53 +00:00
* @ method generateTilingTexture
2014-04-01 02:02:36 +00:00
*
2014-02-28 09:30:53 +00:00
* @ param forcePowerOfTwo { Boolean } Whether we want to force the texture to be a power of two
* /
PIXI . TilingSprite . prototype . generateTilingTexture = function ( forcePowerOfTwo )
{
var texture = this . texture ;
if ( ! texture . baseTexture . hasLoaded ) return ;
var baseTexture = texture . baseTexture ;
var frame = texture . frame ;
var targetWidth , targetHeight ;
// check that the frame is the same size as the base texture.
var isFrame = frame . width !== baseTexture . width || frame . height !== baseTexture . height ;
var newTextureRequired = false ;
if ( ! forcePowerOfTwo )
{
if ( isFrame )
{
2014-02-28 18:55:07 +00:00
targetWidth = frame . width ;
targetHeight = frame . height ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
newTextureRequired = true ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
}
}
else
{
targetWidth = PIXI . getNextPowerOfTwo ( frame . width ) ;
targetHeight = PIXI . getNextPowerOfTwo ( frame . height ) ;
if ( frame . width !== targetWidth && frame . height !== targetHeight ) newTextureRequired = true ;
}
if ( newTextureRequired )
{
var canvasBuffer ;
if ( this . tilingTexture && this . tilingTexture . isTiling )
{
canvasBuffer = this . tilingTexture . canvasBuffer ;
canvasBuffer . resize ( targetWidth , targetHeight ) ;
this . tilingTexture . baseTexture . width = targetWidth ;
this . tilingTexture . baseTexture . height = targetHeight ;
this . tilingTexture . needsUpdate = true ;
}
else
{
canvasBuffer = new PIXI . CanvasBuffer ( targetWidth , targetHeight ) ;
this . tilingTexture = PIXI . Texture . fromCanvas ( canvasBuffer . canvas ) ;
this . tilingTexture . canvasBuffer = canvasBuffer ;
this . tilingTexture . isTiling = true ;
}
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
canvasBuffer . context . drawImage ( texture . baseTexture . source ,
frame . x ,
frame . y ,
frame . width ,
frame . height ,
0 ,
0 ,
targetWidth ,
targetHeight ) ;
this . tileScaleOffset . x = frame . width / targetWidth ;
this . tileScaleOffset . y = frame . height / targetHeight ;
}
else
{
//TODO - switching?
if ( this . tilingTexture && this . tilingTexture . isTiling )
{
// destroy the tiling texture!
// TODO could store this somewhere?
this . tilingTexture . destroy ( true ) ;
}
this . tileScaleOffset . x = 1 ;
this . tileScaleOffset . y = 1 ;
this . tilingTexture = texture ;
}
this . refreshTexture = false ;
this . tilingTexture . baseTexture . _powerOf2 = true ;
} ;
/ * *
* @ author Mat Groves http : //matgroves.com/ @Doormat23
* /
PIXI . BaseTextureCache = { } ;
PIXI . texturesToUpdate = [ ] ;
PIXI . texturesToDestroy = [ ] ;
PIXI . BaseTextureCacheIdGenerator = 0 ;
/ * *
* A texture stores the information that represents an image . All textures have a base texture
*
* @ class BaseTexture
* @ uses EventTarget
* @ constructor
* @ param source { String } the source object ( image or canvas )
* @ param scaleMode { Number } Should be one of the PIXI . scaleMode consts
* /
PIXI . BaseTexture = function ( source , scaleMode )
{
PIXI . EventTarget . call ( this ) ;
/ * *
* [ read - only ] The width of the base texture set when the image has loaded
*
* @ property width
* @ type Number
* @ readOnly
* /
this . width = 100 ;
/ * *
* [ read - only ] The height of the base texture set when the image has loaded
*
* @ property height
* @ type Number
* @ readOnly
* /
this . height = 100 ;
/ * *
* The scale mode to apply when scaling this texture
* @ property scaleMode
* @ type PIXI . scaleModes
* @ default PIXI . scaleModes . LINEAR
* /
this . scaleMode = scaleMode || PIXI . scaleModes . DEFAULT ;
/ * *
* [ read - only ] Describes if the base texture has loaded or not
*
* @ property hasLoaded
* @ type Boolean
* @ readOnly
* /
this . hasLoaded = false ;
/ * *
* The source that is loaded to create the texture
*
* @ property source
* @ type Image
* /
this . source = source ;
//TODO will be used for futer pixi 1.5...
this . id = PIXI . BaseTextureCacheIdGenerator ++ ;
// used for webGL
this . _glTextures = [ ] ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
if ( ! source ) return ;
if ( this . source . complete || this . source . getContext )
{
this . hasLoaded = true ;
this . width = this . source . width ;
this . height = this . source . height ;
PIXI . texturesToUpdate . push ( this ) ;
}
else
{
var scope = this ;
this . source . onload = function ( ) {
scope . hasLoaded = true ;
scope . width = scope . source . width ;
scope . height = scope . source . height ;
// add it to somewhere...
PIXI . texturesToUpdate . push ( scope ) ;
scope . dispatchEvent ( { type : 'loaded' , content : scope } ) ;
} ;
}
this . imageUrl = null ;
this . _powerOf2 = false ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
} ;
PIXI . BaseTexture . prototype . constructor = PIXI . BaseTexture ;
/ * *
* Destroys this base texture
*
* @ method destroy
* /
PIXI . BaseTexture . prototype . destroy = function ( )
{
if ( this . imageUrl )
{
delete PIXI . BaseTextureCache [ this . imageUrl ] ;
this . imageUrl = null ;
this . source . src = null ;
}
this . source = null ;
PIXI . texturesToDestroy . push ( this ) ;
} ;
/ * *
* Changes the source image of the texture
*
* @ method updateSourceImage
* @ param newSrc { String } the path of the image
* /
PIXI . BaseTexture . prototype . updateSourceImage = function ( newSrc )
{
this . hasLoaded = false ;
this . source . src = null ;
this . source . src = newSrc ;
} ;
/ * *
* Helper function that returns a base texture based on an image url
* If the image is not in the base texture cache it will be created and loaded
*
* @ static
* @ method fromImage
* @ param imageUrl { String } The image url of the texture
2014-04-01 02:02:36 +00:00
* @ param crossorigin { Boolean }
2014-02-28 09:30:53 +00:00
* @ param scaleMode { Number } Should be one of the PIXI . scaleMode consts
* @ return BaseTexture
* /
PIXI . BaseTexture . fromImage = function ( imageUrl , crossorigin , scaleMode )
{
var baseTexture = PIXI . BaseTextureCache [ imageUrl ] ;
2014-04-01 02:02:36 +00:00
if ( crossorigin === undefined ) crossorigin = true ;
2014-02-28 09:30:53 +00:00
if ( ! baseTexture )
{
// new Image() breaks tex loading in some versions of Chrome.
// See https://code.google.com/p/chromium/issues/detail?id=238071
var image = new Image ( ) ; //document.createElement('img');
if ( crossorigin )
{
image . crossOrigin = '' ;
}
image . src = imageUrl ;
baseTexture = new PIXI . BaseTexture ( image , scaleMode ) ;
baseTexture . imageUrl = imageUrl ;
PIXI . BaseTextureCache [ imageUrl ] = baseTexture ;
}
return baseTexture ;
} ;
PIXI . BaseTexture . fromCanvas = function ( canvas , scaleMode )
{
if ( ! canvas . _pixiId )
{
canvas . _pixiId = 'canvas_' + PIXI . TextureCacheIdGenerator ++ ;
}
var baseTexture = PIXI . BaseTextureCache [ canvas . _pixiId ] ;
if ( ! baseTexture )
{
baseTexture = new PIXI . BaseTexture ( canvas , scaleMode ) ;
PIXI . BaseTextureCache [ canvas . _pixiId ] = baseTexture ;
}
return baseTexture ;
} ;
/ * *
* @ author Mat Groves http : //matgroves.com/ @Doormat23
* /
PIXI . TextureCache = { } ;
PIXI . FrameCache = { } ;
PIXI . TextureCacheIdGenerator = 0 ;
/ * *
* A texture stores the information that represents an image or part of an image . It cannot be added
* to the display list directly . To do this use PIXI . Sprite . If no frame is provided then the whole image is used
*
* @ class Texture
* @ uses EventTarget
* @ constructor
* @ param baseTexture { BaseTexture } The base texture source to create the texture from
* @ param frame { Rectangle } The rectangle frame of the texture to show
* /
PIXI . Texture = function ( baseTexture , frame )
{
PIXI . EventTarget . call ( this ) ;
if ( ! frame )
{
this . noFrame = true ;
frame = new PIXI . Rectangle ( 0 , 0 , 1 , 1 ) ;
}
if ( baseTexture instanceof PIXI . Texture )
baseTexture = baseTexture . baseTexture ;
/ * *
* The base texture of that this texture uses
*
* @ property baseTexture
* @ type BaseTexture
* /
this . baseTexture = baseTexture ;
/ * *
* The frame specifies the region of the base texture that this texture uses
*
* @ property frame
* @ type Rectangle
* /
this . frame = frame ;
/ * *
* The trim point
*
* @ property trim
* @ type Rectangle
* /
this . trim = null ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
this . scope = this ;
this . _uvs = null ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
if ( baseTexture . hasLoaded )
{
if ( this . noFrame ) frame = new PIXI . Rectangle ( 0 , 0 , baseTexture . width , baseTexture . height ) ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
this . setFrame ( frame ) ;
}
else
{
var scope = this ;
baseTexture . addEventListener ( 'loaded' , function ( ) { scope . onBaseTextureLoaded ( ) ; } ) ;
}
} ;
PIXI . Texture . prototype . constructor = PIXI . Texture ;
/ * *
* Called when the base texture is loaded
*
* @ method onBaseTextureLoaded
* @ param event
* @ private
* /
PIXI . Texture . prototype . onBaseTextureLoaded = function ( )
{
var baseTexture = this . baseTexture ;
baseTexture . removeEventListener ( 'loaded' , this . onLoaded ) ;
if ( this . noFrame ) this . frame = new PIXI . Rectangle ( 0 , 0 , baseTexture . width , baseTexture . height ) ;
2014-04-01 02:02:36 +00:00
2014-02-28 09:30:53 +00:00
this . setFrame ( this . frame ) ;
this . scope . dispatchEvent ( { type : 'update' , content : this } ) ;
} ;
/ * *
* Destroys this texture
*
* @ method destroy
* @ param destroyBase { Boolean } Whether to destroy the base texture as well
* /
PIXI . Texture . prototype . destroy = function ( destroyBase )
{
if ( destroyBase ) this . baseTexture . destroy ( ) ;
} ;
/ * *
* Specifies the rectangle region of the baseTexture
*
* @ method setFrame
* @ param frame { Rectangle } The frame of the texture to set it to
* /
PIXI . Texture . prototype . setFrame = function ( frame )
{
this . frame = frame ;
this . width = frame . width ;
this . height = frame . height ;
if ( frame . x + frame . width > this . baseTexture . width || frame . y + frame . height > this . baseTexture . height )
{
throw new Error ( 'Texture Error: frame does not fit inside the base Texture dimensions ' + this ) ;
}
this . updateFrame = true ;
PIXI . Texture . frameUpdates . push ( this ) ;
//this.dispatchEvent( { type: 'update', content: this } );
} ;
PIXI . Texture . prototype . _updateWebGLuvs = function ( )
{
if ( ! this . _uvs ) this . _uvs = new PIXI . TextureUvs ( ) ;
var frame = this . frame ;
var tw = this . baseTexture . width ;
var th = this . baseTexture . height ;
this . _uvs . x0 = frame . x / tw ;
this . _uvs . y0 = frame . y / th ;
this . _uvs . x1 = ( frame . x + frame . width ) / tw ;
this . _uvs . y1 = frame . y / th ;
this . _uvs . x2 = ( frame . x + frame . width ) / tw ;
this . _uvs . y2 = ( frame . y + frame . height ) / th ;
this . _uvs . x3 = frame . x / tw ;
this . _uvs . y3 = ( 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
*
* @ static
* @ method fromImage
* @ param imageUrl { String } The image url of the texture
* @ param crossorigin { Boolean } Whether requests should be treated as crossorigin
* @ return Texture
* /
PIXI . Texture . fromImage = function ( imageUrl , crossorigin , scaleMode )
{
var texture = PIXI . TextureCache [ imageUrl ] ;
if ( ! texture )
{
texture = new PIXI . Texture ( PIXI . BaseTexture . fromImage ( imageUrl , crossorigin , scaleMode ) ) ;
PIXI . TextureCache [ imageUrl ] = texture ;
}
return texture ;
} ;
/ * *
* Helper function that returns a texture based on a frame id
* If the frame id is not in the texture cache an error will be thrown
*
* @ static
* @ method fromFrame
* @ param frameId { String } The frame id of the texture
* @ return Texture
* /
PIXI . Texture . fromFrame = function ( frameId )
{
var texture = PIXI . TextureCache [ frameId ] ;
if ( ! texture ) throw new Error ( 'The frameId "' + frameId + '" does not exist in the texture cache ' ) ;
return texture ;
} ;
/ * *
* Helper function that returns a texture based on a canvas element
* If the canvas is not in the texture cache it will be created and loaded
*
* @ static
* @ method fromCanvas
* @ param canvas { Canvas } The canvas element source of the texture
* @ return Texture
* /
PIXI . Texture . fromCanvas = function ( canvas , scaleMode )
{
var baseTexture = PIXI . BaseTexture . fromCanvas ( canvas , scaleMode ) ;
return new PIXI . Texture ( baseTexture ) ;
} ;
/ * *
* Adds a texture to the textureCache .
*
* @ static
* @ method addTextureToCache
* @ param texture { Texture }
* @ param id { String } the id that the texture will be stored against .
* /
PIXI . Texture . addTextureToCache = function ( texture , id )
{
PIXI . TextureCache [ id ] = texture ;
} ;
/ * *
* Remove a texture from the textureCache .
*
* @ static
* @ method removeTextureFromCache
* @ param id { String } the id of the texture to be removed
* @ return { Texture } the texture that was removed
* /
PIXI . Texture . removeTextureFromCache = function ( id )
{
var texture = PIXI . TextureCache [ id ] ;
delete PIXI . TextureCache [ id ] ;
delete PIXI . BaseTextureCache [ id ] ;
return texture ;
} ;
// this is more for webGL.. it contains updated frames..
PIXI . Texture . frameUpdates = [ ] ;
PIXI . TextureUvs = function ( )
{
this . x0 = 0 ;
this . y0 = 0 ;
this . x1 = 0 ;
this . y1 = 0 ;
this . x2 = 0 ;
this . y2 = 0 ;
this . x3 = 0 ;
this . y4 = 0 ;
} ;
/ * *
* @ author Mat Groves http : //matgroves.com/ @Doormat23
* /
/ * *
A RenderTexture is a special texture that allows any pixi displayObject to be rendered to it .
_ _Hint _ _ : All DisplayObjects ( exmpl . Sprites ) that render on RenderTexture should be preloaded .
Otherwise black rectangles will be drawn instead .
RenderTexture takes snapshot of DisplayObject passed to render method . If DisplayObject is passed to render method , position and rotation of it will be ignored . For example :
var renderTexture = new PIXI . RenderTexture ( 800 , 600 ) ;
var sprite = PIXI . Sprite . fromImage ( "spinObj_01.png" ) ;
sprite . position . x = 800 / 2 ;
sprite . position . y = 600 / 2 ;
sprite . anchor . x = 0.5 ;
sprite . anchor . y = 0.5 ;
renderTexture . render ( sprite ) ;
Sprite in this case will be rendered to 0 , 0 position . To render this sprite at center DisplayObjectContainer should be used :
var doc = new PIXI . DisplayObjectContainer ( ) ;
doc . addChild ( sprite ) ;
renderTexture . render ( doc ) ; // Renders to center of renderTexture
* @ class RenderTexture
* @ extends Texture
* @ constructor
* @ param width { Number } The width of the render texture
* @ param height { Number } The height of the render texture
* /
PIXI . RenderTexture = function ( width , height , renderer )
{
PIXI . EventTarget . call ( this ) ;
/ * *
* The with of the render texture
*
* @ property width
* @ type Number
* /
this . width = width || 100 ;
/ * *
* The height of the render texture
*
* @ property height
* @ type Number
* /
this . height = height || 100 ;
/ * *
* The framing rectangle of the render texture
*
* @ property frame
* @ type Rectangle
* /
this . frame = new PIXI . Rectangle ( 0 , 0 , this . width , this . height ) ;
/ * *
* The base texture object that this texture uses
*
* @ property baseTexture
* @ type BaseTexture
* /
this . baseTexture = new PIXI . BaseTexture ( ) ;
this . baseTexture . width = this . width ;
this . baseTexture . height = this . height ;
this . baseTexture . _glTextures = [ ] ;
this . baseTexture . hasLoaded = true ;
// each render texture can only belong to one renderer at the moment if its webGL
this . renderer = renderer || PIXI . defaultRenderer ;
if ( this . renderer . type === PIXI . WEBGL _RENDERER )
{
var gl = this . renderer . gl ;
this . textureBuffer = new PIXI . FilterTexture ( gl , this . width , this . height ) ;
this . baseTexture . _glTextures [ gl . id ] = this . textureBuffer . texture ;
this . render = this . renderWebGL ;
this . projection = new PIXI . Point ( this . width / 2 , - this . height / 2 ) ;
}
else
{
this . render = this . renderCanvas ;
this . textureBuffer = new PIXI . CanvasBuffer ( this . width , this . height ) ;
this . baseTexture . source = this . textureBuffer . canvas ;
}
PIXI . Texture . frameUpdates . push ( this ) ;
} ;
PIXI . RenderTexture . prototype = Object . create ( PIXI . Texture . prototype ) ;
PIXI . RenderTexture . prototype . constructor = PIXI . RenderTexture ;
PIXI . RenderTexture . prototype . resize = function ( width , height )
{
this . width = width ;
this . height = height ;
this . frame . width = this . width ;
this . frame . height = this . height ;
if ( this . renderer . type === PIXI . WEBGL _RENDERER )
{
this . projection . x = this . width / 2 ;
this . projection . y = - this . height / 2 ;
var gl = this . renderer . gl ;
gl . bindTexture ( gl . TEXTURE _2D , this . baseTexture . _glTextures [ gl . id ] ) ;
gl . texImage2D ( gl . TEXTURE _2D , 0 , gl . RGBA , this . width , this . height , 0 , gl . RGBA , gl . UNSIGNED _BYTE , null ) ;
}
else
{
this . textureBuffer . resize ( this . width , this . height ) ;
}
PIXI . Texture . frameUpdates . push ( this ) ;
} ;
/ * *
* This function will draw the display object to the texture .
*
* @ method renderWebGL
* @ param displayObject { DisplayObject } The display object to render this texture on
* @ param clear { Boolean } If true the texture will be cleared before the displayObject is drawn
* @ private
* /
PIXI . RenderTexture . prototype . renderWebGL = function ( displayObject , position , clear )
{
//TOOD replace position with matrix..
var gl = this . renderer . gl ;
gl . colorMask ( true , true , true , true ) ;
gl . viewport ( 0 , 0 , this . width , this . height ) ;
gl . bindFramebuffer ( gl . FRAMEBUFFER , this . textureBuffer . frameBuffer ) ;
if ( clear ) this . textureBuffer . clear ( ) ;
// THIS WILL MESS WITH HIT TESTING!
var children = displayObject . children ;
//TODO -? create a new one??? dont think so!
var originalWorldTransform = displayObject . worldTransform ;
displayObject . worldTransform = PIXI . RenderTexture . tempMatrix ;
// modify to flip...
displayObject . worldTransform . d = - 1 ;
displayObject . worldTransform . ty = this . projection . y * - 2 ;
if ( position )
{
displayObject . worldTransform . tx = position . x ;
displayObject . worldTransform . ty -= position . y ;
}
for ( var i = 0 , j = children . length ; i < j ; i ++ )
{
children [ i ] . updateTransform ( ) ;
}
// update the textures!
PIXI . WebGLRenderer . updateTextures ( ) ;
2014-04-01 02:02:36 +00:00
//
2014-02-28 09:30:53 +00:00
this . renderer . renderDisplayObject ( displayObject , this . projection , this . textureBuffer . frameBuffer ) ;
displayObject . worldTransform = originalWorldTransform ;
} ;
/ * *
* This function will draw the display object to the texture .
*
* @ method renderCanvas
* @ param displayObject { DisplayObject } The display object to render this texture on
* @ param clear { Boolean } If true the texture will be cleared before the displayObject is drawn
* @ private
* /
PIXI . RenderTexture . prototype . renderCanvas = function ( displayObject , position , clear )
{
var children = displayObject . children ;
var originalWorldTransform = displayObject . worldTransform ;
displayObject . worldTransform = PIXI . RenderTexture . tempMatrix ;
if ( position )
{
displayObject . worldTransform . tx = position . x ;
displayObject . worldTransform . ty = position . y ;
}
for ( var i = 0 , j = children . length ; i < j ; i ++ )
{
children [ i ] . updateTransform ( ) ;
}
if ( clear ) this . textureBuffer . clear ( ) ;
var context = this . textureBuffer . context ;
this . renderer . renderDisplayObject ( displayObject , context ) ;
context . setTransform ( 1 , 0 , 0 , 1 , 0 , 0 ) ;
displayObject . worldTransform = originalWorldTransform ;
} ;
PIXI . RenderTexture . tempMatrix = new PIXI . Matrix ( ) ;
/ * *
* @ author Mat Groves http : //matgroves.com/ @Doormat23
* /
if ( typeof exports !== 'undefined' ) {
if ( typeof module !== 'undefined' && module . exports ) {
exports = module . exports = PIXI ;
}
exports . PIXI = PIXI ;
} else if ( typeof define !== 'undefined' && define . amd ) {
2014-03-10 03:06:28 +00:00
define ( 'PIXI' , ( function ( ) { return root . PIXI = PIXI ; } ) ( ) ) ;
2014-02-28 09:30:53 +00:00
} else {
root . PIXI = PIXI ;
}
2014-04-01 02:02:36 +00:00
} ) . call ( this ) ;