Force Callback not being called...

OvermindDL1

02-04-2006 13:43:30

I have a setup as such:

class Spawnable
{
// Some other declarations here as well...

void init()
{
// Some other stuff here first to set things up

m_Entity = createVisibleEntity();
m_SceneNode->attachObject(m_Entity);

m_PhysBody = createPhysBody();
m_PhysBody->attachToNode(m_SceneNode);
m_PhysBody->setUserData(this);
m_PhysBody->setPositionOrientation(m_Position, Quaternion(Radian(0.0f),m_Direction));
m_PhysBody->setCustomForceAndTorqueCallback(fastdelegate::MakeDelegate(this, &Spawnable::forceCallback));first
}

virtual Ogre::Entity *createVisibleEntity(void) = 0;
virtual OgreNewt::Body *createPhysBody(void) = 0;

virtual void forceCallback(OgreNewt::Body* me); // does basic gravity
}

// And any class that inherits from it, for example my hovering vehicle:
class HovererBase
{
// Some other declarations here as well...

virtual void forceCallback(OgreNewt::Body* me)
{
// I call the base function and do some moving calculations and forces here as well as calling the buoyancy callback below using addBouyancyForce()
}

virtual bool buoyancyCallback(int colID, OgreNewt::Body* me, const Ogre::Quaternion& orient, const Ogre::Vector3& pos, Ogre::Plane& plane);
}


Problem is, only the base's forceCallback() is called, never the overridden one. I didn't have a problem when I had ogrenewt using boost::function doing this same thing before I updated to using the cvs' fastdelegate, so I assume I'm doing something wrong on the "m_PhysBody->setCustomForceAndTorqueCallback" line. Any help?

EDIT: I copied in my old copy that used boost::function and recompiled ogrenewt, the app runs perfect then. I must be doing something wrong with fastdelegate, anyone know how to use the thing, can't seem to figure it out, won't compile if I use a functor, doesn't work with virtual methods, am I missing a command?

walaber

06-04-2006 01:44:27

i'm not sure, but the full explanation of fast delegate can be found at:
http://www.codeproject.com/cpp/FastDelegate.asp.

OvermindDL1

06-04-2006 06:49:20

Hmm, upon reading that it only supports a small subset of what boost::function supports, which do not include functors and the like, has the syntax for virtual functions though.

Why not use boost::function, it makes the *exact* same assembly code, except it also checks that the pointer is valid before it calls it unlike fast delegate (so you don't need to check it yourself), which are only two extra asm calls...

walaber

06-04-2006 17:19:16

i chose fastdelegate because it is a drop-in replacement that requires no changes to existing OgreNewt code, but also allows more advanced member-function binding if the user desires.

apparently it has some functionality missing when compared to the boost solutions... if we switch to boost, will all existing code (just passing a pointer to a static function) still work?

if you can convince me why boost is better, and it will work without breaking everypne's code, I will definately consider it.

OvermindDL1

07-04-2006 00:19:00

The onyl code change required will be to remove the fastdelegate keywords (although you could make a fastdelegate namespace that imports the boost namespace so not even those would need to be changed), change up your code a little to take boost instead of fastdelegate (simple search/replace as they have the exact same syntax), and preferably, but not necessary, change the things of
if(functionPointer) functionPointer(/*whatever*/);
into try/catch's instead (boost design, although you can leave the if in there, it adds two unnecessary asm codes whereas the try/catch does not unless it is actually called, which will only occur if the pointer is null, which it should not be from what I've seen of you code).

Technically you could just change the word fastdelegate into boost everywhere and change the typedef lines and it would still work fine.

As for the assembly generation, if you have a pointer that is void(class *pointer), then fastdelegate will generate 3 codes that will always be called, one to push the pointer, one to push the function, one to call, boost does has an extra two, to make 5 in this example (although I am pretty sure it can be reduced to three with a define if you really wanted the extra two instructions), the extra two is just a compare to make sure the pointer is not null, and a jump, so if it is null, it throws an exception, if it is not null it then does the same thing as fastdelegate.

Not to mention, boost::function has already been accepted as a standard class into the next version of C++ due out in 2009; boost::bind is also accepted in, replacing std's current bind_1st and bind_2nd.

In the original thread this was discussed I showed the assembly code that both generate if you wish to see them.

walaber

07-04-2006 21:35:36

more than the assembly code, I just want to make sure that people with old code using static function pointers will not have to change their code at all... obviously fast delegate can do this...

if boost can also do it, and is more widely accepted / fully featured, than we can switch.

I don't care about changing the OgreNewt code a bit, that's no problem. I just want to make sure user's existing code will still compile properly.

OvermindDL1

07-04-2006 23:50:18

