How can I copy a shape?

Official forum for the Chipmunk2D Physics Library.
Post Reply
KIAaze
Posts: 3
Joined: Wed Sep 24, 2008 8:36 pm
Contact:

How can I copy a shape?

Post by KIAaze »

Hi,

I'm trying to implement Chipmunks in a game engine I'm working on:
http://sourceforge.net/projects/gamepower/

I want to create a class which contains the info necessary for the game engine to display it and for the chipmunks physics engine to process it, i.e. basically a sprite, a shape and a body.

Since shape and body need to be freed when the object is destroyed, I need a destructor, and therefore also a copy constructor (necessary for use of the object in vectors!) and an assignment operator.
The problem is that I need to copy the shape in the copy constructor and I can't do that since I don't have access to the cpPolyShape properties like numVerts, verts and offset.

How can I do that?
Any suggestions on design improvement are of course also welcome. :)

Here's my current code:
It currently segfaults on exit when the destructor is called

Code: Select all

#include "chipmunk/chipmunk.h"
#include "gp2d/gp2d.h"
using namespace gp2d;

#include <iostream>
using namespace std;

ostream& operator<<(ostream& a, const cpVect& b)
{
        a<<"("<<b.x<<","<<b.y<<")";
        return(a);
};

bool quit = false;

class ExitAction : public GP2DKeyAction {
public:
    ExitAction() {}
    ~ExitAction() {}
    
    void keyDown(GP2DKeyEvent& event) {
        cout << "Exiting" << endl;
        quit = true;
    }
};

void drawLine(GLfloat x1,GLfloat y1,GLfloat x2,GLfloat y2) {
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    glColor4f(0.0f, 1.0f, 0.0f, 0.5f);
    glLineWidth(5.0f);
    glBegin(GL_LINES);
        glVertex2f(x1,y1);
        glVertex2f(x2,y2);
    glEnd();
}

class GP2D_chipmunk_combo
{
    public:
	GP2DSprite sprite;
	cpBody* body;
	cpShape* shape;
	cpSpace* space;
    public:
	GP2D_chipmunk_combo(GP2DTexture* texSusi, cpSpace* a_space)
	{
	    sprite=GP2DSprite(texSusi);

	    cpVect offset=cpv(32,-32);
	    cpVect verts[] = {
		    cpv(-32,-32),
		    cpv(-32, 32),
		    cpv( 32, 32),
		    cpv( 32,-32),
	    };
	    cpFloat m=1;
	    cpFloat i=cpMomentForPoly(m, 4, verts, offset);

	    body=cpBodyNew(m,i);
	    shape = cpPolyShapeNew(body, 4, verts, offset);
	    space=a_space;

	    cpSpaceAddBody(space,body);
	    cpSpaceAddShape(space,shape);
	}
	~GP2D_chipmunk_combo()
	{
	    cpShapeFree(shape);
	    cpBodyFree(body);
	}
	
	//copy constructor
	GP2D_chipmunk_combo(const GP2D_chipmunk_combo& a_GP2D_chipmunk_combo)
	{
		cout<<"GP2D_chipmunk_combo: copy constructor called"<<endl;
// 		sprite=a_GP2D_chipmunk_combo.sprite;
		body=cpBodyNew(a_GP2D_chipmunk_combo.body->m,a_GP2D_chipmunk_combo.body->i);
//Need to figure out how to access cpPolyShape properties!
/*		cpVect verts[] = {
			cpv(-32,-32),
			cpv(-32, 32),
			cpv( 32, 32),
			cpv( 32,-32),
		};
		shape=cpPolyShapeNew(body, 4,, cpvzero);*/
	}
	//assignment operator
	GP2D_chipmunk_combo& operator=(const GP2D_chipmunk_combo& a_GP2D_chipmunk_combo)
	{
		cout<<"GP2D_chipmunk_combo: assignment operator called"<<endl;
	}

	void remove()
	{
	    cpSpaceRemoveShape(space, shape);
	    cpSpaceRemoveBody(space, body);
	}
	void setPosition(GLfloat x, GLfloat y)
	{
	    sprite.setPosition(x,y);
	    (body->p).x=x;
	    (body->p).y=y;
	}
	void setRotation_Z(GLfloat a)
	{
	    sprite.setRotation_Z(a);
	    body->a=a;
	}
	void updatePosition()
	{
	    sprite.setPosition((body->p).x,(body->p).y);
	    sprite.setRotation_Z(body->a);
	}
};

