[Share] Box2d debug drawing for 2.0.1 (2012-06-29)

Cocos2d-x: 2.0.1 (2012-06-29)
Box2d: v2.2.0

Usage:

mWorld = new b2World(b2Vec2(0.0f, -15.0f));
b2DebugDraw *debugDraw = new b2DebugDraw(PTM_RATIO);
mWorld->SetDebugDraw(debugDraw);
uint32 flags = 0;
flags += b2Draw::e_shapeBit;
flags += b2Draw::e_jointBit;
flags += b2Draw::e_centerOfMassBit;
flags += b2Draw::e_aabbBit;
flags += b2Draw::e_pairBit;
debugDraw->SetFlags(flags);

Drawing:

ccGLEnableVertexAttribs( kCCVertexAttribFlag_Position );
kmGLPushMatrix();
mWorld->DrawDebugData();
kmGLPopMatrix();

Header:

#include "Box2D/Box2D.h"

class b2DebugDraw : public b2Draw
{
public:
    b2DebugDraw( float32 ratio );

    void DrawPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color);
    void DrawSolidPolygon(const b2Vec2* vertices, int32 vertexCount, const b2Color& color);
    void DrawCircle(const b2Vec2& center, float32 radius, const b2Color& color);
    void DrawSolidCircle(const b2Vec2& center, float32 radius, const b2Vec2& axis, const b2Color& color);
    void DrawSegment(const b2Vec2& p1, const b2Vec2& p2, const b2Color& color);
    void DrawTransform(const b2Transform& xf);
    void DrawPoint(const b2Vec2& p, float32 size, const b2Color& color);
    void DrawString(int x, int y, const char* string, ...);
    void DrawAABB(b2AABB* aabb, const b2Color& color);

private:
    cocos2d::CCGLProgram *mShaderProgram;
    GLint mColorLocation;
    float mRatio;
};

Source:

b2DebugDraw::b2DebugDraw( float32 ratio ) : mRatio( ratio )
{
    mShaderProgram = CCShaderCache::sharedShaderCache()->programForKey(kCCShader_Position_uColor);
    mColorLocation = glGetUniformLocation( mShaderProgram->getProgram(), "u_color");
}

