From 433a1f9b4e34b479fc9089afeb5c340f5c13cb91 Mon Sep 17 00:00:00 2001
From: liabru <liambrum@gmail.com>
Date: Thu, 13 Mar 2014 00:21:31 +0000
Subject: [PATCH] bodies now have a 'render' object property sprites
 implemented backgrounds implemented

---
 src/body/Body.js      | 18 +++++---
 src/factory/Bodies.js | 18 +++++---
 src/render/Render.js  | 99 +++++++++++++++++++++++++++++--------------
 3 files changed, 90 insertions(+), 45 deletions(-)

diff --git a/src/body/Body.js b/src/body/Body.js
index a8a8f2b..94997eb 100644
--- a/src/body/Body.js
+++ b/src/body/Body.js
@@ -38,11 +38,14 @@ var Body = {};
             restitution: 0,
             friction: 0.1,
             frictionAir: 0.01,
-            path: 'L 0 0 L 40 0 L 40 40 L 0 40',
-            fillStyle: options.isStatic ? '#eeeeee' : Common.choose(['#556270', '#4ECDC4', '#C7F464', '#FF6B6B', '#C44D58']),
-            lineWidth: 1.5,
             groupId: 0,
-            slop: 0.05
+            slop: 0.05,
+            render: {
+                visible: true,
+                sprite: null,
+                path: 'L 0 0 L 40 0 L 40 40 L 0 40',
+                lineWidth: 1.5
+            }
         };
 
         var body = Common.extend(defaults, options);
@@ -77,7 +80,7 @@ var Body = {};
      */
     Body.updateProperties = function(body) {
         // calculated properties
-        body.vertices = body.vertices || Vertices.fromPath(body.path);
+        body.vertices = body.vertices || Vertices.fromPath(body.render.path);
         body.axes = body.axes || Axes.fromVertices(body.vertices);
         body.area = Vertices.area(body.vertices);
         body.bounds = Bounds.create(body.vertices);
@@ -87,7 +90,8 @@ var Body = {};
         body.inverseInertia = 1 / body.inertia;
         body.positionPrev = body.positionPrev || { x: body.position.x, y: body.position.y };
         body.anglePrev = body.anglePrev || body.angle;
-        body.strokeStyle = body.strokeStyle || Common.shadeColor(body.fillStyle, -20);
+        body.render.fillStyle = body.render.fillStyle || (body.isStatic ? '#eeeeee' : Common.choose(['#556270', '#4ECDC4', '#C7F464', '#FF6B6B', '#C44D58']));
+        body.render.strokeStyle = body.render.strokeStyle || Common.shadeColor(body.render.fillStyle, -20);
 
         // update geometry
         Vertices.create(body.vertices, body);
@@ -103,7 +107,7 @@ var Body = {};
             body.friction = 1;
             body.mass = body.inertia = body.density = Infinity;
             body.inverseMass = body.inverseInertia = 0;
-            body.lineWidth = 1;
+            body.render.lineWidth = 1;
         }
 
         Sleeping.set(body, body.isSleeping);
diff --git a/src/factory/Bodies.js b/src/factory/Bodies.js
index 786ef89..46bbd61 100644
--- a/src/factory/Bodies.js
+++ b/src/factory/Bodies.js
@@ -25,9 +25,11 @@ var Bodies = {};
         options = options || {};
 
         var rectangle = { 
-                position: { x: x, y: y },
+            position: { x: x, y: y },
+            render: {
                 path: 'L 0 0 L ' + width + ' 0 L ' + width + ' ' + height + ' L 0 ' + height
-            };
+            }
+        };
 
         return Body.create(Common.extend({}, rectangle, options));
     };
@@ -54,9 +56,11 @@ var Bodies = {};
             x3 = x2 + x1;
 
         var trapezoid = { 
-                position: { x: x, y: y },
+            position: { x: x, y: y },
+            render: {
                 path: 'L 0 0 L ' + x1 + ' ' + (-height) + ' L ' + x2 + ' ' + (-height) + ' L ' + x3 + ' 0'
-            };
+            }
+        };
 
         return Body.create(Common.extend({}, trapezoid, options));
     };
@@ -118,9 +122,11 @@ var Bodies = {};
         }
 
         var polygon = { 
-                position: { x: x, y: y },
+            position: { x: x, y: y },
+            render: {
                 path: path
-            };
+            }
+        };
 
         return Body.create(Common.extend({}, polygon, options));
     };
diff --git a/src/render/Render.js b/src/render/Render.js
index 63d09a9..84f9aac 100644
--- a/src/render/Render.js
+++ b/src/render/Render.js
@@ -47,9 +47,25 @@ var Render = {};
         render.canvas = render.canvas || _createCanvas(render.options.width, render.options.height);
         render.context = render.canvas.getContext('2d');
 
