File indexing completed on 2024-03-24 15:14:07
0001 /* 0002 * box2dfixture.cpp 0003 * Copyright (c) 2010-2011 Thorbjørn Lindeijer <thorbjorn@lindeijer.nl> 0004 * Copyright (c) 2011 Daker Fernandes Pinheiro <daker.pinheiro@openbossa.org> 0005 * Copyright (c) 2011 Alessandro Portale <alessandro.portale@nokia.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 #include "box2dfixture.h" 0029 0030 #include "box2dbody.h" 0031 #include "box2dworld.h" 0032 0033 #include <QDebug> 0034 0035 #include "Common/b2Math.h" 0036 0037 Box2DFixture::Box2DFixture(QObject *parent) : 0038 QObject(parent), 0039 mFixture(0), 0040 mBody(0) 0041 { 0042 mFixtureDef.userData = this; 0043 } 0044 0045 float Box2DFixture::density() const 0046 { 0047 return mFixtureDef.density; 0048 } 0049 0050 void Box2DFixture::setDensity(float density) 0051 { 0052 if (mFixtureDef.density == density) 0053 return; 0054 0055 mFixtureDef.density = density; 0056 if (mFixture) 0057 mFixture->SetDensity(density); 0058 emit densityChanged(); 0059 } 0060 0061 float Box2DFixture::friction() const 0062 { 0063 return mFixtureDef.friction; 0064 } 0065 0066 void Box2DFixture::setFriction(float friction) 0067 { 0068 if (mFixtureDef.friction == friction) 0069 return; 0070 0071 mFixtureDef.friction = friction; 0072 if (mFixture) 0073 mFixture->SetFriction(friction); 0074 emit frictionChanged(); 0075 } 0076 0077 float Box2DFixture::restitution() const 0078 { 0079 return mFixtureDef.restitution; 0080 } 0081 0082 void Box2DFixture::setRestitution(float restitution) 0083 { 0084 if (mFixtureDef.restitution == restitution) 0085 return; 0086 0087 mFixtureDef.restitution = restitution; 0088 if (mFixture) 0089 mFixture->SetRestitution(restitution); 0090 emit restitutionChanged(); 0091 } 0092 0093 bool Box2DFixture::isSensor() const 0094 { 0095 return mFixtureDef.isSensor; 0096 } 0097 0098 void Box2DFixture::setSensor(bool sensor) 0099 { 0100 if (mFixtureDef.isSensor == sensor) 0101 return; 0102 0103 mFixtureDef.isSensor = sensor; 0104 if (mFixture) 0105 mFixture->SetSensor(sensor); 0106 emit sensorChanged(); 0107 } 0108 0109 Box2DFixture::CategoryFlags Box2DFixture::categories() const 0110 { 0111 return CategoryFlags(mFixtureDef.filter.categoryBits); 0112 } 0113 0114 void Box2DFixture::setCategories(CategoryFlags layers) 0115 { 0116 if (mFixtureDef.filter.categoryBits == layers) 0117 return; 0118 0119 mFixtureDef.filter.categoryBits = layers; 0120 if (mFixture) 0121 mFixture->SetFilterData(mFixtureDef.filter); 0122 0123 emit categoriesChanged(); 0124 } 0125 0126 Box2DFixture::CategoryFlags Box2DFixture::collidesWith() const 0127 { 0128 return CategoryFlags(mFixtureDef.filter.maskBits); 0129 } 0130 0131 void Box2DFixture::setCollidesWith(CategoryFlags layers) 0132 { 0133 if (mFixtureDef.filter.maskBits == layers) 0134 return; 0135 0136 mFixtureDef.filter.maskBits = layers; 0137 if (mFixture) 0138 mFixture->SetFilterData(mFixtureDef.filter); 0139 0140 emit collidesWithChanged(); 0141 } 0142 0143 int Box2DFixture::groupIndex() const 0144 { 0145 return mFixtureDef.filter.groupIndex; 0146 } 0147 0148 void Box2DFixture::setGroupIndex(int groupIndex) 0149 { 0150 if (mFixtureDef.filter.groupIndex == groupIndex) 0151 return; 0152 0153 mFixtureDef.filter.groupIndex = groupIndex; 0154 if (mFixture) 0155 mFixture->SetFilterData(mFixtureDef.filter); 0156 0157 emit groupIndexChanged(); 0158 } 0159 0160 void Box2DFixture::initialize(Box2DBody *body) 0161 { 0162 mBody = body; 0163 b2Shape *shape = createShape(); 0164 if (!shape) 0165 return; 0166 0167 mFixtureDef.shape = shape; 0168 mFixture = body->body()->CreateFixture(&mFixtureDef); 0169 delete shape; 0170 } 0171 0172 void Box2DFixture::recreateFixture() 0173 { 0174 if (!mBody) 0175 return; 0176 if (mFixture) 0177 mBody->body()->DestroyFixture(mFixture); 0178 initialize(mBody); 0179 } 0180 0181 Box2DBody *Box2DFixture::getBody() const 0182 { 0183 return mBody; 0184 } 0185 0186 //=================== BOX ======================= 0187 0188 void Box2DBox::setX(qreal x) 0189 { 0190 if (mPosition.x() == x) 0191 return; 0192 mPosition.setX(x); 0193 recreateFixture(); 0194 emit xChanged(); 0195 } 0196 0197 void Box2DBox::setY(qreal y) 0198 { 0199 if (mPosition.y() == y) 0200 return; 0201 mPosition.setY(y); 0202 recreateFixture(); 0203 emit yChanged(); 0204 } 0205 0206 void Box2DBox::setWidth(qreal width) 0207 { 0208 if (mSize.width() == width) 0209 return; 0210 mSize.setWidth(width); 0211 recreateFixture(); 0212 emit widthChanged(); 0213 } 0214 0215 void Box2DBox::setHeight(qreal height) 0216 { 0217 if (mSize.height() == height) 0218 return; 0219 mSize.setHeight(height); 0220 recreateFixture(); 0221 emit heightChanged(); 0222 } 0223 0224 void Box2DBox::setRotation(qreal rotation) 0225 { 0226 if (mRotation == rotation) 0227 return; 0228 mRotation = rotation; 0229 recreateFixture(); 0230 emit rotationChanged(); 0231 } 0232 0233 b2Shape *Box2DBox::createShape() 0234 { 0235 const qreal halfWidth = width() * 0.5; 0236 const qreal halfHeight = height() * 0.5; 0237 const QPointF center(x() + halfWidth, 0238 y() + halfHeight); 0239 0240 b2PolygonShape *shape = new b2PolygonShape; 0241 shape->SetAsBox(b2Max(mBody->world()->toMeters(halfWidth), b2_linearSlop), 0242 b2Max(mBody->world()->toMeters(halfHeight), b2_linearSlop), 0243 mBody->world()->toMeters(center), 0244 toRadians(rotation())); 0245 0246 return shape; 0247 } 0248 0249 //=================== CIRCLE ======================= 0250 0251 void Box2DCircle::setX(qreal x) 0252 { 0253 if (mPosition.x() == x) 0254 return; 0255 mPosition.setX(x); 0256 recreateFixture(); 0257 emit xChanged(); 0258 } 0259 0260 void Box2DCircle::setY(qreal y) 0261 { 0262 if (mPosition.y() == y) 0263 return; 0264 mPosition.setY(y); 0265 recreateFixture(); 0266 emit yChanged(); 0267 } 0268 0269 void Box2DCircle::setRadius(float radius) 0270 { 0271 if (mRadius == radius) 0272 return; 0273 mRadius = radius; 0274 recreateFixture(); 0275 emit radiusChanged(); 0276 } 0277 0278 b2Shape *Box2DCircle::createShape() 0279 { 0280 b2CircleShape *shape = new b2CircleShape; 0281 0282 shape->m_radius = mBody->world()->toMeters(radius()); 0283 shape->m_p = mBody->world()->toMeters(position() + QPointF(radius(), radius())); 0284 0285 return shape; 0286 } 0287 0288 //=================== POLYGON ======================= 0289 0290 void Box2DPolygon::setVertices(const QVariantList &vertices) 0291 { 0292 if (vertices == mVertices) 0293 return; 0294 0295 mVertices = vertices; 0296 recreateFixture(); 0297 emit verticesChanged(); 0298 } 0299 0300 b2Shape *Box2DPolygon::createShape() 0301 { 0302 const int count = mVertices.length(); 0303 if (count < 2 || count > b2_maxPolygonVertices) { 0304 qWarning() << "Polygon: Invalid number of vertices:" << count; 0305 return 0; 0306 } 0307 0308 QScopedArrayPointer<b2Vec2> vertices(new b2Vec2[count]); 0309 0310 for (int i = 0; i < count; ++i) { 0311 vertices[i] = mBody->world()->toMeters(mVertices.at(i).toPointF()); 0312 0313 if (i > 0) { 0314 if (b2DistanceSquared(vertices[i - 1], vertices[i]) <= b2_linearSlop * b2_linearSlop) { 0315 qWarning() << "Polygon: vertices are too close together"; 0316 return 0; 0317 } 0318 } 0319 } 0320 0321 b2PolygonShape *shape = new b2PolygonShape; 0322 shape->Set(vertices.data(), count); 0323 0324 return shape; 0325 } 0326 0327 //=================== CHAIN ======================= 0328 0329 Box2DChain::Box2DChain(QQuickItem *parent) : 0330 Box2DFixture(parent), 0331 mLoop(false), 0332 mPrevVertexFlag(false), 0333 mNextVertexFlag(false) 0334 { 0335 } 0336 0337 void Box2DChain::setVertices(const QVariantList &vertices) 0338 { 0339 if (vertices == mVertices) 0340 return; 0341 0342 mVertices = vertices; 0343 recreateFixture(); 0344 emit verticesChanged(); 0345 } 0346 0347 void Box2DChain::setLoop(bool loop) 0348 { 0349 if (mLoop == loop) 0350 return; 0351 0352 mLoop = loop; 0353 recreateFixture(); 0354 emit loopChanged(); 0355 } 0356 0357 void Box2DChain::setPrevVertex(const QPointF &prevVertex) 0358 { 0359 if (mPrevVertexFlag && mPrevVertex == prevVertex) 0360 return; 0361 0362 mPrevVertex = prevVertex; 0363 mPrevVertexFlag = true; 0364 recreateFixture(); 0365 emit prevVertexChanged(); 0366 } 0367 0368 void Box2DChain::setNextVertex(const QPointF &nextVertex) 0369 { 0370 if (mNextVertexFlag && mNextVertex == nextVertex) 0371 return; 0372 0373 mNextVertex = nextVertex; 0374 mNextVertexFlag = true; 0375 recreateFixture(); 0376 emit nextVertexChanged(); 0377 } 0378 0379 b2Shape *Box2DChain::createShape() 0380 { 0381 const int count = mVertices.length(); 0382 0383 if (count < 2 || (mLoop && count < 3)) { 0384 qWarning() << "Chain: Invalid number of vertices:" << count; 0385 return 0; 0386 } 0387 0388 QScopedArrayPointer<b2Vec2> vertices(new b2Vec2[count]); 0389 0390 for (int i = 0; i < count; ++i) { 0391 vertices[i] = mBody->world()->toMeters(mVertices.at(i).toPointF()); 0392 0393 if (i > 0) { 0394 if (b2DistanceSquared(vertices[i - 1], vertices[i]) <= b2_linearSlop * b2_linearSlop) { 0395 qWarning() << "Chain: vertices are too close together"; 0396 return 0; 0397 } 0398 } 0399 } 0400 0401 b2ChainShape *shape = new b2ChainShape; 0402 if (mLoop) { 0403 shape->CreateLoop(vertices.data(), count); 0404 } else { 0405 shape->CreateChain(vertices.data(), count); 0406 0407 if (mPrevVertexFlag) 0408 shape->SetPrevVertex(mBody->world()->toMeters(mPrevVertex)); 0409 if (mNextVertexFlag) 0410 shape->SetNextVertex(mBody->world()->toMeters(mNextVertex)); 0411 } 0412 0413 return shape; 0414 } 0415 0416 //=================== EDGE ======================= 0417 0418 void Box2DEdge::setVertices(const QVariantList &vertices) 0419 { 0420 if (vertices == mVertices) 0421 return; 0422 0423 mVertices = vertices; 0424 recreateFixture(); 0425 emit verticesChanged(); 0426 } 0427 0428 b2Shape *Box2DEdge::createShape() 0429 { 0430 const int count = mVertices.length(); 0431 if (count != 2) { 0432 qWarning() << "Edge: Invalid number of vertices:" << count; 0433 return 0; 0434 } 0435 const b2Vec2 vertex1 = mBody->world()->toMeters(mVertices.at(0).toPointF()); 0436 const b2Vec2 vertex2 = mBody->world()->toMeters(mVertices.at(1).toPointF()); 0437 if (b2DistanceSquared(vertex1, vertex2) <= b2_linearSlop * b2_linearSlop) { 0438 qWarning() << "Edge: vertices are too close together"; 0439 return 0; 0440 } 0441 b2EdgeShape *shape = new b2EdgeShape; 0442 shape->Set(vertex1, vertex2); 0443 0444 return shape; 0445 }