void b2DebugDraw::DrawPolygon(const b2Vec2* old_vertices, int32 vertexCount, const b2Color& color)
{
    mShaderProgram->use();
    mShaderProgram->setUniformForModelViewProjectionMatrix();

    ccVertex2F *vertices = new ccVertex2F[vertexCount];

    for( int i=0;isetUniformLocationWith4f(mColorLocation, color.r, color.g, color.b, 1);
    glVertexAttribPointer(kCCVertexAttrib_Position, 2, GL_FLOAT, GL_FALSE, 0, vertices);
    glDrawArrays(GL_LINE_LOOP, 0, vertexCount);

    delete []vertices;

    CC_INCREMENT_GL_DRAWS(1);

    CHECK_GL_ERROR_DEBUG();
}

void b2DebugDraw::DrawSolidPolygon(const b2Vec2* old_vertices, int32 vertexCount, const b2Color& color)
{
    mShaderProgram->use();
    mShaderProgram->setUniformForModelViewProjectionMatrix();

    ccVertex2F *vertices = new ccVertex2F[vertexCount];

    for( int i=0;isetUniformLocationWith4f(mColorLocation, color.r*0.5f, color.g*0.5f, color.b*0.5f, 0.5f);

    glVertexAttribPointer(kCCVertexAttrib_Position, 2, GL_FLOAT, GL_FALSE, 0, vertices);

    glDrawArrays(GL_TRIANGLE_FAN, 0, vertexCount);

    mShaderProgram->setUniformLocationWith4f(mColorLocation, color.r, color.g, color.b, 1);
    glDrawArrays(GL_LINE_LOOP, 0, vertexCount);

    delete []vertices;

    CC_INCREMENT_GL_DRAWS(2);

    CHECK_GL_ERROR_DEBUG();
}

void b2DebugDraw::DrawCircle(const b2Vec2& center, float32 radius, const b2Color& color)
{
    mShaderProgram->use();
    mShaderProgram->setUniformForModelViewProjectionMatrix();

    const float32 k_segments = 16.0f;
    const int vertexCount=16;
    const float32 k_increment = 2.0f * b2_pi / k_segments;
    float32 theta = 0.0f;

    GLfloat             glVertices[vertexCount*2];
    for (int32 i = 0; i < k_segments; ++i)
    {
        b2Vec2 v = center + radius * b2Vec2(cosf(theta), sinf(theta));
        glVertices[i*2]=v.x * mRatio;
        glVertices[i*2+1]=v.y * mRatio;
        theta += k_increment;
    }

    mShaderProgram->setUniformLocationWith4f(mColorLocation, color.r, color.g, color.b, 1);
    glVertexAttribPointer(kCCVertexAttrib_Position, 2, GL_FLOAT, GL_FALSE, 0, glVertices);

    glDrawArrays(GL_LINE_LOOP, 0, vertexCount);

    CC_INCREMENT_GL_DRAWS(1);

    CHECK_GL_ERROR_DEBUG();
}

void b2DebugDraw::DrawSolidCircle(const b2Vec2& center, float32 radius, const b2Vec2& axis, const b2Color& color)
{
    mShaderProgram->use();
    mShaderProgram->setUniformForModelViewProjectionMatrix();

    const float32 k_segments = 16.0f;
    const int vertexCount=16;
    const float32 k_increment = 2.0f * b2_pi / k_segments;
    float32 theta = 0.0f;

    GLfloat             glVertices[vertexCount*2];
    for (int32 i = 0; i < k_segments; ++i)
    {
        b2Vec2 v = center + radius * b2Vec2(cosf(theta), sinf(theta));
        glVertices[i*2]=v.x * mRatio;
        glVertices[i*2+1]=v.y * mRatio;
        theta += k_increment;
    }

    mShaderProgram->setUniformLocationWith4f(mColorLocation, color.r*0.5f, color.g*0.5f, color.b*0.5f, 0.5f);
    glVertexAttribPointer(kCCVertexAttrib_Position, 2, GL_FLOAT, GL_FALSE, 0, glVertices);
    glDrawArrays(GL_TRIANGLE_FAN, 0, vertexCount);

    mShaderProgram->setUniformLocationWith4f(mColorLocation, color.r, color.g, color.b, 1);
    glDrawArrays(GL_LINE_LOOP, 0, vertexCount);

    DrawSegment(center,center+radius*axis,color);

    CC_INCREMENT_GL_DRAWS(2);

    CHECK_GL_ERROR_DEBUG();
}

void b2DebugDraw::DrawSegment(const b2Vec2& p1, const b2Vec2& p2, const b2Color& color)
{
    mShaderProgram->use();
    mShaderProgram->setUniformForModelViewProjectionMatrix();

    mShaderProgram->setUniformLocationWith4f(mColorLocation, color.r, color.g, color.b, 1);

    GLfloat             glVertices[] = {
        p1.x * mRatio, p1.y * mRatio,
        p2.x * mRatio, p2.y * mRatio
    };

    glVertexAttribPointer(kCCVertexAttrib_Position, 2, GL_FLOAT, GL_FALSE, 0, glVertices);

    glDrawArrays(GL_LINES, 0, 2);

    CC_INCREMENT_GL_DRAWS(1);

    CHECK_GL_ERROR_DEBUG();
}

void b2DebugDraw::DrawTransform(const b2Transform& xf)
{
    b2Vec2 p1 = xf.p, p2;
    const float32 k_axisScale = 0.4f;
    p2 = p1 + k_axisScale * xf.q.GetXAxis();
    DrawSegment(p1, p2, b2Color(1,0,0));

    p2 = p1 + k_axisScale * xf.q.GetYAxis();
    DrawSegment(p1,p2,b2Color(0,1,0));
}

Cheers.

Thanks for sharing :slight_smile:

Nikolay Osaulenko wrote:

Thanks for sharing :slight_smile:

Your welcome, Added drawing code to.

Thank you so much for this!

When I used the codes you provided,the debugdraw didn’t crash, but all the elements become bigger much more. why is it?

Actually,We only need to add following code under m_world~~>SetDebugDraw; in the constructor of Test. The crash will be OK.
code:
m_destructionListener.test = this;
m_world~~>SetDestructionListener(&m_destructionListener);
m_world~~>SetContactListener;
m_world~~>SetDebugDraw(&m_debugDraw);

uint32 flags = 0;
flags = b2Draw::e_shapeBit;
flags
= b2Draw::e_jointBit;
flags = b2Draw::e_aabbBit;
flags
= b2Draw::e_pairBit;
flags += b2Draw::e_centerOfMassBit;
m_debugDraw.SetFlags(flags);

Did you use this:

b2DebugDraw *debugDraw = new b2DebugDraw(PTM_RATIO);

With the PTM_RATIO? That could be the problem.

thanks Treon Revan for sharing it, this is what I was trying from last few days, just perfect! :slight_smile:

for those who are bit confuse with bigger outlines, do following:
uint32 flags = 0;
flags = b2Draw::e_shapeBit;
/* comment this & you will get perfect output
flags
= b2Draw::e_jointBit;
flags = b2Draw::e_centerOfMassBit;
flags
= b2Draw::e_aabbBit;
flags += b2Draw::e_pairBit;
*/
debugDraw->SetFlags(flags);

Thanks & Regards,
Paresh

I create new class b2DebugDraw, paste the code in filees, it’s ok to run, no errors, but no draw any lines on bodyes. Where do I insert the code from the “Drawing” part? I put that piece of code in the “tick” from HelloWorldScene.cpp.

You do it in Draw() method. If you don’t know what that is, you can look at the examples, or if you use the project from the template, it includes the draw() method.

Jeffrey Walraven wrote:

You do it in Draw() method. If you don’t know what that is, you can look at the examples, or if you use the project from the template, it includes the draw() method.

I am soryy,but I am new. I use template for VS2010. You mean the “b2Draw.cpp”?
.
.
.
Ok, It’s working fine now! THANK YOU!

when i addd this class in my project i got 5 errors of “use of undeclared identifier cclog”…would please help me?

@gamier champ
What version of cocos2dx are you using?

i am using cocos2d-x 2.0.1

Hello,

should this work on version 2.1.1?

I’m getting error ‘class “CCGLProgram” has no member “setUniformForModelViewProjectionMatrix()”’ with the following line:

mShaderProgram->setUniformForModelViewProjectionMatrix();

Thanks.

Ville S wrote:

Hello,
>
should this work on version 2.1.1?
>
I’m getting error ‘class “CCGLProgram” has no member “setUniformForModelViewProjectionMatrix()”’ with the following line:
[…]
>
>
Thanks.

Hello Ville S.

Try to change to:

mShaderProgram->setUniformsForBuiltins();

:slight_smile:

doesnt work. for me. compiling works. but dont see anything on screen. not sure what is going wrong. any ideas?

@hans hans

Can you provide more information. I don’t think anybody can figure it out from that unless they also have the problem. Did you use put all the code provided from Travis in the right places? Did you put this code in the Draw method?

ccGLEnableVertexAttribs( kCCVertexAttribFlag_Position );
kmGLPushMatrix();
mWorld->DrawDebugData();
kmGLPopMatrix();

Did you set the debug draw method for the world in the constructor? Please provide more information.

yep yep and yep. im trying some things, will update as it goes.

ok, heres what i do:

i have a layer that has a level object based on b2ContactListener and CCNode. this layer does the following:

this~~>level = new Level;
level~~>setParent(this);
this~~>addChild;
this~~>level~~>createPhysicalWorld;
this~~>level~~>createActions;
createPhysicalWorld is:

<pre>
void Level::createPhysicalWorld
{
world = new b2World);
world~~>SetAllowSleeping(true);
world~~>SetContinuousPhysics;
world~~>SetContactListener(this);

b2Body *dynamicBody;
b2BodyDef myBodyDef;
myBodyDef.type = b2_dynamicBody; //this will be a dynamic body
myBodyDef.position.Set(0, 20); //set the starting position
myBodyDef.angle = 0; //set the starting angle
dynamicBody = world~~>CreateBody;
b2PolygonShape boxShape;
boxShape.SetAsBox;
b2FixtureDef boxFixtureDef;
boxFixtureDef.shape = &boxShape;
boxFixtureDef.density = 1;
dynamicBody~~>CreateFixture(&boxFixtureDef);
dynamicBody~~>SetTransform, 1 );
dynamicBody~~>SetLinearVelocity( b2Vec2( 5, 30 ) ); //moving up and left 5 units per second
dynamicBody
>SetAngularVelocity( 90 * DEGTORAD ); //90 degrees per second clockwise
myBodyDef.type = b2_staticBody; //this will be a static body
myBodyDef.position.Set; //slightly lower position
b2Body* staticBody = world
>CreateBody(&myBodyDef); //add body to world
staticBody~~>CreateFixture; //add fixture to body
myBodyDef.type = b2_kinematicBody; //this will be a kinematic body
myBodyDef.position.Set; // start from left side, slightly above the static body
b2Body* kinematicBody = world~~>CreateBody(&myBodyDef); //add body to world

kinematicBody~~>CreateFixture; //add fixture to body
kinematicBody~~>SetLinearVelocity( b2Vec2( 1, 0 ) ); //move right 1 unit per second
kinematicBody~~>SetAngularVelocity; //1 turn per second counter-clockwise
}
</pre>
i.e. it creates the world and a few objects in it.

the createActions member just creates an action ´that repeatedly calls Level::update, that steps through the physics. here is level::update:

<pre>
b2DebugDraw *debugDraw = new b2DebugDraw;
uint32 flags = 0;
flags = b2Draw::e_shapeBit;
flags
= b2Draw::e_jointBit;
flags = b2Draw::e_centerOfMassBit;
flags
= b2Draw::e_aabbBit;
flags += b2Draw::e_pairBit;
debugDraw~~>SetFlags(flags);
world~~>SetDebugDraw;
debugDraw~~>SetFlags(flags);

world~~>SetDebugDraw;
world~~>Step(kSecondsPerUpdate, 8, 1);

ccGLEnableVertexAttribs( kCCVertexAttribFlag_Position );

kmGLPushMatrix();

world->DrawDebugData();

kmGLPopMatrix();

however. i just see a black screen. all of this is in android btw.

Let me get this straight, you don’t have anything on the screen? Have you tried adding a sprite to see if the display is working at all? If nothing is displaying, then you have a bigger problem.