Home > Back-end >  How to use the Box2D's b2Draw class in Qt6 with OpenGL3? DrawSegment is not called
How to use the Box2D's b2Draw class in Qt6 with OpenGL3? DrawSegment is not called

Time:08-18

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 print hello:

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 &center, float radius, const b2Color &color) { }
void DebugDrawer::DrawSolidCircle(const b2Vec2 &center, float radius, const b2Vec2 &axis, const b2Color &color) { }
void DebugDrawer::DrawTransform(const b2Transform &xf) { }

I inherited the DebugDrawer class from the b2Draw class:

DebugDrawer.h

#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 the animationLoop() method I the m_pWorld->Step() method and I call the paintGL() method by calling the update() method. Inside of the paintGL() method I call the m_pWorld->DebugDraw() method. I expect that the DebugDrawer::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

CodePudding user response:

The DrawSegment method is not called because there is no Box2D's objects that must be drawn with segments. I add b2EdgeShape in the physics world and now DrawSegment works:

    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);
  • Related