int main(void)
{
    cpInitChipmunk(); /* Actually, that's pretty much it */
    cpSpace* space=cpSpaceNew();
    space->gravity=cpv(0,-100);

    cpFloat dt=0.008;

    cpBody* staticBody = cpBodyNew(INFINITY, INFINITY);
    cpShape* bottom=cpSegmentShapeNew(staticBody, cpv(-320,-240), cpv(320,-240), 0.0f);
    cpSpaceAddStaticShape(space,bottom);

//     cpFloat dim=10;
//     int count=1000;
//     cpSpaceResizeStaticHash(space, dim, count);
//     cpSpaceResizeActiveHash(space, dim, count);

    GP2DEngine* engine = GP2DEngine::getInstance();
    engine->initAll();
    GP2DWindow* window = GP2DWindow::getInstance();
    window->setRenderMode(GP2DWindow::GP2D_OPENGL);
    window->setWindowTitle("Gamepower 2D Testing App");
    window->createWindow(640, 480, 24);
    window->setGraphicsDefaults();
    window->createNewCamera();
    GP2DInputHandler* handler = new GP2DInputHandler();
    handler->registerKeyAction(GP2DKeyEvent::GP2D_KEY_ESCAPE, new ExitAction());
    GP2DCamera* cam = new GP2DCamera(256);
    cam->setPosition(0.0f, 0.0f);
    GP2DTexture* texSusi = new GP2DTexture("susi.png");

//     vector <GP2D_chipmunk_combo> sprSusi1;
//     sprSusi1.push_back(GP2D_chipmunk_combo(texSusi,space));
//     sprSusi1[sprSusi1.size()-1].setPosition(0.0f, 0.0f);
    GP2D_chipmunk_combo S(texSusi,space);
    S.setPosition(0,0);

    GP2D_chipmunk_combo B=S;

    while(!quit) {
        handler->handleInputEvents();
        window->clearScreen();
	S.updatePosition();
	S.sprite.draw();
/*	for(int i=0;i<sprSusi1.size();i++)
	{
	    sprSusi1[i].updatePosition();
	    sprSusi1[i].sprite.draw();
	}*/
	drawLine(-320,-240,320,-240);
        window->sync();
	cpSpaceStep(space,dt);
    }

    engine->shutdownAll();

/*    cout<<"before1"<<endl;
    cpSpaceFreeChildren(space);
    cout<<"after1"<<endl;*/
//     S.~GP2D_chipmunk_combo();
    S.remove();
    B.remove();
    cpSpaceFree(space);
    return(0);
}
If you want to test it, here's how:

Code: Select all

svn co https://gamepower.svn.sourceforge.net/svnroot/gamepower gamepower
cd gamepower/GP2D-new/branches/GP2D_chipmunk_combo
make all_plus_libs
./GP2D_chipmunk_combo
gdb output:

Code: Select all

GNU gdb 6.8-debian
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i486-linux-gnu"...
(gdb) run
Starting program: /home/KIAaze/Desktop/svn_projects/gamepower/GP2D-new/branches/GP2D_chipmunk_combo/GP2D_chipmunk_combo 
[Thread debugging using libthread_db enabled]
[New Thread 0xb76176c0 (LWP 24827)]
[New Thread 0xb73e9b90 (LWP 24830)]
[Thread 0xb73e9b90 (LWP 24830) exited]
[New Thread 0xb73e9b90 (LWP 24831)]
Texture loaded (OGL): susi.png, 64x64
GP2D_chipmunk_combo: copy constructor called
Exiting
[Thread 0xb73e9b90 (LWP 24831) exited]

Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0xb76176c0 (LWP 24827)]
0xb7f75ff5 in cpSpaceRemoveShape () from ./libchipmunk.so
Current language:  auto; currently asm
(gdb) up
#1  0x0804b00a in GP2D_chipmunk_combo::remove (this=0xbfbbaf28) at GP2D_chipmunk_combo.cpp:99
99		    cpSpaceRemoveShape(space, shape);
Current language:  auto; currently c++
(gdb) up
#2  0x0804a0e0 in main () at GP2D_chipmunk_combo.cpp:181
181	    B.remove();
(gdb) up
Initial frame selected; you cannot go up.
(gdb) 
ker
Posts: 56
Joined: Tue Jul 15, 2008 4:13 am
Contact:

