Do fuzzy comparisions to avoid small inaccuracies causing repaints
[qmlarcade:qmlarcade.git] / plugins / box2d / box2dbody.cpp
1 /*
2  * Box2D QML plugin
3  * Copyright (C) 2010 Nokia Corporation
4  *
5  * This file is part of the QmlArcade.
6  *
7  * QmlArcade is free software; you can redistribute it and/or modify it
8  * under the terms of the GNU General Public License as published by the Free
9  * Software Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * QmlArcade is distributed in the hope that it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
15  * more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with QmlArcade.  If not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include "box2dbody.h"
22
23 #include "box2dworld.h"
24
25 #include <Box2D.h>
26 #include <cmath>
27
28 static const float scaleRatio = 32.0f; // 32 pixels in one meter
29
30 Box2DBody::Box2DBody(QDeclarativeItem *parent) :
31     QDeclarativeItem(parent),
32     mBody(0),
33     mFixed(false)
34 {
35 }
36
37 Box2DBody::~Box2DBody()
38 {
39     if (Box2DWorld *world = qobject_cast<Box2DWorld*>(parent()))
40         world->unregisterBody(this);
41 }
42
43 void Box2DBody::componentComplete()
44 {
45     if (Box2DWorld *world = qobject_cast<Box2DWorld*>(parent()))
46         world->registerBody(this);
47     else
48         qWarning() << "Warning: Body should have World as parent";
49 }
50
51 void Box2DBody::initialize(b2World *world)
52 {
53     b2BodyDef bodyDef;
54     bodyDef.position.Set((x() + width() / 2) / scaleRatio,
55                          -(y() + height() / 2) / scaleRatio);
56     bodyDef.angle = -(rotation() * (2 * M_PI)) / 360.0;
57
58     mBody = world->CreateBody(&bodyDef);
59
60     // TODO: Create a shape for each child shape
61     b2PolygonDef shapeDef;
62     shapeDef.SetAsBox(width() / 2.0f / scaleRatio,
63                       height() / 2.0f / scaleRatio);
64     shapeDef.density = 1.0f;    // TODO: Make a property for it in Box2DShape
65     shapeDef.friction = 0.3f;   // TODO: Make a property for it in Box2DShape
66     shapeDef.restitution = 0.5f;
67     mBody->CreateShape(&shapeDef);
68
69     if (!mFixed)
70         mBody->SetMassFromShapes(); // TODO: Make a property for it in Box2DBody
71 }
72
73 /**
74  * Synchronizes the state of this body with the internal Box2D state.
75  */
76 void Box2DBody::synchronize()
77 {
78     Q_ASSERT(mBody);
79     const b2Vec2 position = mBody->GetPosition();
80     const float32 angle = mBody->GetAngle();
81
82     const qreal newX = position.x * scaleRatio - width() / 2;
83     const qreal newY = -position.y * scaleRatio - height() / 2;
84     const qreal newRotation = -(angle * 360.0) / (2 * M_PI);
85
86     // Do fuzzy comparisions to avoid small inaccuracies causing repaints
87     if (!qFuzzyCompare(x(), newX) || !qFuzzyCompare(y(), newY))
88         setPos(newX, newY);
89     if (!qFuzzyCompare(rotation(), newRotation))
90         setRotation(newRotation);
91 }
92
93 void Box2DBody::cleanup(b2World *world)
94 {
95     world->DestroyBody(mBody);
96 }