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