Boost::Function is made to be used identically like function pointers (as is fastdelegate), so if anyone passes a normal static function, not a single change is needed (as I showed in my examples on that other thread). The *only* changes that are necessary to users of the callbacks is if they have something like "m_PhysBody->setCustomForceAndTorqueCallback(fastdelegate::MakeDelegate(this, &Spawnable::forceCallback));", that would need to be changed to something like "m_PhysBody->setCustomForceAndTorqueCallback(boost::bind(&Spawnable::forceCallback, this, _1));", or if you used the wrapper as I gave in the other thread, it would be "m_PhysBody->setCustomForceAndTorqueCallback<>(&Spawnable::forceCallback, this);".

walaber

08-04-2006 01:39:11

okay, in that case I am OK with switching over to boost before too many people get used to fastdelegate.

may I request again that the necessary code be packaged up and sent to me?

OvermindDL1

08-04-2006 09:28:00

Sure, will post up this weekend (after work Saturday I will have time).

EDIT: Went ahead and made it. My post with it is here, and the direct link to the archive is here.

Just extract into the OgreMain folder, overwriting the current files. This is built off of the latest anon cvs (just updated). It also includes a bit of a portion of boost, it can certainly be trimmed down if you wanted. I changed the documentation on that one callback to show how to bind with boost using the normal method and my wrapper method.

praetor

10-04-2006 15:44:09

boost's function and bind libraries support everything FastDelegate has and more. They are much more powerful. I use boost extensively, and prefer it for many tasks. The difference between the two is that FastDelegate avoids heap allocations at ALL costs. This is the source of its limitations. Heap allocations are slow compared to stack allocations, which is the source of the name FASTDelegate. How much faster or slower I haven't done any performance comparisons. I use boost::function extensively and I hope it doesn't turn out to be a mistake. I image the only time the difference would show itself is when many many bindings are being generated each frame. Use of the resulting bound functions should always be fast. So, maybe just try to avoid creating functors over and over.

OvermindDL1

10-04-2006 22:42:01

I've tested. Both fastdelegate and boost::function generate identical assembly for static functions and 'bind'ed functions, plus two more calls for making sure it is not an invalid pointer (can probably be disabled with a define before including boost::function). It will, however, generate a bit more for functors and such (not worth noticing since fastdelegate does not support them at all). I've posted the assembly they generate in the other thread.

walaber

11-04-2006 05:48:02

okay I finally got around to applying your changes. so far so good, but the buoyancy demo will not compile after making the necessary changes to the code.

here's what I changed to code to for the addBuoyancy part:

// also don't forget buoyancy force.
// just pass the acceleration due to gravity, not the force (accel * mass)!
me->addBouyancyForce<OgreNewtonFrameListener>( 0.7, 0.5, 0.5, Ogre::Vector3(0.0f,-9.8f,0.0f), &OgreNewtonFrameListener::buoyancyCallback, this );


but I'm getting some compiler errors. all of the other demos (after adjusting the code) compile fine. can you get the buoyancy demo to compile? what might I be doing wrong?

OvermindDL1

11-04-2006 20:17:01

okay I finally got around to applying your changes. so far so good, but the buoyancy demo will not compile after making the necessary changes to the code.

here's what I changed to code to for the addBuoyancy part:

// also don't forget buoyancy force.
// just pass the acceleration due to gravity, not the force (accel * mass)!
me->addBouyancyForce<OgreNewtonFrameListener>( 0.7, 0.5, 0.5, Ogre::Vector3(0.0f,-9.8f,0.0f), &OgreNewtonFrameListener::buoyancyCallback, this );


but I'm getting some compiler errors. all of the other demos (after adjusting the code) compile fine. can you get the buoyancy demo to compile? what might I be doing wrong?


I havn't recompiled that demo. I'll check my code this evening (or if I can TS into home if I get a moment here at work). Knowing my luck, I forgot something. >.>

EDIT: TS'ed in, found the problem. The bouyancy callback does not take 1 paramater, it takes 4. On line 382 (I think), you see the "instancedClassPointer, _1) );", change it to "instancedClassPointer, _1, _2, _3, _4) );". That should fix it. And, my comments on lines 155/156/157, I forgot to say put the classname in between the <>. That should fix it.

walaber

12-04-2006 01:35:22

cool, that fixed it. it's actually a 5-parameter function, so I added a "_5" to the end, and got it to compile. I fixed the templates for the other functions as well to reflect their number of parameters.

I will do a little more testing tonight, and then update CVS if all goes well.

OvermindDL1

12-04-2006 20:42:03

It's 5? Could of sworn it was 4, it compiled with 4 params. And didn't the others in Body only have 1 param?

walaber

13-04-2006 00:28:15

ForceAndTorque has 1 void(Body*)
Transform has 3 void(Body*, const Vector3&, const Quaternion& )
AutoActivate has 2 void(Body*, int)
Buuoyancy has 5 bool(int, Body*, const Vector3&, const Quaternion&, Plane&)

I made the necessary changes, and it seems to be working great. I will update CVS tonight.

OvermindDL1

13-04-2006 00:51:07

Ah, heh, sorry about that, was at work when I did it and if I am at work, working on something non-work related, it takes a backseat in my mind. >.>