/** * See [Demo.js](https://github.com/liabru/matter-js/blob/master/demo/js/Demo.js) * and [DemoMobile.js](https://github.com/liabru/matter-js/blob/master/demo/js/DemoMobile.js) for usage examples. * * @class RenderPixi */ var RenderPixi = {}; (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, options: { width: 800, height: 600, background: '#fafafa', wireframeBackground: '#222', 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); // init pixi render.context = new PIXI.WebGLRenderer(800, 600, render.canvas, false, true); render.canvas = render.context.view; render.stage = new PIXI.Stage(); // caches render.textures = {}; render.sprites = {}; render.primitives = {}; // use a sprite batch for performance render.spriteBatch = new PIXI.SpriteBatch(); render.stage.addChild(render.spriteBatch); // 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; }; return render; }; /** * Clears the scene graph * @method clear * @param {RenderPixi} render */ RenderPixi.clear = function(render) { var stage = render.stage, spriteBatch = render.spriteBatch; // clear stage while (stage.children[0]) { stage.removeChild(stage.children[0]); } // clear sprite batch while (spriteBatch.children[0]) { spriteBatch.removeChild(spriteBatch.children[0]); } var bgSprite = render.sprites['bg-0']; // clear caches render.textures = {}; render.sprites = {}; render.primitives = {}; // set background sprite render.sprites['bg-0'] = bgSprite; if (bgSprite) spriteBatch.addChildAt(bgSprite, 0); // add sprite batch back into stage render.stage.addChild(render.spriteBatch); // reset background state render.currentBackground = null; }; /** * 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.stage.setBackgroundColor(color); // remove background sprite if existing if (bgSprite) render.spriteBatch.removeChild(bgSprite); } 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; render.spriteBatch.addChildAt(bgSprite, 0); } } render.currentBackground = background; } }; /** * Description * @method world * @param {engine} engine */ RenderPixi.world = function(engine) { var render = engine.render, world = engine.world, context = render.context, stage = render.stage, options = render.options, bodies = Composite.allBodies(world), constraints = Composite.allConstraints(world), i; if (options.wireframes) { RenderPixi.setBackground(render, options.wireframeBackground); } else { RenderPixi.setBackground(render, options.background); } for (i = 0; i < bodies.length; i++) RenderPixi.body(engine, bodies[i]); for (i = 0; i < constraints.length; i++) RenderPixi.constraint(engine, constraints[i]); context.render(stage); }; /** * 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, stage = render.stage, 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 if (stage.children.indexOf(primitive) === -1) stage.addChild(primitive); // 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; if (bodyRender.sprite && bodyRender.sprite.texture) { var spriteId = 'b-' + body.id, sprite = render.sprites[spriteId], spriteBatch = render.spriteBatch; // initialise body sprite if not existing if (!sprite) sprite = render.sprites[spriteId] = _createBodySprite(render, body); // add to scene graph if not already there if (spriteBatch.children.indexOf(sprite) === -1) spriteBatch.addChild(sprite); // update body sprite sprite.position.x = body.position.x; sprite.position.y = body.position.y; sprite.rotation = body.angle; } else { var primitiveId = 'b-' + body.id, primitive = render.primitives[primitiveId], stage = render.stage; // 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 if (stage.children.indexOf(primitive) === -1) stage.addChild(primitive); // 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 = 0.5; sprite.anchor.y = 0.5; return sprite; }; /** * Creates a body primitive * @method _createBodyPrimitive * @private * @param {RenderPixi} render * @param {body} body * @return {PIXI.Graphics} graphics */ var _createBodyPrimitive = function(render, body) { var bodyRender = body.render, options = render.options, primitive = new PIXI.Graphics(); primitive.clear(); if (!options.wireframes) { primitive.beginFill(Common.colorToNumber(bodyRender.fillStyle), 1); primitive.lineStyle(body.render.lineWidth, Common.colorToNumber(bodyRender.strokeStyle), 1); } else { primitive.beginFill(0, 0); primitive.lineStyle(1, Common.colorToNumber('#bbb'), 1); } primitive.moveTo(body.vertices[0].x - body.position.x, body.vertices[0].y - body.position.y); for (var j = 1; j < body.vertices.length; j++) { primitive.lineTo(body.vertices[j].x - body.position.x, body.vertices[j].y - body.position.y); } primitive.lineTo(body.vertices[0].x - body.position.x, body.vertices[0].y - body.position.y); primitive.endFill(); // angle indicator if (options.showAngleIndicator || options.showAxes) { primitive.beginFill(0, 0); if (options.wireframes) { primitive.lineStyle(1, Common.colorToNumber('#CD5C5C'), 1); } else { primitive.lineStyle(1, Common.colorToNumber(body.render.strokeStyle)); } primitive.moveTo(0, 0); primitive.lineTo(((body.vertices[0].x + body.vertices[body.vertices.length-1].x) / 2) - body.position.x, ((body.vertices[0].y + body.vertices[body.vertices.length-1].y) / 2) - body.position.y); primitive.endFill(); } 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; }; })();