Show:

File: src/render/RenderPixi.js

  1. /**
  2. * The `Matter.RenderPixi` module is an example renderer using pixi.js.
  3. * See also `Matter.Render` for a canvas based renderer.
  4. *
  5. * @class RenderPixi
  6. * @deprecated the Matter.RenderPixi module will soon be removed from the Matter.js core.
  7. * It will likely be moved to its own repository (but maintenance will be limited).
  8. */
  9. var RenderPixi = {};
  10. module.exports = RenderPixi;
  11. var Bounds = require('../geometry/Bounds');
  12. var Composite = require('../body/Composite');
  13. var Common = require('../core/Common');
  14. var Events = require('../core/Events');
  15. var Vector = require('../geometry/Vector');
  16. (function() {
  17. var _requestAnimationFrame,
  18. _cancelAnimationFrame;
  19. if (typeof window !== 'undefined') {
  20. _requestAnimationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame
  21. || window.mozRequestAnimationFrame || window.msRequestAnimationFrame
  22. || function(callback){ window.setTimeout(function() { callback(Common.now()); }, 1000 / 60); };
  23. _cancelAnimationFrame = window.cancelAnimationFrame || window.mozCancelAnimationFrame
  24. || window.webkitCancelAnimationFrame || window.msCancelAnimationFrame;
  25. }
  26. /**
  27. * Creates a new Pixi.js WebGL renderer
  28. * @method create
  29. * @param {object} options
  30. * @return {RenderPixi} A new renderer
  31. * @deprecated
  32. */
  33. RenderPixi.create = function(options) {
  34. Common.warn('RenderPixi.create: Matter.RenderPixi is deprecated (see docs)');
  35. var defaults = {
  36. controller: RenderPixi,
  37. engine: null,
  38. element: null,
  39. frameRequestId: null,
  40. canvas: null,
  41. renderer: null,
  42. container: null,
  43. spriteContainer: null,
  44. pixiOptions: null,
  45. options: {
  46. width: 800,
  47. height: 600,
  48. background: '#fafafa',
  49. wireframeBackground: '#222',
  50. hasBounds: false,
  51. enabled: true,
  52. wireframes: true,
  53. showSleeping: true,
  54. showDebug: false,
  55. showBroadphase: false,
  56. showBounds: false,
  57. showVelocity: false,
  58. showCollisions: false,
  59. showAxes: false,
  60. showPositions: false,
  61. showAngleIndicator: false,
  62. showIds: false,
  63. showShadows: false
  64. }
  65. };
  66. var render = Common.extend(defaults, options),
  67. transparent = !render.options.wireframes && render.options.background === 'transparent';
  68. // init pixi
  69. render.pixiOptions = render.pixiOptions || {
  70. view: render.canvas,
  71. transparent: transparent,
  72. antialias: true,
  73. backgroundColor: options.background
  74. };
  75. render.mouse = options.mouse;
  76. render.engine = options.engine;
  77. render.renderer = render.renderer || new PIXI.WebGLRenderer(render.options.width, render.options.height, render.pixiOptions);
  78. render.container = render.container || new PIXI.Container();
  79. render.spriteContainer = render.spriteContainer || new PIXI.Container();
  80. render.canvas = render.canvas || render.renderer.view;
  81. render.bounds = render.bounds || {
  82. min: {
  83. x: 0,
  84. y: 0
  85. },
  86. max: {
  87. x: render.options.width,
  88. y: render.options.height
  89. }
  90. };
  91. // event listeners
  92. Events.on(render.engine, 'beforeUpdate', function() {
  93. RenderPixi.clear(render);
  94. });
  95. // caches
  96. render.textures = {};
  97. render.sprites = {};
  98. render.primitives = {};
  99. // use a sprite batch for performance
  100. render.container.addChild(render.spriteContainer);
  101. // insert canvas
  102. if (Common.isElement(render.element)) {
  103. render.element.appendChild(render.canvas);
  104. } else {
  105. Common.warn('No "render.element" passed, "render.canvas" was not inserted into document.');
  106. }
  107. // prevent menus on canvas
  108. render.canvas.oncontextmenu = function() { return false; };
  109. render.canvas.onselectstart = function() { return false; };
  110. return render;
  111. };
  112. /**
  113. * Continuously updates the render canvas on the `requestAnimationFrame` event.
  114. * @method run
  115. * @param {render} render
  116. * @deprecated
  117. */
  118. RenderPixi.run = function(render) {
  119. (function loop(time){
  120. render.frameRequestId = _requestAnimationFrame(loop);
  121. RenderPixi.world(render);
  122. })();
  123. };
  124. /**
  125. * Ends execution of `Render.run` on the given `render`, by canceling the animation frame request event loop.
  126. * @method stop
  127. * @param {render} render
  128. * @deprecated
  129. */
  130. RenderPixi.stop = function(render) {
  131. _cancelAnimationFrame(render.frameRequestId);
  132. };
  133. /**
  134. * Clears the scene graph
  135. * @method clear
  136. * @param {RenderPixi} render
  137. * @deprecated
  138. */
  139. RenderPixi.clear = function(render) {
  140. var container = render.container,
  141. spriteContainer = render.spriteContainer;
  142. // clear stage container
  143. while (container.children[0]) {
  144. container.removeChild(container.children[0]);
  145. }
  146. // clear sprite batch
  147. while (spriteContainer.children[0]) {
  148. spriteContainer.removeChild(spriteContainer.children[0]);
  149. }
  150. var bgSprite = render.sprites['bg-0'];
  151. // clear caches
  152. render.textures = {};
  153. render.sprites = {};
  154. render.primitives = {};
  155. // set background sprite
  156. render.sprites['bg-0'] = bgSprite;
  157. if (bgSprite)
  158. container.addChildAt(bgSprite, 0);
  159. // add sprite batch back into container
  160. render.container.addChild(render.spriteContainer);
  161. // reset background state
  162. render.currentBackground = null;
  163. // reset bounds transforms
  164. container.scale.set(1, 1);
  165. container.position.set(0, 0);
  166. };
  167. /**
  168. * Sets the background of the canvas
  169. * @method setBackground
  170. * @param {RenderPixi} render
  171. * @param {string} background
  172. * @deprecated
  173. */
  174. RenderPixi.setBackground = function(render, background) {
  175. if (render.currentBackground !== background) {
  176. var isColor = background.indexOf && background.indexOf('#') !== -1,
  177. bgSprite = render.sprites['bg-0'];
  178. if (isColor) {
  179. // if solid background color
  180. var color = Common.colorToNumber(background);
  181. render.renderer.backgroundColor = color;
  182. // remove background sprite if existing
  183. if (bgSprite)
  184. render.container.removeChild(bgSprite);
  185. } else {
  186. // initialise background sprite if needed
  187. if (!bgSprite) {
  188. var texture = _getTexture(render, background);
  189. bgSprite = render.sprites['bg-0'] = new PIXI.Sprite(texture);
  190. bgSprite.position.x = 0;
  191. bgSprite.position.y = 0;
  192. render.container.addChildAt(bgSprite, 0);
  193. }
  194. }
  195. render.currentBackground = background;
  196. }
  197. };
  198. /**
  199. * Description
  200. * @method world
  201. * @param {engine} engine
  202. * @deprecated
  203. */
  204. RenderPixi.world = function(render) {
  205. var engine = render.engine,
  206. world = engine.world,
  207. renderer = render.renderer,
  208. container = render.container,
  209. options = render.options,
  210. bodies = Composite.allBodies(world),
  211. allConstraints = Composite.allConstraints(world),
  212. constraints = [],
  213. i;
  214. if (options.wireframes) {
  215. RenderPixi.setBackground(render, options.wireframeBackground);
  216. } else {
  217. RenderPixi.setBackground(render, options.background);
  218. }
  219. // handle bounds
  220. var boundsWidth = render.bounds.max.x - render.bounds.min.x,
  221. boundsHeight = render.bounds.max.y - render.bounds.min.y,
  222. boundsScaleX = boundsWidth / render.options.width,
  223. boundsScaleY = boundsHeight / render.options.height;
  224. if (options.hasBounds) {
  225. // Hide bodies that are not in view
  226. for (i = 0; i < bodies.length; i++) {
  227. var body = bodies[i];
  228. body.render.sprite.visible = Bounds.overlaps(body.bounds, render.bounds);
  229. }
  230. // filter out constraints that are not in view
  231. for (i = 0; i < allConstraints.length; i++) {
  232. var constraint = allConstraints[i],
  233. bodyA = constraint.bodyA,
  234. bodyB = constraint.bodyB,
  235. pointAWorld = constraint.pointA,
  236. pointBWorld = constraint.pointB;
  237. if (bodyA) pointAWorld = Vector.add(bodyA.position, constraint.pointA);
  238. if (bodyB) pointBWorld = Vector.add(bodyB.position, constraint.pointB);
  239. if (!pointAWorld || !pointBWorld)
  240. continue;
  241. if (Bounds.contains(render.bounds, pointAWorld) || Bounds.contains(render.bounds, pointBWorld))
  242. constraints.push(constraint);
  243. }
  244. // transform the view
  245. container.scale.set(1 / boundsScaleX, 1 / boundsScaleY);
  246. container.position.set(-render.bounds.min.x * (1 / boundsScaleX), -render.bounds.min.y * (1 / boundsScaleY));
  247. } else {
  248. constraints = allConstraints;
  249. }
  250. for (i = 0; i < bodies.length; i++)
  251. RenderPixi.body(render, bodies[i]);
  252. for (i = 0; i < constraints.length; i++)
  253. RenderPixi.constraint(render, constraints[i]);
  254. renderer.render(container);
  255. };
  256. /**
  257. * Description
  258. * @method constraint
  259. * @param {engine} engine
  260. * @param {constraint} constraint
  261. * @deprecated
  262. */
  263. RenderPixi.constraint = function(render, constraint) {
  264. var engine = render.engine,
  265. bodyA = constraint.bodyA,
  266. bodyB = constraint.bodyB,
  267. pointA = constraint.pointA,
  268. pointB = constraint.pointB,
  269. container = render.container,
  270. constraintRender = constraint.render,
  271. primitiveId = 'c-' + constraint.id,
  272. primitive = render.primitives[primitiveId];
  273. // initialise constraint primitive if not existing
  274. if (!primitive)
  275. primitive = render.primitives[primitiveId] = new PIXI.Graphics();
  276. // don't render if constraint does not have two end points
  277. if (!constraintRender.visible || !constraint.pointA || !constraint.pointB) {
  278. primitive.clear();
  279. return;
  280. }
  281. // add to scene graph if not already there
  282. if (Common.indexOf(container.children, primitive) === -1)
  283. container.addChild(primitive);
  284. // render the constraint on every update, since they can change dynamically
  285. primitive.clear();
  286. primitive.beginFill(0, 0);
  287. primitive.lineStyle(constraintRender.lineWidth, Common.colorToNumber(constraintRender.strokeStyle), 1);
  288. if (bodyA) {
  289. primitive.moveTo(bodyA.position.x + pointA.x, bodyA.position.y + pointA.y);
  290. } else {
  291. primitive.moveTo(pointA.x, pointA.y);
  292. }
  293. if (bodyB) {
  294. primitive.lineTo(bodyB.position.x + pointB.x, bodyB.position.y + pointB.y);
  295. } else {
  296. primitive.lineTo(pointB.x, pointB.y);
  297. }
  298. primitive.endFill();
  299. };
  300. /**
  301. * Description
  302. * @method body
  303. * @param {engine} engine
  304. * @param {body} body
  305. * @deprecated
  306. */
  307. RenderPixi.body = function(render, body) {
  308. var engine = render.engine,
  309. bodyRender = body.render;
  310. if (!bodyRender.visible)
  311. return;
  312. if (bodyRender.sprite && bodyRender.sprite.texture) {
  313. var spriteId = 'b-' + body.id,
  314. sprite = render.sprites[spriteId],
  315. spriteContainer = render.spriteContainer;
  316. // initialise body sprite if not existing
  317. if (!sprite)
  318. sprite = render.sprites[spriteId] = _createBodySprite(render, body);
  319. // add to scene graph if not already there
  320. if (Common.indexOf(spriteContainer.children, sprite) === -1)
  321. spriteContainer.addChild(sprite);
  322. // update body sprite
  323. sprite.position.x = body.position.x;
  324. sprite.position.y = body.position.y;
  325. sprite.rotation = body.angle;
  326. sprite.scale.x = bodyRender.sprite.xScale || 1;
  327. sprite.scale.y = bodyRender.sprite.yScale || 1;
  328. } else {
  329. var primitiveId = 'b-' + body.id,
  330. primitive = render.primitives[primitiveId],
  331. container = render.container;
  332. // initialise body primitive if not existing
  333. if (!primitive) {
  334. primitive = render.primitives[primitiveId] = _createBodyPrimitive(render, body);
  335. primitive.initialAngle = body.angle;
  336. }
  337. // add to scene graph if not already there
  338. if (Common.indexOf(container.children, primitive) === -1)
  339. container.addChild(primitive);
  340. // update body primitive
  341. primitive.position.x = body.position.x;
  342. primitive.position.y = body.position.y;
  343. primitive.rotation = body.angle - primitive.initialAngle;
  344. }
  345. };
  346. /**
  347. * Creates a body sprite
  348. * @method _createBodySprite
  349. * @private
  350. * @param {RenderPixi} render
  351. * @param {body} body
  352. * @return {PIXI.Sprite} sprite
  353. * @deprecated
  354. */
  355. var _createBodySprite = function(render, body) {
  356. var bodyRender = body.render,
  357. texturePath = bodyRender.sprite.texture,
  358. texture = _getTexture(render, texturePath),
  359. sprite = new PIXI.Sprite(texture);
  360. sprite.anchor.x = body.render.sprite.xOffset;
  361. sprite.anchor.y = body.render.sprite.yOffset;
  362. return sprite;
  363. };
  364. /**
  365. * Creates a body primitive
  366. * @method _createBodyPrimitive
  367. * @private
  368. * @param {RenderPixi} render
  369. * @param {body} body
  370. * @return {PIXI.Graphics} graphics
  371. * @deprecated
  372. */
  373. var _createBodyPrimitive = function(render, body) {
  374. var bodyRender = body.render,
  375. options = render.options,
  376. primitive = new PIXI.Graphics(),
  377. fillStyle = Common.colorToNumber(bodyRender.fillStyle),
  378. strokeStyle = Common.colorToNumber(bodyRender.strokeStyle),
  379. strokeStyleIndicator = Common.colorToNumber(bodyRender.strokeStyle),
  380. strokeStyleWireframe = Common.colorToNumber('#bbb'),
  381. strokeStyleWireframeIndicator = Common.colorToNumber('#CD5C5C'),
  382. part;
  383. primitive.clear();
  384. // handle compound parts
  385. for (var k = body.parts.length > 1 ? 1 : 0; k < body.parts.length; k++) {
  386. part = body.parts[k];
  387. if (!options.wireframes) {
  388. primitive.beginFill(fillStyle, 1);
  389. primitive.lineStyle(bodyRender.lineWidth, strokeStyle, 1);
  390. } else {
  391. primitive.beginFill(0, 0);
  392. primitive.lineStyle(1, strokeStyleWireframe, 1);
  393. }
  394. primitive.moveTo(part.vertices[0].x - body.position.x, part.vertices[0].y - body.position.y);
  395. for (var j = 1; j < part.vertices.length; j++) {
  396. primitive.lineTo(part.vertices[j].x - body.position.x, part.vertices[j].y - body.position.y);
  397. }
  398. primitive.lineTo(part.vertices[0].x - body.position.x, part.vertices[0].y - body.position.y);
  399. primitive.endFill();
  400. // angle indicator
  401. if (options.showAngleIndicator || options.showAxes) {
  402. primitive.beginFill(0, 0);
  403. if (options.wireframes) {
  404. primitive.lineStyle(1, strokeStyleWireframeIndicator, 1);
  405. } else {
  406. primitive.lineStyle(1, strokeStyleIndicator);
  407. }
  408. primitive.moveTo(part.position.x - body.position.x, part.position.y - body.position.y);
  409. primitive.lineTo(((part.vertices[0].x + part.vertices[part.vertices.length-1].x) / 2 - body.position.x),
  410. ((part.vertices[0].y + part.vertices[part.vertices.length-1].y) / 2 - body.position.y));
  411. primitive.endFill();
  412. }
  413. }
  414. return primitive;
  415. };
  416. /**
  417. * Gets the requested texture (a PIXI.Texture) via its path
  418. * @method _getTexture
  419. * @private
  420. * @param {RenderPixi} render
  421. * @param {string} imagePath
  422. * @return {PIXI.Texture} texture
  423. * @deprecated
  424. */
  425. var _getTexture = function(render, imagePath) {
  426. var texture = render.textures[imagePath];
  427. if (!texture)
  428. texture = render.textures[imagePath] = PIXI.Texture.fromImage(imagePath);
  429. return texture;
  430. };
  431. })();
0.16.0