Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DrawSegment is not called #725

Open
8Observer8 opened this issue Aug 14, 2022 · 3 comments
Open

DrawSegment is not called #725

8Observer8 opened this issue Aug 14, 2022 · 3 comments

Comments

@8Observer8
Copy link

8Observer8 commented Aug 14, 2022

I already have created three simple examples in: Qt6, PyQt6, and SDL2. I thought that a problem in Qt6 but it the same for three cases. It looks like a bug. These examples try to print hello in the console from DrawSegment().

I expect to see hello in the console:

DebugDrawer.cpp

#include "DebugDrawer.h"
#include <iostream>

DebugDrawer::DebugDrawer()
{

}

void DebugDrawer::DrawSegment(const b2Vec2 &p1, const b2Vec2 &p2, const b2Color &color)
{
    std::cout << "hello" << std::endl;
}

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 from the b2Draw and overloaded the methods:

DebugDrawer.h

#ifndef DEBUGDRAWER_H
#define DEBUGDRAWER_H

#include "box2d/b2_draw.h"

class DebugDrawer : public b2Draw
{
public:
    DebugDrawer();

private:
    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 an object with the box shape:

    b2PolygonShape shape;
    shape.SetAsBox(50.f / WORLD_SCALE, 50.f / WORLD_SCALE);

    b2BodyDef bdef;
    bdef.type = b2_staticBody;

    pBody = pWorld->CreateBody(&bdef);
    pBody->CreateFixture(&shape, 2.f);

I set the debug draw in the main.cpp file:

    pDebugDrawer = new DebugDrawer();
    pWorld->SetDebugDraw(pDebugDrawer);

I set flags:

   uint32 flags = 0;
    flags += b2Draw::e_shapeBit;
    flags += b2Draw::e_jointBit;
    flags += b2Draw::e_centerOfMassBit;
    flags += b2Draw::e_aabbBit;
    flags += b2Draw::e_pairBit;
    pDebugDrawer->SetFlags(flags);

I call pWorld.Step() and pWorld->DebugDraw():

        pWorld->Step(0.016f, 8, 3);
        pWorld->DebugDraw();

main.cpp

#ifdef _WIN32
#include <windows.h>
extern "C" __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
extern "C" __declspec(dllexport) DWORD AmdPowerXpressRequestHighPerformance = 0x00000001;
#endif

#define SDL_MAIN_HANDLED

#include <glad/glad.h>
#include <SDL.h>
#include <box2d/box2d.h>
#include <iostream>
#include "DebugDrawer.h"

const float WORLD_SCALE = 30.f;
b2World* pWorld;
DebugDrawer* pDebugDrawer;
b2Body* pBody;

int main()
{
    // Initialize the SDL2 library
    if (SDL_Init(SDL_INIT_VIDEO) != 0)
    {
        SDL_Log("Failed to initialize the SDL2 library: %s", SDL_GetError());
        return 1;
    }

    // Create a SDL window
    const int WIN_WIDTH = 500;
    const int WIN_HEIGHT = 500;
    SDL_Window* window = SDL_CreateWindow(
        "Empty Window",
        SDL_WINDOWPOS_CENTERED,
        SDL_WINDOWPOS_CENTERED,
        WIN_WIDTH, WIN_HEIGHT,
        SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL);

    // Create a SDL renderer
    SDL_Renderer* renderer = SDL_CreateRenderer(
        window, -1, SDL_RENDERER_ACCELERATED);
    if (!renderer)
    {
        SDL_Log("Failed to create a SDL renderer %s", SDL_GetError());
        return 1;
    }

    SDL_GLContext context = SDL_GL_CreateContext(window);

    // Initialize the GLAD library
    if (!gladLoadGL())
    {
        SDL_Log("Failed to initialize the GLAD library");
        return 1;
    }

    glViewport(0, 0, WIN_WIDTH, WIN_HEIGHT);
    glClearColor(0.1f, 0.1f, 0.1f, 1.0f);

    b2Vec2 gravity(0.f, 9.8f);
    pWorld = new b2World(gravity);

    pDebugDrawer = new DebugDrawer();
    pWorld->SetDebugDraw(pDebugDrawer);

    uint32 flags = 0;
    flags += b2Draw::e_shapeBit;
    flags += b2Draw::e_jointBit;
    flags += b2Draw::e_centerOfMassBit;
    flags += b2Draw::e_aabbBit;
    flags += b2Draw::e_pairBit;
    pDebugDrawer->SetFlags(flags);

    b2PolygonShape shape;
    shape.SetAsBox(50.f / WORLD_SCALE, 50.f / WORLD_SCALE);

    b2BodyDef bdef;
    bdef.type = b2_staticBody;

    pBody = pWorld->CreateBody(&bdef);
    pBody->CreateFixture(&shape, 2.f);

    SDL_Event event;
    bool running = true;
    SDL_PollEvent(&event);

    while (running)
    {
        switch (event.type)
        {
        case SDL_QUIT:
            running = false;
            break;
        case SDL_KEYDOWN:
            switch (event.key.keysym.sym)
            {
            case SDLK_ESCAPE:
                running = false;
                break;
            }
            break;
        }

        glClear(GL_COLOR_BUFFER_BIT);

        pWorld->Step(0.016f, 8, 3);
        pWorld->DebugDraw();

        SDL_GL_SwapWindow(window);
        SDL_PollEvent(&event);
    }

    delete pWorld;
    delete pDebugDrawer;

    SDL_GL_DeleteContext(context);
    SDL_DestroyRenderer(renderer);
    SDL_DestroyWindow(window);
    SDL_Quit();
    return 0;
}
@8Observer8
Copy link
Author

8Observer8 commented Aug 14, 2022

The same example in PyQt6:

main.py

import sys

from PyQt6.QtCore import Qt
from PyQt6.QtGui import QSurfaceFormat
from PyQt6.QtWidgets import QApplication

from widget import Widget


def main():
    QApplication.setAttribute(Qt.ApplicationAttribute.AA_UseDesktopOpenGL)
    app = QApplication(sys.argv)

