File indexing completed on 2024-04-21 14:43:26

0001 /*
0002  * box2dworld.h
0003  * Copyright (c) 2010 Thorbjørn Lindeijer <thorbjorn@lindeijer.nl>
0004  * Copyright (c) 2011 Joonas Erkinheimo <joonas.erkinheimo@nokia.com>
0005  * Copyright (c) 2012 Adriano Rezende <atdrez@gmail.com>
0006  *
0007  * This file is part of the Box2D QML plugin.
0008  *
0009  * This software is provided 'as-is', without any express or implied warranty.
0010  * In no event will the authors be held liable for any damages arising from
0011  * the use of this software.
0012  *
0013  * Permission is granted to anyone to use this software for any purpose,
0014  * including commercial applications, and to alter it and redistribute it
0015  * freely, subject to the following restrictions:
0016  *
0017  * 1. The origin of this software must not be misrepresented; you must not
0018  *    claim that you wrote the original software. If you use this software in
0019  *    a product, an acknowledgment in the product documentation would be
0020  *    appreciated but is not required.
0021  *
0022  * 2. Altered source versions must be plainly marked as such, and must not be
0023  *    misrepresented as being the original software.
0024  *
0025  * 3. This notice may not be removed or altered from any source distribution.
0026  */
0027 
0028 #ifndef BOX2DWORLD_H
0029 #define BOX2DWORLD_H
0030 
0031 #include <QAbstractAnimation>
0032 #include <QQuickItem>
0033 
0034 #include <Box2D.h>
0035 
0036 class Box2DContact;
0037 class Box2DFixture;
0038 class Box2DJoint;
0039 class Box2DWorld;
0040 class Box2DRayCast;
0041 class ContactListener;
0042 class StepDriver;
0043 
0044 /**
0045  * Small utility class to synchronize the stepping with the framerate.
0046  */
0047 class StepDriver : public QAbstractAnimation
0048 {
0049     Q_OBJECT
0050 
0051 public:
0052     explicit StepDriver(Box2DWorld *world);
0053 
0054     int duration() const;
0055 
0056 protected:
0057     void updateCurrentTime(int);
0058 
0059 private:
0060     Box2DWorld *mWorld;
0061 };
0062 
0063 
0064 /**
0065  * A property group for getting profiling data.
0066  */
0067 class Box2DProfile : public QObject
0068 {
0069     Q_OBJECT
0070 
0071     Q_PROPERTY(float step READ step CONSTANT)
0072     Q_PROPERTY(float collide READ collide CONSTANT)
0073     Q_PROPERTY(float solve READ solve CONSTANT)
0074     Q_PROPERTY(float solveInit READ solveInit CONSTANT)
0075     Q_PROPERTY(float solveVelocity READ solveVelocity CONSTANT)
0076     Q_PROPERTY(float solvePosition READ solvePosition CONSTANT)
0077     Q_PROPERTY(float broadphase READ broadphase CONSTANT)
0078     Q_PROPERTY(float solveTOI READ solveTOI CONSTANT)
0079     Q_PROPERTY(float synchronize READ synchronize CONSTANT)
0080     Q_PROPERTY(float emitSignals READ emitSignals CONSTANT)
0081 
0082 public:
0083     explicit Box2DProfile(b2World *world, QObject *parent = 0)
0084         : QObject(parent)
0085         , mWorld(world)
0086     {}
0087 
0088     float step() const;
0089     float collide() const;
0090     float solve() const;
0091     float solveInit() const;
0092     float solveVelocity() const;
0093     float solvePosition() const;
0094     float broadphase() const;
0095     float solveTOI() const;
0096     float synchronize() const;
0097     float emitSignals() const;
0098 
0099 private:
0100     friend class Box2DWorld;
0101 
0102     b2World *mWorld;
0103     float mSynchronize;
0104     float mEmitSignals;
0105 };
0106 
0107 
0108 /**
0109  * Wrapper class around a Box2D world.
0110  */
0111 class Box2DWorld : public QObject, public QQmlParserStatus, b2DestructionListener
0112 {
0113     Q_OBJECT
0114 
0115     Q_PROPERTY(bool running READ isRunning WRITE setRunning NOTIFY runningChanged)
0116     Q_PROPERTY(float timeStep READ timeStep WRITE setTimeStep NOTIFY timeStepChanged)
0117     Q_PROPERTY(int velocityIterations READ velocityIterations WRITE setVelocityIterations NOTIFY velocityIterationsChanged)
0118     Q_PROPERTY(int positionIterations READ positionIterations WRITE setPositionIterations NOTIFY positionIterationsChanged)
0119     Q_PROPERTY(QPointF gravity READ gravity WRITE setGravity NOTIFY gravityChanged)
0120     Q_PROPERTY(bool autoClearForces READ autoClearForces WRITE setAutoClearForces NOTIFY autoClearForcesChanged)
0121     Q_PROPERTY(Box2DProfile *profile READ profile NOTIFY stepped)
0122     Q_PROPERTY(float pixelsPerMeter READ pixelsPerMeter WRITE setPixelsPerMeter NOTIFY pixelsPerMeterChanged)
0123     Q_PROPERTY(bool enableContactEvents READ enableContactEvents WRITE setEnableContactEvents NOTIFY enableContactEventsChanged)
0124 
0125     Q_INTERFACES(QQmlParserStatus)
0126 
0127 public:
0128     explicit Box2DWorld(QObject *parent = 0);
0129     ~Box2DWorld();
0130 
0131     float timeStep() const;
0132     void setTimeStep(float timeStep);
0133 
0134     bool isRunning() const;
0135     void setRunning(bool running);
0136 
0137     int velocityIterations() const;
0138     void setVelocityIterations(int iterations);
0139 
0140     int positionIterations() const;
0141     void setPositionIterations(int iterations);
0142 
0143     QPointF gravity() const;
0144     void setGravity(const QPointF &gravity);
0145 
0146     bool autoClearForces() const;
0147     void setAutoClearForces(bool autoClearForces);
0148 
0149     Box2DProfile *profile() const;
0150 
0151     bool enableContactEvents() const;
0152     void setEnableContactEvents(bool enableContactEvents);
0153 
0154     float pixelsPerMeter() const;
0155     void setPixelsPerMeter(float pixelsPerMeter);
0156 
0157     float metersPerPixel() const;
0158     float pixelsPerMeterY() const;
0159     float metersPerPixelY() const;
0160 
0161     float toPixels(float length) const;
0162     float toMeters(float length) const;
0163 
0164     QPointF toPixels(const b2Vec2 &vec) const;
0165     b2Vec2 toMeters(const QPointF &point) const;
0166 
0167     bool isSynchronizing() const;
0168 
0169     void classBegin();
0170     void componentComplete();
0171 
0172     b2World &world();
0173 
0174     // b2DestructionListener interface
0175     void SayGoodbye(b2Joint *joint);
0176     void SayGoodbye(b2Fixture *fixture);
0177 
0178     Q_INVOKABLE void step();
0179     Q_INVOKABLE void clearForces();
0180     Q_INVOKABLE void rayCast(Box2DRayCast *rayCast,
0181                              const QPointF &point1,
0182                              const QPointF &point2);
0183     static Box2DWorld * defaultWorld();
0184 
0185 signals:
0186     void preSolve(Box2DContact * contact);
0187     void postSolve(Box2DContact * contact);
0188 
0189     void timeStepChanged();
0190     void velocityIterationsChanged();
0191     void positionIterationsChanged();
0192     void gravityChanged();
0193     void autoClearForcesChanged();
0194     void runningChanged();
0195     void stepped();
0196     void enableContactEventsChanged();
0197     void pixelsPerMeterChanged();
0198 
0199 protected:
0200     void enableContactListener(bool enable);
0201 
0202 private:
0203     b2World mWorld;
0204     ContactListener *mContactListener;
0205     float mTimeStep;
0206     int mVelocityIterations;
0207     int mPositionIterations;
0208     bool mComponentComplete;
0209     bool mIsRunning;
0210     bool mSynchronizing;
0211     StepDriver *mStepDriver;
0212     Box2DProfile *mProfile;
0213     bool mEnableContactEvents;
0214     float mPixelsPerMeter;
0215 };
0216 
0217 
0218 inline float Box2DProfile::step() const
0219 {
0220     return mWorld->GetProfile().step;
0221 }
0222 
0223 inline float Box2DProfile::collide() const
0224 {
0225     return mWorld->GetProfile().collide;
0226 }
0227 
0228 inline float Box2DProfile::solve() const
0229 {
0230     return mWorld->GetProfile().solve;
0231 }
0232 
0233 inline float Box2DProfile::solveInit() const
0234 {
0235     return mWorld->GetProfile().solveInit;
0236 }
0237 
0238 inline float Box2DProfile::solveVelocity() const
0239 {
0240     return mWorld->GetProfile().solveVelocity;
0241 }
0242 
0243 inline float Box2DProfile::solvePosition() const
0244 {
0245     return mWorld->GetProfile().solvePosition;
0246 }
0247 
0248 inline float Box2DProfile::broadphase() const
0249 {
0250     return mWorld->GetProfile().broadphase;
0251 }
0252 
0253 inline float Box2DProfile::solveTOI() const
0254 {
0255     return mWorld->GetProfile().solveTOI;
0256 }
0257 
0258 inline float Box2DProfile::synchronize() const
0259 {
0260     return mSynchronize;
0261 }
0262 
0263 inline float Box2DProfile::emitSignals() const
0264 {
0265     return mEmitSignals;
0266 }
0267 
0268 
0269 /**
0270  * The amount of time to step through each frame in seconds.
0271  * By default it is 1 / 60.
0272  */
0273 inline float Box2DWorld::timeStep() const
0274 {
0275     return mTimeStep;
0276 }
0277 
0278 inline bool Box2DWorld::isRunning() const
0279 {
0280     return mIsRunning;
0281 }
0282 
0283 /**
0284  * The number of velocity iterations used to process one step.
0285  * 8 by default.
0286  */
0287 inline int Box2DWorld::velocityIterations() const
0288 {
0289     return mVelocityIterations;
0290 }
0291 
0292 /**
0293  * The number of position iterations used to process one step.
0294  * 3 by default.
0295  */
0296 inline int Box2DWorld::positionIterations() const
0297 {
0298     return mPositionIterations;
0299 }
0300 
0301 inline bool Box2DWorld::autoClearForces() const
0302 {
0303     return mWorld.GetAutoClearForces();
0304 }
0305 
0306 inline Box2DProfile *Box2DWorld::profile() const
0307 {
0308     return mProfile;
0309 }
0310 
0311 inline bool Box2DWorld::enableContactEvents() const
0312 {
0313     return mEnableContactEvents;
0314 }
0315 
0316 inline float Box2DWorld::pixelsPerMeter() const
0317 {
0318     return mPixelsPerMeter;
0319 }
0320 
0321 inline float Box2DWorld::metersPerPixel() const
0322 {
0323     return 1.0f / pixelsPerMeter();
0324 }
0325 
0326 inline float Box2DWorld::pixelsPerMeterY() const
0327 {
0328     return -pixelsPerMeter(); // Y-axis inverted
0329 }
0330 
0331 inline float Box2DWorld::metersPerPixelY() const
0332 {
0333     return -metersPerPixel();
0334 }
0335 
0336 /**
0337  * Converts lengths from Box2D to QML units.
0338  */
0339 inline float Box2DWorld::toPixels(float length) const
0340 {
0341     return length * pixelsPerMeter();
0342 }
0343 
0344 /**
0345  * Converts lengths from QML to Box2D units.
0346  */
0347 inline float Box2DWorld::toMeters(float length) const
0348 {
0349     return length * metersPerPixel();
0350 }
0351 
0352 /**
0353  * Converts positions and sizes from Box2D to QML coordinates.
0354  */
0355 inline QPointF Box2DWorld::toPixels(const b2Vec2 &vec) const
0356 {
0357     return QPointF(vec.x * pixelsPerMeter(),
0358                    vec.y * pixelsPerMeterY());
0359 }
0360 
0361 /**
0362  * Converts positions and sizes from QML to Box2D coordinates.
0363  */
0364 inline b2Vec2 Box2DWorld::toMeters(const QPointF &point) const
0365 {
0366     return b2Vec2(point.x() * metersPerPixel(),
0367                   point.y() * metersPerPixelY());
0368 }
0369 
0370 inline bool Box2DWorld::isSynchronizing() const
0371 {
0372     return mSynchronizing;
0373 }
0374 
0375 inline b2World &Box2DWorld::world()
0376 {
0377     return mWorld;
0378 }
0379 
0380 inline void Box2DWorld::clearForces()
0381 {
0382     mWorld.ClearForces();
0383 }
0384 
0385 
0386 /**
0387  * Inverts the y-axis as required for forces and velocities.
0388  */
0389 inline QPointF invertY(const b2Vec2 &vec)
0390 {
0391     return QPointF(vec.x, -vec.y);
0392 }
0393 
0394 /**
0395  * Inverts the y-axis as required for forces and velocities.
0396  */
0397 inline b2Vec2 invertY(const QPointF &vec)
0398 {
0399     return b2Vec2(vec.x(), -vec.y());
0400 }
0401 
0402 /**
0403  * Converts angles from Box2D to QML values.
0404  */
0405 inline float toDegrees(float radians)
0406 {
0407     return -radians * 180 / b2_pi;
0408 }
0409 
0410 /**
0411  * Converts angles from QML to Box2D values.
0412  */
0413 inline float toRadians(float degrees)
0414 {
0415     return -degrees * b2_pi / 180;
0416 }
0417 
0418 
0419 QML_DECLARE_TYPE(Box2DWorld)
0420 
0421 #endif // BOX2DWORLD_H