File indexing completed on 2024-04-21 14:43:24
0001 /* 0002 * box2ddebugdraw.cpp 0003 * Copyright (c) 2010 Thorbjørn Lindeijer <thorbjorn@lindeijer.nl> 0004 * Copyright (c) 2014 Moukhlynin Ruslan <ruslan@khvmntk.ru> 0005 * 0006 * This file is part of the Box2D QML plugin. 0007 * 0008 * This software is provided 'as-is', without any express or implied warranty. 0009 * In no event will the authors be held liable for any damages arising from 0010 * the use of this software. 0011 * 0012 * Permission is granted to anyone to use this software for any purpose, 0013 * including commercial applications, and to alter it and redistribute it 0014 * freely, subject to the following restrictions: 0015 * 0016 * 1. The origin of this software must not be misrepresented; you must not 0017 * claim that you wrote the original software. If you use this software in 0018 * a product, an acknowledgment in the product documentation would be 0019 * appreciated but is not required. 0020 * 0021 * 2. Altered source versions must be plainly marked as such, and must not be 0022 * misrepresented as being the original software. 0023 * 0024 * 3. This notice may not be removed or altered from any source distribution. 0025 */ 0026 0027 #define CIRCLE_SEGMENTS_COUNT 32 0028 #define LINE_WIDTH 1 0029 0030 #include "box2ddebugdraw.h" 0031 0032 #include "box2dworld.h" 0033 0034 #include <Box2D.h> 0035 0036 #include <QPainter> 0037 #include <QSGNode> 0038 #include <QSGFlatColorMaterial> 0039 #include <QtCore/qmath.h> 0040 0041 class DebugDraw : public b2Draw 0042 { 0043 public: 0044 DebugDraw(QSGNode *root, Box2DWorld &world); 0045 0046 void draw(); 0047 0048 void DrawPolygon(const b2Vec2 *vertices, int32 vertexCount, 0049 const b2Color &color); 0050 void DrawSolidPolygon(const b2Vec2 *vertices, int32 vertexCount, 0051 const b2Color &color); 0052 void DrawCircle(const b2Vec2 ¢er, float32 radius, 0053 const b2Color &color); 0054 void DrawSolidCircle(const b2Vec2 ¢er, float32 radius, 0055 const b2Vec2 &axis, const b2Color &color); 0056 void DrawSegment(const b2Vec2 &p1, const b2Vec2 &p2, 0057 const b2Color &color); 0058 void DrawTransform(const b2Transform &xf); 0059 0060 void setAxisScale(qreal axisScale); 0061 0062 private: 0063 QSGNode *mRoot; 0064 Box2DWorld &mWorld; 0065 qreal mAxisScale; 0066 0067 QSGNode *createNode(QSGGeometry *geometry, const QColor &color, QSGNode *parent = 0); 0068 }; 0069 0070 DebugDraw::DebugDraw(QSGNode *root, Box2DWorld &world) : 0071 mRoot(root), 0072 mWorld(world) 0073 { 0074 } 0075 0076 void DebugDraw::draw() 0077 { 0078 mWorld.world().SetDebugDraw(this); 0079 mWorld.world().DrawDebugData(); 0080 mWorld.world().SetDebugDraw(0); 0081 } 0082 0083 static QColor toQColor(const b2Color &color) 0084 { 0085 return QColor(color.r * 255, 0086 color.g * 255, 0087 color.b * 255, 0088 color.a * 255); 0089 } 0090 0091 QSGNode *DebugDraw::createNode(QSGGeometry *geometry, const QColor &color, QSGNode *parent) 0092 { 0093 QSGFlatColorMaterial *material = new QSGFlatColorMaterial; 0094 material->setColor(color); 0095 0096 QSGGeometryNode *node = new QSGGeometryNode; 0097 node->setGeometry(geometry); 0098 node->setFlag(QSGNode::OwnsGeometry); 0099 node->setMaterial(material); 0100 node->setFlag(QSGNode::OwnsMaterial); 0101 0102 if (parent) 0103 parent->appendChildNode(node); 0104 else 0105 mRoot->appendChildNode(node); 0106 return node; 0107 } 0108 0109 void DebugDraw::DrawPolygon(const b2Vec2 *vertices, 0110 int32 vertexCount, 0111 const b2Color &color) 0112 { 0113 QSGGeometry *geometry = new QSGGeometry(QSGGeometry::defaultAttributes_Point2D(), 0114 vertexCount); 0115 geometry->setDrawingMode(GL_LINE_LOOP); 0116 geometry->setLineWidth(LINE_WIDTH); 0117 0118 QSGGeometry::Point2D *points = geometry->vertexDataAsPoint2D(); 0119 for (int i = 0; i < vertexCount; ++i) { 0120 QPointF point = mWorld.toPixels(vertices[i]); 0121 points[i].set(point.x(), point.y()); 0122 } 0123 0124 createNode(geometry, toQColor(color)); 0125 } 0126 0127 void DebugDraw::DrawSolidPolygon(const b2Vec2 *vertices, 0128 int32 vertexCount, 0129 const b2Color &color) 0130 { 0131 QSGGeometry *geometry = new QSGGeometry(QSGGeometry::defaultAttributes_Point2D(), 0132 vertexCount); 0133 geometry->setDrawingMode(GL_TRIANGLE_FAN); 0134 geometry->setLineWidth(LINE_WIDTH); 0135 0136 QSGGeometry::Point2D *points = geometry->vertexDataAsPoint2D(); 0137 for (int i = 0; i < vertexCount; ++i) { 0138 QPointF point = mWorld.toPixels(vertices[i]); 0139 points[i].set(point.x(), point.y()); 0140 } 0141 0142 createNode(geometry, toQColor(color)); 0143 } 0144 0145 void DebugDraw::DrawCircle(const b2Vec2 ¢er, 0146 float32 radius, 0147 const b2Color &color) 0148 { 0149 QSGGeometry *geometry = new QSGGeometry(QSGGeometry::defaultAttributes_Point2D(), 0150 CIRCLE_SEGMENTS_COUNT); 0151 geometry->setDrawingMode(GL_LINE_LOOP); 0152 geometry->setLineWidth(LINE_WIDTH); 0153 0154 QPointF centerInPixels = mWorld.toPixels(center); 0155 qreal radiusInPixels = mWorld.toPixels(radius); 0156 0157 QSGGeometry::Point2D *points = geometry->vertexDataAsPoint2D(); 0158 for (int i = 0; i < CIRCLE_SEGMENTS_COUNT; ++i) { 0159 float theta = i * 2 * M_PI / (CIRCLE_SEGMENTS_COUNT - 2); 0160 points[i].set(centerInPixels.x() + radiusInPixels * qCos(theta), 0161 centerInPixels.y() + radiusInPixels * qSin(theta)); 0162 } 0163 0164 createNode(geometry, toQColor(color)); 0165 } 0166 0167 void DebugDraw::DrawSolidCircle(const b2Vec2 ¢er, float32 radius, 0168 const b2Vec2 &axis, const b2Color &color) 0169 { 0170 0171 QSGGeometry *geometry = new QSGGeometry(QSGGeometry::defaultAttributes_Point2D(), 0172 CIRCLE_SEGMENTS_COUNT); 0173 geometry->setDrawingMode(GL_TRIANGLE_FAN); 0174 geometry->setLineWidth(LINE_WIDTH); 0175 0176 QPointF centerInPixels = mWorld.toPixels(center); 0177 QPointF axisInPixels = mWorld.toPixels(axis); 0178 qreal radiusInPixels = mWorld.toPixels(radius); 0179 axisInPixels.setX(centerInPixels.x() + radius * axisInPixels.x()); 0180 axisInPixels.setY(centerInPixels.y() + radius * axisInPixels.y()); 0181 0182 QSGGeometry::Point2D *points = geometry->vertexDataAsPoint2D(); 0183 points[0].set(centerInPixels.x(), centerInPixels.y()); 0184 for (int i = 1; i < CIRCLE_SEGMENTS_COUNT; ++i) { 0185 float theta = i * 2 * M_PI / (CIRCLE_SEGMENTS_COUNT - 2); 0186 points[i].set(centerInPixels.x() + radiusInPixels * qCos(theta), 0187 centerInPixels.y() + radiusInPixels * qSin(theta)); 0188 } 0189 QSGNode * node = createNode(geometry,toQColor(color)); 0190 0191 QSGGeometry *axisGeometry = new QSGGeometry(QSGGeometry::defaultAttributes_Point2D(), 2); 0192 axisGeometry->setDrawingMode(GL_LINES); 0193 axisGeometry->setLineWidth(LINE_WIDTH); 0194 0195 axisGeometry->vertexDataAsPoint2D()[0].set(centerInPixels.x(), centerInPixels.y()); 0196 axisGeometry->vertexDataAsPoint2D()[1].set(axisInPixels.x(), axisInPixels.y()); 0197 createNode(axisGeometry, qRgb(200, 64, 0), node); 0198 } 0199 0200 void DebugDraw::DrawSegment(const b2Vec2 &p1, 0201 const b2Vec2 &p2, 0202 const b2Color &color) 0203 { 0204 QPointF p1InPixels = mWorld.toPixels(p1); 0205 QPointF p2InPixels = mWorld.toPixels(p2); 0206 0207 QSGGeometry *geometry = new QSGGeometry(QSGGeometry::defaultAttributes_Point2D(), 2); 0208 geometry->setDrawingMode(GL_LINES); 0209 geometry->setLineWidth(LINE_WIDTH); 0210 0211 geometry->vertexDataAsPoint2D()[0].set(p1InPixels.x(), p1InPixels.y()); 0212 geometry->vertexDataAsPoint2D()[1].set(p2InPixels.x(), p2InPixels.y()); 0213 0214 createNode(geometry, toQColor(color)); 0215 } 0216 0217 void DebugDraw::DrawTransform(const b2Transform &xf) 0218 { 0219 0220 QPointF p1 = mWorld.toPixels(xf.p); 0221 QPointF p2 = mWorld.toPixels(xf.q.GetXAxis()); 0222 p2 = QPointF(p1.x() + mAxisScale * p2.x(), 0223 p1.y() + mAxisScale * p2.y()); 0224 0225 QSGGeometry *geometryX = new QSGGeometry(QSGGeometry::defaultAttributes_Point2D(), 2); 0226 geometryX->setDrawingMode(GL_LINES); 0227 geometryX->setLineWidth(LINE_WIDTH); 0228 geometryX->vertexDataAsPoint2D()[0].set(p1.x(), p1.y()); 0229 geometryX->vertexDataAsPoint2D()[1].set(p2.x(), p2.y()); 0230 createNode(geometryX,Qt::blue); 0231 0232 p2 = mWorld.toPixels(xf.q.GetYAxis()); 0233 p2 = QPointF(p1.x() + mAxisScale * p2.x(), 0234 p1.y() + mAxisScale * p2.y()); 0235 0236 QSGGeometry *geometryY = new QSGGeometry(QSGGeometry::defaultAttributes_Point2D(), 2); 0237 geometryY->setDrawingMode(GL_LINES); 0238 geometryY->setLineWidth(LINE_WIDTH); 0239 geometryY->vertexDataAsPoint2D()[0].set(p1.x(), p1.y()); 0240 geometryY->vertexDataAsPoint2D()[1].set(p2.x(), p2.y()); 0241 0242 createNode(geometryY, Qt::yellow); 0243 } 0244 0245 void DebugDraw::setAxisScale(qreal axisScale) 0246 { 0247 mAxisScale = axisScale; 0248 } 0249 0250 Box2DDebugDraw::Box2DDebugDraw(QQuickItem *parent) : 0251 QQuickItem (parent), 0252 mWorld(0), 0253 mAxisScale(0.5), 0254 mFlags(Everything) 0255 { 0256 setFlag(QQuickItem::ItemHasContents, true); 0257 setWorld(Box2DWorld::defaultWorld()); 0258 } 0259 0260 void Box2DDebugDraw::setAxisScale(qreal axisScale) 0261 { 0262 if (mAxisScale != axisScale) { 0263 mAxisScale = axisScale; 0264 emit axisScaleChanged(); 0265 } 0266 } 0267 0268 void Box2DDebugDraw::setFlags(DebugFlag flags) 0269 { 0270 if (mFlags != flags) { 0271 mFlags = flags; 0272 emit flagsChanged(); 0273 } 0274 } 0275 0276 void Box2DDebugDraw::setWorld(Box2DWorld *world) 0277 { 0278 if (mWorld == world) 0279 return; 0280 0281 if (mWorld) 0282 mWorld->disconnect(this); 0283 0284 mWorld = world; 0285 0286 if (mWorld) 0287 connect(mWorld, SIGNAL(stepped()), SLOT(onWorldStepped())); 0288 0289 emit worldChanged(); 0290 } 0291 0292 QSGNode *Box2DDebugDraw::updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *) 0293 { 0294 if (oldNode) 0295 delete oldNode; 0296 0297 if (!mWorld) 0298 return 0; 0299 0300 QSGTransformNode *root = new QSGTransformNode; 0301 DebugDraw debugDraw(root, *mWorld); 0302 debugDraw.SetFlags(mFlags); 0303 debugDraw.setAxisScale(mAxisScale); 0304 debugDraw.draw(); 0305 return root; 0306 } 0307 0308 void Box2DDebugDraw::onWorldStepped() 0309 { 0310 if (isVisible() && opacity() > 0) 0311 update(); 0312 }