Re: How can I copy a shape?

Post by ker »

eh, the segfault happens because you free the body and shape TWICE

Code: Select all

    cpSpaceFreeChildren(space);
    cout<<"after1"<<endl;*/
//     S.~GP2D_chipmunk_combo();
    S.remove();
    B.remove();
remove(); frees body and shape, cpSpaceFreeChildren(space) does the same in this instance

I'd advise to never use cpSpaceFreeChildren, since that really deletes all bodies and shapes, to which you still might have pointers somewhere else.
Instead call remove() in your destructor, then free body and space

Also, try using valgrind for segfaults, its extremely perfect for those (even thou a bunch of errors valgrind tells me exist are within chipmunk :/ ^^)


Now, to your original problem:
every cpShape has an element called

Code: Select all

cpShapeKlass* klass;
(can be seen in cpShape.h:52)

cpShapeKlass has an element called type, which is of the type

Code: Select all

typedef enum cpShapeType{$
    CP_CIRCLE_SHAPE,$
    CP_SEGMENT_SHAPE,$
    CP_POLY_SHAPE,$
    CP_NUM_SHAPES$
} cpShapeType;
now you can start doing select/case constructs to know if you need cpCircleShapeNew, cpSegmentShapeNew or cpPolyShapeNew

for the values:

cast your shape to (cpCircleShape*) to get access to cpVect c (center) and cpFloat r (radius)
cast your shape to (cpSegmentShape*) to get access to cpVect a, b, n and cpFloat r (thickness)
cast your shape to (cpPolyShape*) to get access int numVerts, cpVect * verts

I'm kinda bad with c-programming (the structs are c-structs), so I really hope the casting works as I'm writing here, otherwise this'll get a mess, but I think that kind of casting happens inside chipmunk as well
[edit]
The documentation says this is bad design and will probably not be possible in the future :/
so I guess you better create direct pointers to cpCircleShape, cpSegmentShape and cpPolyShape to access your values, the other 2 shapes can always be NULL, that way you have an easy way to check what type you have
makes coding easier and less error prone anyway
KIAaze
Posts: 3
Joined: Wed Sep 24, 2008 8:36 pm
Contact:

Re: How can I copy a shape?

Post by KIAaze »

Yes, I used the cast method.
The documentation says this is bad design and will probably not be possible in the future :/
so I guess you better create direct pointers to cpCircleShape, cpSegmentShape and cpPolyShape to access your values, the other 2 shapes can always be NULL, that way you have an easy way to check what type you have
makes coding easier and less error prone anyway
What documentation are you referring to?
I only know about this one: http://files.slembcke.net/chipmunk/chipmunk-docs.html

And how should I "create direct pointers to cpCircleShape, cpSegmentShape and cpPolyShape"?
Should I use the cast method for this or should I use some low-level functions from chipmunks like cpPolyShapeInit (i.e. functions not mentioned in the html doc)?

I currently only use boxes (4-poly), but knowing the shape will probably come in handy later.

Has anybody made a C++ port of Chipmunks yet? I think this might make a lot of things easier.

P.S: Yes, I use valgrind too some times. But it's more for finding memleaks. gdb is enough for most segfault IMO.
ker
Posts: 56
Joined: Tue Jul 15, 2008 4:13 am
Contact:

Re: How can I copy a shape?

Post by ker »

:) well gdb would've told you the same

documentation2.0: http://code.google.com/p/chipmunk-physics/wiki/cpShape

direct pointers would be to have 3 pointers per ShapeClass, one for each type. The actually used type pointer would have the shape, the other 2 would be NULL

C++ wrapper: http://code.google.com/p/chipmunk-physi ... gsAndPorts
KIAaze
Posts: 3
Joined: Wed Sep 24, 2008 8:36 pm
Contact:

Re: How can I copy a shape?

Post by KIAaze »

Thanks for your help.
I downloaded the C++ wrapper and will try it out.
Post Reply

Who is online

Users browsing this forum: No registered users and 3 guests