0
0
Fork 0
mirror of https://github.com/liabru/matter-js.git synced 2025-01-13 16:18:50 -05:00
liabru-matter-js/src/render/RenderPixi.js

456 lines
15 KiB
JavaScript
Raw Normal View History

2014-03-19 20:46:25 -04:00
/**
* The `Matter.RenderPixi` module is an example renderer using pixi.js.
* See also `Matter.Render` for a canvas based renderer.
2014-03-19 20:46:25 -04:00
*
* @class RenderPixi
*/
var RenderPixi = {};
2015-06-04 15:54:50 -04:00
module.exports = RenderPixi;
var Composite = require('../body/Composite');
var Common = require('../core/Common');
2014-03-19 20:46:25 -04:00
(function() {
/**
* Creates a new Pixi.js WebGL renderer
* @method create
* @param {object} options
* @return {RenderPixi} A new renderer
*/
RenderPixi.create = function(options) {
var defaults = {
controller: RenderPixi,
element: null,
canvas: null,
renderer: null,
container: null,
spriteContainer: null,
pixiOptions: null,
2014-03-19 20:46:25 -04:00
options: {
width: 800,
height: 600,
background: '#fafafa',
wireframeBackground: '#222',
hasBounds: false,
2014-03-19 20:46:25 -04:00
enabled: true,
wireframes: true,
showSleeping: true,
showDebug: false,
showBroadphase: false,
showBounds: false,
showVelocity: false,
showCollisions: false,
showAxes: false,
showPositions: false,
showAngleIndicator: false,
showIds: false,
showShadows: false
}
};
var render = Common.extend(defaults, options),
transparent = !render.options.wireframes && render.options.background === 'transparent';
2014-03-19 20:46:25 -04:00
// init pixi
render.pixiOptions = render.pixiOptions || {
2015-05-19 15:07:04 -04:00
view: render.canvas,
transparent: transparent,
antialias: true,
backgroundColor: options.background
};
render.renderer = render.renderer || new PIXI.WebGLRenderer(render.options.width, render.options.height, render.pixiOptions);
render.container = render.container || new PIXI.Container();
render.spriteContainer = render.spriteContainer || new PIXI.Container();
render.canvas = render.canvas || render.renderer.view;
render.bounds = render.bounds || {
min: {
x: 0,
y: 0
},
max: {
x: render.options.width,
y: render.options.height
}
};
2014-03-19 20:46:25 -04:00
// caches
render.textures = {};
render.sprites = {};
render.primitives = {};
// use a sprite batch for performance
2015-05-21 14:10:17 -04:00
render.container.addChild(render.spriteContainer);
2014-03-19 20:46:25 -04:00
// insert canvas
if (Common.isElement(render.element)) {
render.element.appendChild(render.canvas);
} else {
Common.log('No "render.element" passed, "render.canvas" was not inserted into document.', 'warn');
}
// prevent menus on canvas
render.canvas.oncontextmenu = function() { return false; };
render.canvas.onselectstart = function() { return false; };
2014-03-19 20:46:25 -04:00
return render;
};
/**
* Clears the scene graph
* @method clear
* @param {RenderPixi} render
*/
RenderPixi.clear = function(render) {
var container = render.container,
2015-05-21 14:10:17 -04:00
spriteContainer = render.spriteContainer;
2014-03-19 20:46:25 -04:00
// clear stage container
while (container.children[0]) {
container.removeChild(container.children[0]);
2014-03-19 20:46:25 -04:00
}
// clear sprite batch
2015-05-21 14:10:17 -04:00
while (spriteContainer.children[0]) {
spriteContainer.removeChild(spriteContainer.children[0]);
2014-03-19 20:46:25 -04:00
}
var bgSprite = render.sprites['bg-0'];
// clear caches
render.textures = {};
render.sprites = {};
render.primitives = {};
// set background sprite
render.sprites['bg-0'] = bgSprite;
if (bgSprite)
2015-05-19 15:07:04 -04:00
container.addChildAt(bgSprite, 0);
2014-03-19 20:46:25 -04:00
// add sprite batch back into container
2015-05-21 14:10:17 -04:00
render.container.addChild(render.spriteContainer);
2014-03-19 20:46:25 -04:00
// reset background state
render.currentBackground = null;
// reset bounds transforms
container.scale.set(1, 1);
container.position.set(0, 0);
2014-03-19 20:46:25 -04:00
};
/**
* Sets the background of the canvas
* @method setBackground
* @param {RenderPixi} render
* @param {string} background
*/
RenderPixi.setBackground = function(render, background) {
if (render.currentBackground !== background) {
var isColor = background.indexOf && background.indexOf('#') !== -1,
bgSprite = render.sprites['bg-0'];
if (isColor) {
// if solid background color
var color = Common.colorToNumber(background);
render.renderer.backgroundColor = color;
2014-03-19 20:46:25 -04:00
// remove background sprite if existing
if (bgSprite)
2015-05-19 15:07:04 -04:00
render.container.removeChild(bgSprite);
2014-03-19 20:46:25 -04:00
} else {
// initialise background sprite if needed
if (!bgSprite) {
var texture = _getTexture(render, background);
bgSprite = render.sprites['bg-0'] = new PIXI.Sprite(texture);
bgSprite.position.x = 0;
bgSprite.position.y = 0;
2015-05-19 15:07:04 -04:00
render.container.addChildAt(bgSprite, 0);
2014-03-19 20:46:25 -04:00
}
}
render.currentBackground = background;
}
};
/**
* Description
* @method world
* @param {engine} engine
*/
RenderPixi.world = function(engine) {
var render = engine.render,
world = engine.world,
renderer = render.renderer,
container = render.container,
2014-03-19 20:46:25 -04:00
options = render.options,
bodies = Composite.allBodies(world),
allConstraints = Composite.allConstraints(world),
constraints = [],
2014-03-19 20:46:25 -04:00
i;
if (options.wireframes) {
RenderPixi.setBackground(render, options.wireframeBackground);
} else {
RenderPixi.setBackground(render, options.background);
}
// handle bounds
var boundsWidth = render.bounds.max.x - render.bounds.min.x,
boundsHeight = render.bounds.max.y - render.bounds.min.y,
boundsScaleX = boundsWidth / render.options.width,
boundsScaleY = boundsHeight / render.options.height;
if (options.hasBounds) {
// Hide bodies that are not in view
for (i = 0; i < bodies.length; i++) {
var body = bodies[i];
body.render.sprite.visible = Bounds.overlaps(body.bounds, render.bounds);
}
// filter out constraints that are not in view
for (i = 0; i < allConstraints.length; i++) {
var constraint = allConstraints[i],
bodyA = constraint.bodyA,
bodyB = constraint.bodyB,
pointAWorld = constraint.pointA,
pointBWorld = constraint.pointB;
if (bodyA) pointAWorld = Vector.add(bodyA.position, constraint.pointA);
if (bodyB) pointBWorld = Vector.add(bodyB.position, constraint.pointB);
if (!pointAWorld || !pointBWorld)
continue;
if (Bounds.contains(render.bounds, pointAWorld) || Bounds.contains(render.bounds, pointBWorld))
constraints.push(constraint);
}
// transform the view
container.scale.set(1 / boundsScaleX, 1 / boundsScaleY);
2014-07-12 13:14:04 -04:00
container.position.set(-render.bounds.min.x * (1 / boundsScaleX), -render.bounds.min.y * (1 / boundsScaleY));
} else {
constraints = allConstraints;
}
for (i = 0; i < bodies.length; i++)
RenderPixi.body(engine, bodies[i]);
2014-03-19 20:46:25 -04:00
for (i = 0; i < constraints.length; i++)
RenderPixi.constraint(engine, constraints[i]);
2014-03-19 20:46:25 -04:00
renderer.render(container);
2014-03-19 20:46:25 -04:00
};
/**
* Description
* @method constraint
* @param {engine} engine
* @param {constraint} constraint
*/
RenderPixi.constraint = function(engine, constraint) {
var render = engine.render,
bodyA = constraint.bodyA,
bodyB = constraint.bodyB,
pointA = constraint.pointA,
pointB = constraint.pointB,
container = render.container,
2014-03-19 20:46:25 -04:00
constraintRender = constraint.render,
primitiveId = 'c-' + constraint.id,
primitive = render.primitives[primitiveId];
// initialise constraint primitive if not existing
if (!primitive)
primitive = render.primitives[primitiveId] = new PIXI.Graphics();
// don't render if constraint does not have two end points
if (!constraintRender.visible || !constraint.pointA || !constraint.pointB) {
primitive.clear();
return;
}
// add to scene graph if not already there
2014-07-12 13:42:39 -04:00
if (Common.indexOf(container.children, primitive) === -1)
container.addChild(primitive);
2014-03-19 20:46:25 -04:00
// render the constraint on every update, since they can change dynamically
primitive.clear();
primitive.beginFill(0, 0);
primitive.lineStyle(constraintRender.lineWidth, Common.colorToNumber(constraintRender.strokeStyle), 1);
if (bodyA) {
primitive.moveTo(bodyA.position.x + pointA.x, bodyA.position.y + pointA.y);
} else {
primitive.moveTo(pointA.x, pointA.y);
}
if (bodyB) {
primitive.lineTo(bodyB.position.x + pointB.x, bodyB.position.y + pointB.y);
} else {
primitive.lineTo(pointB.x, pointB.y);
}
primitive.endFill();
};
/**
* Description
* @method body
* @param {engine} engine
* @param {body} body
*/
RenderPixi.body = function(engine, body) {
var render = engine.render,
bodyRender = body.render;
if (!bodyRender.visible)
return;
2014-03-27 10:38:59 -04:00
if (bodyRender.sprite && bodyRender.sprite.texture) {
2014-03-19 20:46:25 -04:00
var spriteId = 'b-' + body.id,
sprite = render.sprites[spriteId],
2015-05-21 14:10:17 -04:00
spriteContainer = render.spriteContainer;
2014-03-19 20:46:25 -04:00
// initialise body sprite if not existing
if (!sprite)
sprite = render.sprites[spriteId] = _createBodySprite(render, body);
// add to scene graph if not already there
2015-05-21 14:10:17 -04:00
if (Common.indexOf(spriteContainer.children, sprite) === -1)
spriteContainer.addChild(sprite);
2014-03-19 20:46:25 -04:00
// update body sprite
sprite.position.x = body.position.x;
sprite.position.y = body.position.y;
sprite.rotation = body.angle;
sprite.scale.x = bodyRender.sprite.xScale || 1;
sprite.scale.y = bodyRender.sprite.yScale || 1;
2014-03-19 20:46:25 -04:00
} else {
var primitiveId = 'b-' + body.id,
primitive = render.primitives[primitiveId],
container = render.container;
2014-03-19 20:46:25 -04:00
// initialise body primitive if not existing
if (!primitive) {
primitive = render.primitives[primitiveId] = _createBodyPrimitive(render, body);
primitive.initialAngle = body.angle;
}
// add to scene graph if not already there
2014-07-12 13:42:39 -04:00
if (Common.indexOf(container.children, primitive) === -1)
container.addChild(primitive);
2014-03-19 20:46:25 -04:00
// update body primitive
primitive.position.x = body.position.x;
primitive.position.y = body.position.y;
primitive.rotation = body.angle - primitive.initialAngle;
}
};
/**
* Creates a body sprite
* @method _createBodySprite
* @private
* @param {RenderPixi} render
* @param {body} body
* @return {PIXI.Sprite} sprite
*/
var _createBodySprite = function(render, body) {
var bodyRender = body.render,
texturePath = bodyRender.sprite.texture,
texture = _getTexture(render, texturePath),
sprite = new PIXI.Sprite(texture);
sprite.anchor.x = body.render.sprite.xOffset;
sprite.anchor.y = body.render.sprite.yOffset;
2014-03-19 20:46:25 -04:00
return sprite;
};
/**
* Creates a body primitive
* @method _createBodyPrimitive
* @private
* @param {RenderPixi} render
* @param {body} body
* @return {PIXI.Graphics} graphics
*/
2015-05-21 14:10:17 -04:00
var _createBodyPrimitive = function(render, body) {
2014-03-19 20:46:25 -04:00
var bodyRender = body.render,
options = render.options,
2015-04-21 16:16:26 -04:00
primitive = new PIXI.Graphics(),
fillStyle = Common.colorToNumber(bodyRender.fillStyle),
strokeStyle = Common.colorToNumber(bodyRender.strokeStyle),
strokeStyleIndicator = Common.colorToNumber(bodyRender.strokeStyle),
strokeStyleWireframe = Common.colorToNumber('#bbb'),
strokeStyleWireframeIndicator = Common.colorToNumber('#CD5C5C'),
part;
2014-03-19 20:46:25 -04:00
primitive.clear();
2015-04-21 16:16:26 -04:00
// handle compound parts
for (var k = body.parts.length > 1 ? 1 : 0; k < body.parts.length; k++) {
part = body.parts[k];
2014-03-19 20:46:25 -04:00
2015-04-21 16:16:26 -04:00
if (!options.wireframes) {
primitive.beginFill(fillStyle, 1);
primitive.lineStyle(bodyRender.lineWidth, strokeStyle, 1);
} else {
primitive.beginFill(0, 0);
primitive.lineStyle(1, strokeStyleWireframe, 1);
}
2014-03-19 20:46:25 -04:00
2015-04-21 16:16:26 -04:00
primitive.moveTo(part.vertices[0].x - body.position.x, part.vertices[0].y - body.position.y);
2014-03-19 20:46:25 -04:00
2015-04-21 16:16:26 -04:00
for (var j = 1; j < part.vertices.length; j++) {
primitive.lineTo(part.vertices[j].x - body.position.x, part.vertices[j].y - body.position.y);
}
2014-03-19 20:46:25 -04:00
2015-04-21 16:16:26 -04:00
primitive.lineTo(part.vertices[0].x - body.position.x, part.vertices[0].y - body.position.y);
2014-03-19 20:46:25 -04:00
2015-04-21 16:16:26 -04:00
primitive.endFill();
2014-03-19 20:46:25 -04:00
2015-04-21 16:16:26 -04:00
// angle indicator
if (options.showAngleIndicator || options.showAxes) {
primitive.beginFill(0, 0);
2014-03-19 20:46:25 -04:00
2015-04-21 16:16:26 -04:00
if (options.wireframes) {
primitive.lineStyle(1, strokeStyleWireframeIndicator, 1);
} else {
primitive.lineStyle(1, strokeStyleIndicator);
}
2014-03-19 20:46:25 -04:00
2015-04-21 16:16:26 -04:00
primitive.moveTo(part.position.x - body.position.x, part.position.y - body.position.y);
primitive.lineTo(((part.vertices[0].x + part.vertices[part.vertices.length-1].x) / 2 - body.position.x),
((part.vertices[0].y + part.vertices[part.vertices.length-1].y) / 2 - body.position.y));
primitive.endFill();
}
2014-03-19 20:46:25 -04:00
}
return primitive;
};
/**
* Gets the requested texture (a PIXI.Texture) via its path
* @method _getTexture
* @private
* @param {RenderPixi} render
* @param {string} imagePath
* @return {PIXI.Texture} texture
*/
var _getTexture = function(render, imagePath) {
var texture = render.textures[imagePath];
if (!texture)
texture = render.textures[imagePath] = PIXI.Texture.fromImage(imagePath);
return texture;
};
})();