diff --git a/box2d.pro b/box2d.pro index f1ee76fd..42429d2d 100644 --- a/box2d.pro +++ b/box2d.pro @@ -16,9 +16,11 @@ INSTALLS += target qmldir SOURCES += box2dplugin.cpp \ box2dworld.cpp \ - box2dbody.cpp + box2dbody.cpp \ + box2ddebugdraw.cpp HEADERS += \ box2dplugin.h \ box2dworld.h \ - box2dbody.h + box2dbody.h \ + box2ddebugdraw.h diff --git a/box2dbody.cpp b/box2dbody.cpp index 1ace14dc..5f62664c 100644 --- a/box2dbody.cpp +++ b/box2dbody.cpp @@ -25,8 +25,6 @@ #include #include -static const float scaleRatio = 32.0f; // 32 pixels in one meter - Box2DBody::Box2DBody(QDeclarativeItem *parent) : QDeclarativeItem(parent), mBody(0), diff --git a/box2ddebugdraw.cpp b/box2ddebugdraw.cpp new file mode 100644 index 00000000..45ce0d3f --- /dev/null +++ b/box2ddebugdraw.cpp @@ -0,0 +1,185 @@ +/* + * Box2D QML plugin + * Copyright (C) 2010 Nokia Corporation + * + * This file is part of the Box2D QML plugin. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; If not, see . + */ + +#include "box2ddebugdraw.h" + +#include "box2dworld.h" + +#include + +#include + +class DebugDraw : public b2DebugDraw +{ +public: + DebugDraw(QPainter *painter, Box2DWorld *world); + + void draw(); + + void DrawPolygon(const b2Vec2 *vertices, int32 vertexCount, + const b2Color &color); + void DrawSolidPolygon(const b2Vec2 *vertices, int32 vertexCount, + const b2Color &color); + void DrawCircle(const b2Vec2 ¢er, float32 radius, + const b2Color &color); + void DrawSolidCircle(const b2Vec2 ¢er, float32 radius, + const b2Vec2 &axis, const b2Color &color); + void DrawSegment(const b2Vec2 &p1, const b2Vec2 &p2, + const b2Color &color); + void DrawTransform(const b2Transform &xf); + +private: + QPainter *mP; + b2World *mWorld; +}; + +DebugDraw::DebugDraw(QPainter *painter, Box2DWorld *world) + : mP(painter) + , mWorld(world->world()) +{ + SetFlags(e_shapeBit | + e_jointBit | + e_aabbBit | + e_pairBit | + e_centerOfMassBit); +} + +void DebugDraw::draw() +{ + mWorld->SetDebugDraw(this); + mWorld->DrawDebugData(); + mWorld->SetDebugDraw(0); +} + +static QPointF toQPointF(const b2Vec2 &vec) +{ + return QPointF(vec.x * scaleRatio, + -vec.y * scaleRatio); +} + +static QColor toQColor(const b2Color &color) +{ + return QColor(color.r * 255, + color.g * 255, + color.b * 255); +} + +static QPolygonF toQPolygonF(const b2Vec2 *vertices, int32 vertexCount) +{ + QPolygonF polygon; + polygon.reserve(vertexCount); + + for (int i = 0; i < vertexCount; ++i) + polygon.append(toQPointF(vertices[i])); + + return polygon; +} + +void DebugDraw::DrawPolygon(const b2Vec2 *vertices, int32 vertexCount, + const b2Color &color) +{ + mP->setPen(toQColor(color)); + mP->setBrush(Qt::NoBrush); + mP->drawPolygon(toQPolygonF(vertices, vertexCount)); +} + +void DebugDraw::DrawSolidPolygon(const b2Vec2 *vertices, int32 vertexCount, + const b2Color &color) +{ + mP->setPen(Qt::NoPen); + mP->setBrush(toQColor(color)); + mP->drawPolygon(toQPolygonF(vertices, vertexCount)); +} + +void DebugDraw::DrawCircle(const b2Vec2 ¢er, float32 radius, + const b2Color &color) +{ + mP->setPen(toQColor(color)); + mP->setBrush(Qt::NoBrush); + mP->drawEllipse(toQPointF(center), + radius * scaleRatio, + radius * scaleRatio); +} + +void DebugDraw::DrawSolidCircle(const b2Vec2 ¢er, float32 radius, + const b2Vec2 &axis, const b2Color &color) +{ + Q_UNUSED(axis) + + mP->setPen(Qt::NoPen); + mP->setBrush(toQColor(color)); + mP->drawEllipse(toQPointF(center), + radius * scaleRatio, + radius * scaleRatio); +} + +void DebugDraw::DrawSegment(const b2Vec2 &p1, const b2Vec2 &p2, + const b2Color &color) +{ + mP->setPen(toQColor(color)); + mP->drawLine(toQPointF(p1), toQPointF(p2)); +} + +void DebugDraw::DrawTransform(const b2Transform &xf) +{ + Q_UNUSED(xf) + // TODO: Not sure how to draw transforms +} + + +Box2DDebugDraw::Box2DDebugDraw(QDeclarativeItem *parent) : + QDeclarativeItem(parent), + mWorld(0) +{ + setFlag(QGraphicsItem::ItemHasNoContents, false); +} + +void Box2DDebugDraw::setWorld(Box2DWorld *world) +{ + if (mWorld == world) + return; + + if (mWorld) + mWorld->disconnect(this); + + mWorld = world; + + if (mWorld) + connect(mWorld, SIGNAL(stepped()), SLOT(onWorldStepped())); +} + +void Box2DDebugDraw::paint(QPainter *p, const QStyleOptionGraphicsItem *, + QWidget *) +{ + if (!mWorld) + return; + + // Darken the view to make the debug draw stand out more + p->fillRect(0, 0, width(), height(), QColor(0, 0, 0, 128)); + + DebugDraw debugDraw(p, mWorld); + debugDraw.draw(); +} + +void Box2DDebugDraw::onWorldStepped() +{ + if (isVisible() && opacity() > 0) + update(); +} diff --git a/box2ddebugdraw.h b/box2ddebugdraw.h new file mode 100644 index 00000000..a8558687 --- /dev/null +++ b/box2ddebugdraw.h @@ -0,0 +1,49 @@ +/* + * Box2D QML plugin + * Copyright (C) 2010 Nokia Corporation + * + * This file is part of the Box2D QML plugin. + * + * This library is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation; either version 2.1 of the License, or (at + * your option) any later version. + * + * This library is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; If not, see . + */ + +#ifndef BOX2DDEBUGDRAW_H +#define BOX2DDEBUGDRAW_H + +#include + +class Box2DWorld; + +class Box2DDebugDraw : public QDeclarativeItem +{ + Q_OBJECT + + Q_PROPERTY(Box2DWorld *world READ world WRITE setWorld) + +public: + explicit Box2DDebugDraw(QDeclarativeItem *parent = 0); + + Box2DWorld *world() const { return mWorld; } + void setWorld(Box2DWorld *world); + + void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *); + +private slots: + void onWorldStepped(); + +private: + Box2DWorld *mWorld; +}; + +#endif // BOX2DDEBUGDRAW_H diff --git a/box2dplugin.cpp b/box2dplugin.cpp index 4ec5290b..94d9bc43 100644 --- a/box2dplugin.cpp +++ b/box2dplugin.cpp @@ -22,6 +22,7 @@ #include "box2dworld.h" #include "box2dbody.h" +#include "box2ddebugdraw.h" Box2DPlugin::Box2DPlugin(QObject *parent) : QDeclarativeExtensionPlugin(parent) @@ -32,6 +33,7 @@ void Box2DPlugin::registerTypes(const char *uri) { qmlRegisterType(uri, 2, 0, "World"); qmlRegisterType(uri, 2, 0, "Body"); + qmlRegisterType(uri, 2, 0, "DebugDraw"); } Q_EXPORT_PLUGIN2(Box2DPlugin, Box2DPlugin) diff --git a/box2dworld.cpp b/box2dworld.cpp index defdc452..96b206f1 100644 --- a/box2dworld.cpp +++ b/box2dworld.cpp @@ -97,6 +97,7 @@ void Box2DWorld::timerEvent(QTimerEvent *event) mWorld->ClearForces(); foreach (Box2DBody *body, mBodies) body->synchronize(); + emit stepped(); } QDeclarativeItem::timerEvent(event); } diff --git a/box2dworld.h b/box2dworld.h index 365216fe..2b06bc66 100644 --- a/box2dworld.h +++ b/box2dworld.h @@ -28,6 +28,10 @@ class Box2DBody; class b2World; +// TODO: Maybe turn this into a property of the world, though it can't be +// changed dynamically. +static const float scaleRatio = 32.0f; // 32 pixels in one meter + /** * Wrapper class around a Box2D world. */ @@ -86,8 +90,11 @@ class Box2DWorld : public QDeclarativeItem void registerBody(Box2DBody *body); void unregisterBody(Box2DBody *body); + b2World *world() const { return mWorld; } + signals: void gravityChanged(); + void stepped(); protected: void timerEvent(QTimerEvent *); diff --git a/examples/boxes/boxes.qml b/examples/boxes/boxes.qml index 11158bdf..48b88d63 100644 --- a/examples/boxes/boxes.qml +++ b/examples/boxes/boxes.qml @@ -46,6 +46,19 @@ Image { anchors { left: parent.right; bottom: ground.top; top: ceiling.bottom } bodyType: Body.Static } + + DebugDraw { + id: debugDraw + world: world + anchors.fill: world + opacity: 0.75 + visible: false + } + MouseArea { + id: debugMouseArea + anchors.fill: world + onPressed: debugDraw.visible = !debugDraw.visible + } } Accelerometer {