2012年7月23日 星期一

Box2D


CB的global compiler settings -> compiler settings -> Other options 填-fexceptions
#defines填FREEGLUT_STATIC
link libraries加入libFreeGLUT.a libGLUI.a GlU32(GlU32.Lib) Gdi32(Gdi32.Lib) OpenGL32(OpenGL32.Lib) User32(User32.Lib) WinMM(WinMM.Lib)
多加一個libBox2D.a
main.cpp
#include "gluiDraw.h"
#include "glui/GL/glui.h"
#include "myBox2D.h"

MyBox2D mybox2d;
GluiDraw draw;
GLint mainWindow;
GLint winWidth = 640;
GLint winHeight = 640;
int tx, ty, tw, th;
float viewCenterX=0,viewCenterY=0;
GLUI *glui;
int framePeriod = 16;
float viewZoom = 1.0f;
NeoVec2 mp,pre_mp;
bool isMouseRightPressed = false;
bool isMouseLeftPressed = false;

void Resize(int32 newWidth, int32 newHeight)
{
 winWidth = newWidth;
 winHeight = newHeight;
 GLUI_Master.get_viewport_area(&tx, &ty, &tw, &th);
 glViewport(tx, ty, tw, th);

 glMatrixMode(GL_PROJECTION);
 glLoadIdentity();
 float32 ratio = float32(tw) / float32(th);

 b2Vec2 extents(ratio * 25.0f, 25.0f);
 extents *= viewZoom;

 b2Vec2 lower(viewCenterX-extents.x,viewCenterY-extents.y);
 b2Vec2 upper(viewCenterX+extents.x,viewCenterY+extents.y);

 // L/R/B/T
 gluOrtho2D(lower.x, upper.x, lower.y, upper.y);
}

void Mouse(int button, int state, int x, int y)
{
 // Use the mouse to move things around.
 if (button == GLUT_LEFT_BUTTON)
 {
  int specialKey  = glutGetModifiers();
  if (state == GLUT_DOWN)
  {
   if (specialKey  == GLUT_ACTIVE_SHIFT)
   {
               //  cout << "GLUT_LEFT_BUTTON click with SHIFT" << endl;
   }
   else
   {
                // cout << "GLUT_LEFT_BUTTON click" << endl;
   }
  }

  if (state == GLUT_UP)
  {
               // cout << "GLUT_LEFT_BUTTON release" << endl;
  }
 }
 else if (button == GLUT_RIGHT_BUTTON)
 {
  if (state == GLUT_DOWN)
  {
      isMouseRightPressed = true;
           // cout << "GLUT_RIGHT_BUTTON click" << endl;
  }

  if (state == GLUT_UP)
  {
      isMouseRightPressed = false;
           // cout << "GLUT_RIGHT_BUTTON release" << endl;
  }
 }
}
b2Vec2 ConvertScreenToWorld(int32 x, int32 y)
{
 float32 u = x / float32(tw);
 float32 v = (th - y) / float32(th);

 float32 ratio = float32(tw) / float32(th);
 b2Vec2 extents(ratio * 25.0f, 25.0f);
 extents *= viewZoom;

 b2Vec2 lower(viewCenterX-extents.x,viewCenterY-extents.y);
 b2Vec2 upper(viewCenterX+extents.x,viewCenterY+extents.y);

 b2Vec2 p;
 p.x = (1.0f - u) * lower.x + u * upper.x;
 p.y = (1.0f - v) * lower.y + v * upper.y;
 return p;
}
void MouseMotion(int x, int y)
{
    b2Vec2 p = ConvertScreenToWorld(x, y);
    if(isMouseRightPressed)
    {
        float distanceX = p.x - pre_mp.x;
        float distanceY = p.y - pre_mp.y;
        viewCenterX -= distanceX;
  viewCenterY -= distanceY;
  Resize(winWidth, winHeight);
  p = ConvertScreenToWorld(x, y);
        pre_mp.x = p.x;
        pre_mp.y = p.y;
        glutPostRedisplay(); //要求重畫視窗
    }
    //cout << "Mouse clicked and x=" << mp.x << ",y=" << mp.y << endl;
}
void MouseWheel(int wheel, int direction, int x, int y)
{
 B2_NOT_USED(wheel);
 B2_NOT_USED(x);
 B2_NOT_USED(y);
 if (direction > 0)
 {
  viewZoom /= 1.1f;
 }
 else
 {
  viewZoom *= 1.1f;
 }
 Resize(winWidth, winHeight);
}
void Keyboard(unsigned char key, int x, int y)
{
switch (key)
 {
 case 27:
     exit(0);
  break;
    case 'a':
        mybox2d.m_bodies[2]->ApplyForce(b2Vec2(-400,0), mybox2d.m_bodies[2]->GetWorldPoint(b2Vec2(1,1)));
        break;
    case 'd':
        mybox2d.m_bodies[2]->ApplyForce(b2Vec2(400,0), mybox2d.m_bodies[2]->GetWorldPoint(b2Vec2(-1,1)));
        break;
    default:
        break;
 }
}
void KeyboardSpecial(int key, int x, int y)
{
 B2_NOT_USED(x);
 B2_NOT_USED(y);

 switch (key)
 {
 case GLUT_ACTIVE_SHIFT:
  // Press left to pan left.
 case GLUT_KEY_LEFT:
  viewCenterX -= 0.5f;
  Resize(winWidth, winHeight);
  break;

  // Press right to pan right.
 case GLUT_KEY_RIGHT:
  viewCenterX += 0.5f;
  Resize(winWidth, winHeight);
  break;

  // Press down to pan down.
 case GLUT_KEY_DOWN:
  viewCenterY -= 0.5f;
  Resize(winWidth, winHeight);
  break;

  // Press up to pan up.
 case GLUT_KEY_UP:
  viewCenterY += 0.5f;
  Resize(winWidth, winHeight);
  break;
 }
}