+        Render.setBackground(render, render.options.background);
+
         return render;
     };
 
+    /**
+     * Sets the background CSS property of the canvas 
+     * @method setBackground
+     * @param {render} render
+     * @param {string} background
+     */
+    Render.setBackground = function(render, background) {
+        if (render.currentBackground !== background) {
+            render.canvas.style.background = background;
+            render.canvas.style.backgroundSize = "contain";
+            render.currentBackground = background;
+        }
+    };
+
     /**
      * Description
      * @method world
@@ -64,12 +80,16 @@ var Render = {};
             i;
 
         if (options.wireframes) {
-            context.fillStyle = options.wireframeBackground;
+            Render.setBackground(render, options.wireframeBackground);
         } else {
-            context.fillStyle = options.background;
+            Render.setBackground(render, options.background);
         }
-        
+
+        // clear the canvas with a transparent fill, to allow the canvas background to show
+        context.globalCompositeOperation = 'source-in';
+        context.fillStyle = "transparent";
         context.fillRect(0, 0, canvas.width, canvas.height);
+        context.globalCompositeOperation = 'source-over';
 
         if (options.showShadows && !options.wireframes)
             for (i = 0; i < world.bodies.length; i++)
@@ -242,34 +262,49 @@ var Render = {};
             c.stroke();
         }
 
-        // body polygon
-        if (body.circleRadius) {
-            c.beginPath();
-            c.arc(body.position.x, body.position.y, body.circleRadius, 0, 2 * Math.PI);
-            c.closePath();
-        } else {
-            c.beginPath();
-            c.moveTo(body.vertices[0].x, body.vertices[0].y);
-            for (var j = 1; j < body.vertices.length; j++) {
-                c.lineTo(body.vertices[j].x, body.vertices[j].y);
-            }
-            c.closePath();
-        }
+        // draw body
+        if (body.render.visible) {
+            if (body.render.sprite && !options.wireframes) {
+                // body sprite
+                var sprite = body.render.sprite;
+                c.save();
+                c.webkitImageSmoothingEnabled = true;
+                c.translate(body.position.x, body.position.y); 
+                c.rotate(body.angle);
+                c.drawImage(sprite.image, sprite.width * -0.5 * sprite.xScale, sprite.height * -0.5 * sprite.yScale, 
+                            sprite.width * sprite.xScale, sprite.height * sprite.yScale);
+                c.restore();
+            } else {
+                // body polygon
+                if (body.circleRadius) {
+                    c.beginPath();
+                    c.arc(body.position.x, body.position.y, body.circleRadius, 0, 2 * Math.PI);
+                    c.closePath();
+                } else {
+                    c.beginPath();
+                    c.moveTo(body.vertices[0].x, body.vertices[0].y);
+                    for (var j = 1; j < body.vertices.length; j++) {
+                        c.lineTo(body.vertices[j].x, body.vertices[j].y);
+                    }
+                    c.closePath();
+                }
 
-        if (!options.wireframes) {
-            c.fillStyle = body.fillStyle;
-            if (options.showSleeping && body.isSleeping)
-                c.fillStyle = Common.shadeColor(body.fillStyle, 50);
-            c.lineWidth = body.lineWidth;
-            c.strokeStyle = body.strokeStyle;
-            c.fill();
-            c.stroke();
-        } else {
-            c.lineWidth = 1;
-            c.strokeStyle = '#bbb';
-            if (options.showSleeping && body.isSleeping)
-                c.strokeStyle = 'rgba(255,255,255,0.2)';
-            c.stroke();
+                if (!options.wireframes) {
+                    c.fillStyle = body.render.fillStyle;
+                    if (options.showSleeping && body.isSleeping)
+                        c.fillStyle = Common.shadeColor(body.render.fillStyle, 50);
+                    c.lineWidth = body.render.lineWidth;
+                    c.strokeStyle = body.render.strokeStyle;
+                    c.fill();
+                    c.stroke();
+                } else {
+                    c.lineWidth = 1;
+                    c.strokeStyle = '#bbb';
+                    if (options.showSleeping && body.isSleeping)
+                        c.strokeStyle = 'rgba(255,255,255,0.2)';
+                    c.stroke();
+                }
+            }
         }
 
         // angle indicator
@@ -282,7 +317,7 @@ var Render = {};
             if (options.wireframes) {
                 c.strokeStyle = 'indianred';
             } else {
-                c.strokeStyle = body.strokeStyle;
+                c.strokeStyle = body.render.strokeStyle;
             }
             c.stroke();
         }
@@ -298,7 +333,7 @@ var Render = {};
                 if (options.wireframes) {
                     c.strokeStyle = 'indianred';
                 } else {
-                    c.strokeStyle = body.strokeStyle;
+                    c.strokeStyle = body.render.strokeStyle;
                 }
                 c.stroke();
             }