~neon/kolf/master

« back to all changes in this revision

Viewing changes to shape.cpp

  • Committer: Stefan Majewsky
  • Date: 2010-10-31 23:23:16 UTC
  • Revision ID: git-v1:45f6fdbcc5733b0daa25631ea13b5b2f2d86f20e
Create a Box2D world, and attach Box2D bodies to all CanvasItems.

This is unfortunately a very large patch, because it touches everything
in the CanvasItem hierarchy, the ItemFactory, the KolfGame and the
shapes at once. All these objects are closely related through Box2D's
object hierarchy (world -> bodies -> fixtures -> shapes), so these
changes can hardly be split up further.

svn path=/trunk/KDE/kdegames/kolf/; revision=1191711

Show diffs side-by-side

added added

removed removed

Lines of Context:
21
21
#include "overlay.h"
22
22
 
23
23
#include <QtCore/qmath.h>
 
24
#include <Box2D/Collision/Shapes/b2CircleShape.h>
 
25
#include <Box2D/Collision/Shapes/b2EdgeShape.h>
 
26
#include <Box2D/Collision/Shapes/b2PolygonShape.h>
 
27
#include <Box2D/Dynamics/b2Fixture.h>
 
28
 
 
29
static inline b2Vec2 toB2Vec2(const QPointF& p)
 
30
{
 
31
        return b2Vec2(p.x(), p.y());
 
32
}
24
33
 
25
34
//BEGIN Kolf::Shape
26
35
 
27
36
const qreal Kolf::Shape::ActivationOutlinePadding = 5;
28
37
 
29
38
Kolf::Shape::Shape()
30
 
        : m_citem(0)
 
39
        : m_traits(Kolf::Shape::ParticipatesInPhysicalSimulation)
 
40
        , m_citem(0)
 
41
        , m_body(0)
 
42
        , m_fixtureDef(new b2FixtureDef)
 
43
        , m_fixture(0)
 
44
        , m_shape(0)
31
45
{
 
46
        m_fixtureDef->density = 1;
 
47
        m_fixtureDef->restitution = 0.8;
 
48
        m_fixtureDef->friction = 0;
 
49
        m_fixtureDef->userData = this;
32
50
}
33
51
 
34
52
Kolf::Shape::~Shape()
35
53
{
 
54
        delete m_fixtureDef;
 
55
        updateFixture(0); //clear fixture and shape
36
56
}
37
57
 
38
58
QPainterPath Kolf::Shape::activationOutline() const
50
70
        if (m_citem)
51
71
                return false;
52
72
        m_citem = item;
 
73
        m_body = item->m_body;
 
74
        updateFixture(createShape());
53
75
        return true;
54
76
}
55
77
 
 
78
Kolf::Shape::Traits Kolf::Shape::traits() const
 
79
{
 
80
        return m_traits;
 
81
}
 
82
 
 
83
void Kolf::Shape::setTraits(Kolf::Shape::Traits traits)
 
84
{
 
85
        if (m_traits == traits)
 
86
                return;
 
87
        m_traits = traits;
 
88
        updateFixture(createShape());
 
89
}
 
90
 
 
91
void Kolf::Shape::updateFixture(b2Shape* newShape)
 
92
{
 
93
        if (!m_body)
 
94
                return;
 
95
        //destroy old fixture
 
96
        if (m_fixture)
 
97
                m_body->DestroyFixture(m_fixture);
 
98
        delete m_shape;
 
99
        m_shape = 0;
 
100
        //create new fixture
 
101
        if (m_traits & Kolf::Shape::CollisionDetectionFlag)
 
102
        {
 
103
                m_shape = newShape;
 
104
                if (m_shape)
 
105
                {
 
106
                        b2FixtureDef fixtureDef = *m_fixtureDef;
 
107
                        fixtureDef.shape = m_shape;
 
108
                        fixtureDef.isSensor = !(m_traits & Kolf::Shape::PhysicalSimulationFlag);
 
109
                        m_fixture = m_body->CreateFixture(&fixtureDef);
 
110
                }
 
111
        }
 
112
        else
 
113
                delete newShape; //TODO: inefficient
 
114
}
 
115
 
56
116
void Kolf::Shape::update()
57
117
{
 
118
        updateFixture(createShape());
58
119
        m_interactionOutline = m_activationOutline = QPainterPath();
59
120
        createOutlines(m_activationOutline, m_interactionOutline);
 
121
        //propagate update to overlays
60
122
        if (m_citem)
61
123
        {
62
124
                Kolf::Overlay* overlay = m_citem->overlay(false);
88
150
        }
89
151
}
90
152
 
 
153
b2Shape* Kolf::EllipseShape::createShape()
 
154
{
 
155
        const b2Vec2 c = toB2Vec2(m_rect.center());
 
156
        const qreal rx = m_rect.width() / 2, ry = m_rect.height() / 2;
 
157
        if (rx == ry)
 
158
        {
 
159
                //use circle shape when possible because it's cheaper and exact
 
160
                b2CircleShape* shape = new b2CircleShape;
 
161
                shape->m_p = c;
 
162
                shape->m_radius = rx;
 
163
                return shape;
 
164
        }
 
165
        else
 
166
        {
 
167
                //elliptical shape is not pre-made in Box2D, so create a polygon instead
 
168
                b2PolygonShape* shape = new b2PolygonShape;
 
169
                static const int N = 20;
 
170
                //increase N if the approximation turns out to be too bad
 
171
                //TODO: calculate the (cos, sin) pairs only once
 
172
                b2Vec2 vertices[N];
 
173
                static const qreal angleStep = 2 * M_PI / N;
 
174
                for (int i = 0; i < N; ++i)
 
175
                {
 
176
                        const qreal angle = -i * angleStep; //CCW order as required by Box2D
 
177
                        vertices[i].x = c.x + rx * cos(angle);
 
178
                        vertices[i].y = c.y + ry * sin(angle);
 
179
                }
 
180
                shape->Set(vertices, N);
 
181
                return shape;
 
182
        }
 
183
}
 
184
 
91
185
void Kolf::EllipseShape::createOutlines(QPainterPath& activationOutline, QPainterPath& interactionOutline)
92
186
{
93
187
        interactionOutline.addEllipse(m_rect);
118
212
        }
119
213
}
120
214
 
 
215
b2Shape* Kolf::RectShape::createShape()
 
216
{
 
217
        b2PolygonShape* shape = new b2PolygonShape;
 
218
        shape->SetAsBox(
 
219
                m_rect.width() / 2, m_rect.height() / 2,
 
220
                toB2Vec2(m_rect.center()),
 
221
                0 //intrinsic rotation angle
 
222
        );
 
223
        return shape;
 
224
}
 
225
 
121
226
void Kolf::RectShape::createOutlines(QPainterPath& activationOutline, QPainterPath& interactionOutline)
122
227
{
123
228
        interactionOutline.addRect(m_rect);
148
253
        }
149
254
}
150
255
 
 
256
b2Shape* Kolf::LineShape::createShape()
 
257
{
 
258
        b2EdgeShape* shape = new b2EdgeShape;
 
259
        shape->Set(toB2Vec2(m_line.p1()), toB2Vec2(m_line.p2()));
 
260
        return shape;
 
261
}
 
262
 
151
263
void Kolf::LineShape::createOutlines(QPainterPath& activationOutline, QPainterPath& interactionOutline)
152
264
{
153
265
        const QPointF extent = m_line.p2() - m_line.p1();