void drawWholeBody(b2World* world,b2Body* m_bodies[])
{
     int32 bodyCount = world->GetBodyCount();
     for(int number = 0; number < bodyCount; number++)  //扣掉地面一個body
    {
        const b2Transform& xf = m_bodies[number]->GetTransform();
        for (b2Fixture* fixture = m_bodies[number]->GetFixtureList();fixture; fixture = fixture->GetNext())
        {
            switch (fixture->GetType())
            {
                case b2Shape::e_circle:
                {
                    b2CircleShape* circle = (b2CircleShape*)fixture->GetShape();
                    b2Vec2 center = b2Mul(xf, circle->m_p);
                    float32 radius = circle->m_radius;
                    b2Vec2 axis = b2Mul(xf.q, b2Vec2(1.0f, 0.0f)); //還沒用到
                    draw.DrawSolidCircle(NeoVec2(center.x,center.y),radius,NeoVec2(axis.x,axis.y),NeoColor(1,1,1));
                }
                break;
                case b2Shape::e_edge:
                {
                    b2EdgeShape* edge = (b2EdgeShape*)fixture->GetShape();
                    b2Vec2 v1 = b2Mul(xf, edge->m_vertex1);
                    b2Vec2 v2 = b2Mul(xf, edge->m_vertex2);
                    draw.DrawLine(NeoVec2(v1.x,v1.y),NeoVec2(v2.x,v2.y),NeoColor(0,1,0));
                 }
                break;
                case b2Shape::e_chain:
                {
                    b2ChainShape* chain = (b2ChainShape*)fixture->GetShape();
                    int32 count = chain->GetVertexCount();
                    const b2Vec2* vertices = chain->GetVertices();

                    b2Vec2 v1 = b2Mul(xf, vertices[0]);
                    for (int32 i = 1; i < count; ++i)
                    {
                        b2Vec2 v2 = b2Mul(xf, vertices[i]);
                        draw.DrawLine(NeoVec2(v1.x,v1.y),NeoVec2(v2.x,v2.y),NeoColor(1,1,1));
                        draw.DrawCircle(NeoVec2(v1.x,v1.y),0.01,NeoColor(1,1,1));
                         v1 = v2;
                    }
                }
                break;
                case b2Shape::e_polygon:
                {
                    b2PolygonShape* poly = (b2PolygonShape*)fixture->GetShape();
                    int32 vertexCount = poly->m_vertexCount;
                    b2Assert(vertexCount <= b2_maxPolygonVertices);
                    b2Vec2 vertices[b2_maxPolygonVertices];
                    NeoVec2 v[b2_maxPolygonVertices];

                    for (int32 i = 0; i < vertexCount; ++i)
                    {
                    vertices[i] = b2Mul(xf, poly->m_vertices[i]);
                    v[i] = NeoVec2(vertices[i].x,vertices[i].y);
                    }
                    draw.DrawSolidPolygon(v,vertexCount,NeoColor(1,1,1));
                }
                break;
                default:
                break;
            }
        }
    }

}
void display()
{
    //glEnable(GL_DEPTH_TEST);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glPushMatrix();
    int32 bodyCount = mybox2d.m_world->GetBodyCount();
    float32 timeStep = 1.0f / 60.0f;
    int32 velocityIterations = 6;
    int32 positionIterations = 2;
    mybox2d.m_world->Step(timeStep, velocityIterations, positionIterations);
    drawWholeBody(mybox2d.m_world, mybox2d.m_bodies);
    glPopMatrix();
    glutSwapBuffers();
    glFlush();
}
void Timer(int)
{
 glutSetWindow(mainWindow);
    glutPostRedisplay(); //要求重畫視窗
 glutTimerFunc(framePeriod, Timer, 0); //Do Repeat
}
int main(int argc, char* argv[])
{
    glutInit(&argc, argv);
 glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
 glutInitWindowSize(winWidth, winHeight);
    mainWindow = glutCreateWindow("Neo Box2D");
 glutDisplayFunc(display);
    GLUI_Master.set_glutReshapeFunc(Resize);
 GLUI_Master.set_glutSpecialFunc(KeyboardSpecial);
    GLUI_Master.set_glutKeyboardFunc(Keyboard);
 GLUI_Master.set_glutMouseFunc(Mouse);
 glutMouseWheelFunc(MouseWheel);
    glutMotionFunc(MouseMotion);

 glutTimerFunc(framePeriod, Timer, 0);
 //glui->set_main_gfx_window( mainWindow );
 glutMainLoop();
 return 0;
}