    format = QSurfaceFormat()
    format.setSamples(8)
    
    w = Widget()
    w.setFormat(format)
    w.show()
    sys.exit(app.exec())

if __name__ == "__main__":
    main()

widget.py

from Box2D import (b2_staticBody, b2Body, b2BodyDef, b2FixtureDef,
                   b2PolygonShape, b2Vec2, b2World)
from OpenGL import GL as gl
from PyQt6.QtCore import QElapsedTimer, QSize, QTimer
from PyQt6.QtOpenGLWidgets import QOpenGLWidget

from debug_drawer import DebugDrawer


class Widget(QOpenGLWidget):

    def __init__(self):
        super().__init__()
        self.setWindowTitle("Box2D, OpenGL3, PyQt6")
        self.setFixedSize(QSize(500, 500))
        self.deltaTime = 0

        self.WORLD_SCALE = 30.0
        self.world = b2World(gravity=b2Vec2(0.0, 9.8))

    def initializeGL(self):
        gl.glClearColor(0.2, 0.2, 0.2, 1.0)
        gl.glEnable(gl.GL_DEPTH_TEST)

        self.debugDrawer = DebugDrawer()
        self.world.renderer = self.debugDrawer

        self.debugDrawer.flags = { 'drawShapes': True,
            'drawJoints': True, 'drawAABBs': True, 'drawPairs': True }
        # print(self.debugDrawer.flags)

        shape = b2PolygonShape()
        shape.SetAsBox(50.0 / self.WORLD_SCALE, 50.0 / self.WORLD_SCALE)

        bodyDef = b2BodyDef()
        bodyDef.type = b2_staticBody

        self.body: b2Body = self.world.CreateBody(bodyDef)
        fixtureDef = b2FixtureDef()
        fixtureDef.shape = shape
        fixtureDef.density = 2
        self.body.CreateFixture(fixtureDef)

        self.timer = QTimer()
        self.timer.timeout.connect(self.animationLoop)
        self.elapsedTimer = QElapsedTimer()
        self.elapsedTimer.start()
        self.timer.start(1000//60)
    
    def paintGL(self):
        gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT)
        self.world.DrawDebugData()
    
    def resizeGL(self, w: int, h: int):
        gl.glViewport(0, 0, w, h)

    def animationLoop(self):
        self.deltaTime = self.elapsedTimer.elapsed() / 1000.0
        self.elapsedTimer.restart()
        self.world.Step(self.deltaTime, 8, 3)
        self.update()

debug_drawer.py

from Box2D import b2Draw


class DebugDrawer(b2Draw):

    def DrawSegment(self, p1, p2, color):
        print("hello")

    def DrawSolidPolygon(self, vertices, color):
        pass
    def DrawPoint(self, p, size, color):
        pass
    def DrawPolygon(self, vertices, color):
        pass
    def DrawCircle(self, center, radius, color, drawwidth=1):
        pass
    def DrawSolidCircle(self, center, radius, axis, color):
        pass
    def DrawTransform(self, xf):
        pass

@8Observer8
Copy link
Author

8Observer8 commented Aug 14, 2022

The same example in Qt6 and C++:

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();
}

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

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();
}

.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

@8Observer8
Copy link
Author

8Observer8 commented Aug 15, 2022

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 of b2EdgeShape is created:

C++:

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

Python:

        edgeShape = b2EdgeShape()
        edgeShape.vertices = [(0.0, 0.0), (1.0, 0.0)]
        self.edgeBody: b2Body = self.world.CreateBody(bodyDef)
        edgeFixtureDef = b2FixtureDef()
        edgeFixtureDef.shape = edgeShape
        edgeFixtureDef.density = 2
        self.edgeBody.CreateFixture(edgeFixtureDef)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant