Solved How to use the Box2D's b2Draw class in Qt6 with OpenGL3? DrawSegment is not called
-
I am trying to draw colliders of Box2D. Now I have only physics in this example without graphics for simplicity. The
DrawSegment()
method must be called to printhello
:DebugDrawer.cpp
#include "DebugDrawer.h" #include <QtCore/QDebug> DebugDrawer::DebugDrawer() { } void DebugDrawer::DrawSegment(const b2Vec2 &p1, const b2Vec2 &p2, const b2Color &color) { qDebug() << "hello"; } void DebugDrawer::DrawSolidPolygon(const b2Vec2 *vertices, int32 vertexCount, const b2Color &color) { } void DebugDrawer::DrawPolygon(const b2Vec2 *vertices, int32 vertexCount, const b2Color &color) { } void DebugDrawer::DrawPoint(const b2Vec2 &p, float size, const b2Color &color) { } void DebugDrawer::DrawCircle(const b2Vec2 ¢er, float radius, const b2Color &color) { } void DebugDrawer::DrawSolidCircle(const b2Vec2 ¢er, float radius, const b2Vec2 &axis, const b2Color &color) { } void DebugDrawer::DrawTransform(const b2Transform &xf) { }
I inherited the
DebugDrawer
class from theb2Draw
class:#ifndef DEBUGDRAWER_H #define DEBUGDRAWER_H #include "box2d/b2_draw.h" class DebugDrawer : public b2Draw { public: DebugDrawer(); private: // virtual void DrawSegment(b2Vec2& p1, b2Vec2& p2, b2Color& color) override; void DrawSolidPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color); void DrawPoint (const b2Vec2 &p, float size, const b2Color &color); void DrawPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color); void DrawCircle(const b2Vec2& center, float radius, const b2Color& color); void DrawSolidCircle(const b2Vec2& center, float radius, const b2Vec2& axis, const b2Color& color); void DrawSegment(const b2Vec2& p1, const b2Vec2& p2, const b2Color& color); void DrawTransform(const b2Transform& xf); }; #endif // DEBUGDRAWER_H
I created one object with the box shape. I have the
animationLoop()
method that I call with timer. Inside of theanimationLoop()
method I them_pWorld->Step()
method and I call thepaintGL()
method by calling theupdate()
method. Inside of thepaintGL()
method I call them_pWorld->DebugDraw()
method. I expect that theDebugDrawer::DrawSegment()
will be called but it does not happen.Widget.cpp
#include "Widget.h" #include <QtCore/QDebug> Widget::Widget(QWidget *parent) : QOpenGLWidget(parent) { setWindowTitle("Box2D, OpenGL3, Qt6, C++"); setFixedSize(QSize(500, 500)); b2Vec2 gravity(0.f, 9.8f); m_pWorld = new b2World(gravity); } Widget::~Widget() { delete m_pWorld; delete m_pDebugDrawer; } void Widget::initializeGL() { initializeOpenGLFunctions(); glClearColor(0.2f, 0.2f, 0.2f, 1.f); glEnable(GL_DEPTH_TEST); m_pDebugDrawer = new DebugDrawer(); m_pWorld->SetDebugDraw(m_pDebugDrawer); uint32 flags = 0; flags |= b2Draw::e_shapeBit; flags |= b2Draw::e_jointBit; flags |= b2Draw::e_centerOfMassBit; flags |= b2Draw::e_aabbBit; flags |= b2Draw::e_pairBit; m_pDebugDrawer->SetFlags(flags); // m_pDebugDrawer->SetFlags(b2Draw::e_shapeBit); b2PolygonShape shape; shape.SetAsBox(50.f / WORLD_SCALE, 50.f / WORLD_SCALE); b2BodyDef bdef; bdef.type = b2_staticBody; m_pBody = m_pWorld->CreateBody(&bdef); m_pBody->CreateFixture(&shape, 2.f); connect(&m_timer, &QTimer::timeout, this, &Widget::animationLoop); m_timer.start(1000.f/60.f); m_elapsedTimer.start(); } void Widget::paintGL() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); m_pWorld->DebugDraw(); } void Widget::resizeGL(int w, int h) { glViewport(0, 0, w, h); } void Widget::animationLoop() { m_deltaTime = m_elapsedTimer.elapsed() / 1000.f; m_elapsedTimer.restart(); m_pWorld->Step(m_deltaTime, 8, 3); update(); }
Widget.h
#ifndef WIDGET_H #define WIDGET_H #include "box2d/box2d.h" #include <QtCore/QElapsedTimer> #include <QtCore/QTimer> #include <QtOpenGLWidgets/QOpenGLWidget> #include <QtGui/QOpenGLFunctions> #include "DebugDrawer.h" class Widget : public QOpenGLWidget, QOpenGLFunctions { Q_OBJECT public: Widget(QWidget *parent = nullptr); ~Widget(); private slots: void animationLoop(); private: void initializeGL() override; void paintGL() override; void resizeGL(int w, int h) override; private: const float WORLD_SCALE = 30.f; b2World *m_pWorld; DebugDrawer *m_pDebugDrawer; b2Body *m_pBody; QElapsedTimer m_elapsedTimer; QTimer m_timer; float m_deltaTime; }; #endif // WIDGET_H
main.cpp
#ifdef _WIN32 #include <windows.h> extern "C" __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001; extern "C" __declspec(dllexport) DWORD AmdPowerXpressRequestHighPerformance = 0x00000001; #endif #include <QtGui/QSurfaceFormat> #include <QtWidgets/QApplication> #include "Widget.h" int main(int argc, char *argv[]) { QApplication a(argc, argv); QSurfaceFormat format; format.setSamples(8); Widget w; w.setFormat(format); w.show(); return a.exec(); }
.pro
QT += core gui openglwidgets win32: LIBS += -lopengl32 INCLUDEPATH += "E:\Libs\box2d-2.4.1-mingw-64-bit\include" LIBS += -L"E:\Libs\box2d-2.4.1-mingw-64-bit\lib" LIBS += -lbox2d greaterThan(QT_MAJOR_VERSION, 4): QT += widgets CONFIG += c++11 # You can make your code fail to compile if it uses deprecated APIs. # In order to do so, uncomment the following line. #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0 SOURCES += \ DebugDrawer.cpp \ main.cpp \ Widget.cpp HEADERS += \ DebugDrawer.h \ Widget.h # Default rules for deployment. qnx: target.path = /tmp/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin !isEmpty(target.path): INSTALLS += target
-
I should use
DrawPolygon
to draw segments of colliders when I use boxes to draw borders around game objects.DrawSegment()
will be called when an instance ofb2EdgeShape
is created:b2EdgeShape edgeShape; edgeShape.SetOneSided(b2Vec2(0.f, 0.f), b2Vec2(1.f, 0.f), b2Vec2(2.f, 0.f), b2Vec2(3.f, 0.f)); m_pEdgeBody = m_pWorld->CreateBody(&bdef); m_pEdgeBody->CreateFixture(&edgeShape, 2.f);
-
I should use
DrawPolygon
to draw segments of colliders when I use boxes to draw borders around game objects.DrawSegment()
will be called when an instance ofb2EdgeShape
is created:b2EdgeShape edgeShape; edgeShape.SetOneSided(b2Vec2(0.f, 0.f), b2Vec2(1.f, 0.f), b2Vec2(2.f, 0.f), b2Vec2(3.f, 0.f)); m_pEdgeBody = m_pWorld->CreateBody(&bdef); m_pEdgeBody->CreateFixture(&edgeShape, 2.f);