myBox2d.h
#ifndef MYBOX2D_H
#define MYBOX2D_H
#include <Box2D/Box2D.h>
class MyBox2D : public b2ContactListener
{
public:
    b2World* m_world;
    b2Body* m_groundBody;
    b2Body* m_bodies[4];
 b2Joint* m_joints[8];
    MyBox2D()
    {
b2Vec2 gravity(0.0f, -10.0f);
bool doSleep = true;
m_world = new b2World(gravity, doSleep);

//宣告static物體定義
b2BodyDef staticBodyDef;
staticBodyDef.type = b2_staticBody;
//宣告dynamic物體定義
b2BodyDef dynamicBodyDef;
dynamicBodyDef.type = b2_dynamicBody;

//註冊地面(先新增shape,再利用BodyDef給出location)
//shape
b2EdgeShape groundShape;
groundShape.Set(b2Vec2(-50,0), b2Vec2(50,0));
//材質
b2FixtureDef groundFixtureDef;
groundFixtureDef.shape = &groundShape;
groundFixtureDef.density = 1.0f;
groundFixtureDef.friction = 1.0f;
//location
staticBodyDef.position.Set(0, -20);
m_groundBody = m_world->CreateBody(&staticBodyDef);
m_groundBody->CreateFixture(&groundFixtureDef);
m_bodies[0] = m_groundBody;

//球shape
b2CircleShape dynamicCircle;
dynamicCircle.m_p.Set(0.0f, 0.0f);
dynamicCircle.m_radius = 3.0f;
//location
dynamicBodyDef.position.Set(2, 20);
m_bodies[1] = m_world->CreateBody(&dynamicBodyDef);
m_bodies[1]->CreateFixture(&dynamicCircle,1.0f);


b2PolygonShape dynamicBox;
dynamicBox.SetAsBox(2, 2);
dynamicBodyDef.position.Set(0.0f, 10.0f);
m_bodies[2] = m_world->CreateBody(&dynamicBodyDef);
m_bodies[2]->CreateFixture(&dynamicBox, 1.0f);

/*
b2Vec2 vs[4];
vs[0].Set(0.7f, 0.0f);
vs[1].Set(1.0f, 0.02);
vs[2].Set(0.0f, 0.0f);
vs[3].Set(-0.7f, 0.4f);
b2ChainShape chain;
chain.CreateChain(vs, 4);
bodyDef.position.Set(0.0f, 0.0f);
m_bodies[4] = m_world->CreateBody(&bodyDef);
m_bodies[4]->CreateFixture(&chain, 0.01f);
*/
    }
 virtual ~MyBox2D()
 {
     delete m_world;
        m_world = NULL;
 }
};
#endif


gluiDraw.h
#ifndef GLUIDRAW_H
#define GLUIDRAW_H
#include <math.h>
#include <glui/GL/glui.h>
#define PI 3.141592653
const float deg2Rad = PI / 180.;
const float rad2Deg = 180. / PI;

struct NeoColor
{
    float r, g, b;
    NeoColor(){}
    NeoColor(float r_,float g_,float b_) : r(r_), g(g_), b(b_){}
    void Set(float r_,float g_,float b_) {r = r_; g = g_; b = b_;}
};
struct NeoVec2
{
    float x, y;
    NeoVec2(){}
    NeoVec2(float x_,float y_) : x(x_), y(y_){}
    void Set(float x_,float y_) {x = x_; y = y_;}
};
inline NeoVec2 operator + (const NeoVec2 &v1, const NeoVec2 &v2)
{
    return NeoVec2(v1.x + v2.x, v1.y + v2.y);
}
inline NeoVec2 operator * (float a, const NeoVec2 &v)
{
    return NeoVec2(v.x * a, v.y * a);
}

class GluiDraw
{
public:
    GluiDraw(){}
    ~GluiDraw(){}
    void DrawLine(const NeoVec2 &v1,const NeoVec2 &v2,const NeoColor &color)
    {
        glBegin(GL_LINES);
        glColor3f(color.r,color.g,color.b);
        glVertex2f(v1.x,v1.y);
        glVertex2f(v2.x,v2.y);
        glEnd();
    }
    void DrawCircle(const NeoVec2 ¢er, const float radius, const NeoColor &color)
    {
        const float segments = 16.;
        const float inc = 2 * PI / 16.;
        float theta = 0;
        glBegin(GL_LINE_LOOP);
        glColor3f(color.r,color.g,color.b);
        for (int i=0;i < segments;++i)
        {
            NeoVec2 real_v = center + radius * NeoVec2(cosf(theta),sinf(theta));
            glVertex2f(real_v.x,real_v.y);
            theta += inc;
        }
        glEnd();
    }
     void DrawSolidCircle(const NeoVec2 ¢er, const float radius,const NeoVec2 &axis, const NeoColor &color)
    {
        const float segments = 16.;
        const float inc = 2 * PI / 16.;
        float theta = 0;
        glBegin(GL_LINE_LOOP);
        glColor3f(color.r,color.g,color.b);
        for (int i=0;i < segments;++i)
        {
            NeoVec2 real_v = center + radius * NeoVec2(cosf(theta),sinf(theta));
            glVertex2f(real_v.x,real_v.y);
            theta += inc;
        }
        glEnd();
        DrawLine(center,center + (radius * axis),color);
    }
    void DrawPolygon(const NeoVec2* vertices, int vertexCount, const NeoColor& color)
    {
        glColor3f(color.r, color.g, color.b);
        glBegin(GL_LINE_LOOP);
        for (int i = 0; i < vertexCount; ++i)
        {
            glVertex2f(vertices[i].x, vertices[i].y);
        }
        glEnd();
    }
    void DrawSolidPolygon(const NeoVec2* vertices,  int vertexCount, const NeoColor& color)
    {
        glEnable(GL_BLEND);
        glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
        glColor4f(0.5f * color.r, 0.5f * color.g, 0.5f * color.b, 0.5f);
        glBegin(GL_TRIANGLE_FAN);
        for (int i = 0; i < vertexCount; ++i)
        {
            glVertex2f(vertices[i].x, vertices[i].y);
        }
        glEnd();
        glDisable(GL_BLEND);

        glColor4f(color.r, color.g, color.b, 1.0f);
        glBegin(GL_LINE_LOOP);
        for (int i = 0; i < vertexCount; ++i)
        {
            glVertex2f(vertices[i].x, vertices[i].y);
        }
        glEnd();
    }
    void DrawBox(const NeoVec2 ¢er,const float half_width,const float half_height, const NeoColor& color)
    {
        NeoVec2 list[4] = {
        NeoVec2(center.x-(half_width),center.y-(half_height)),
        NeoVec2(center.x+(half_width),center.y-(half_height)),
        NeoVec2(center.x+(half_width),center.y+(half_height)),
        NeoVec2(center.x-(half_width),center.y+(half_height))
        };
        DrawSolidPolygon(list, 4, color);
    }
};
#endif

沒有留言:

張貼留言