0

I am writing for a simulation that uses an old 3D model file format (Carbon Graphics' GEO, if you're interested), and the way the OpenSceneGraph plugin for this model format updates its internal variables is by you registering a callback method for the model to call when it's time to update its values. The callback has the simulation time, the variable name, and its current value. You are to return back the new value for that variable.

So, in my code, I set the callback as follows:

headerNode->setUserUpdate(&FlightDriver::updateGeoVariable);

The class headerNode belongs to has the following variable:

double (* uvarupdate)(const double t, const double val, const std::string name);

Every interval, it will call uvarupdate which I have set to:

updateGeoVariable(const double time, const double val, const std::string name)
{
    return flightData->getValue(name);
}

for each variable inside the model, one at a time. I can't make the method or the flightData member static, as they need to be unique per instance.

I have a hunch that this callback is possibly being called from C code, because when I break, it seems to have no knowledge that it is inside a class, and if I change the signature, the same three values get passed and shoehorned into whatever parameters are first.

However, I really need access to the members of the class, to avoid a really dirty kludge. Since the class itself is what drives a model in the 3D world, having 2 or more of these means that I get callbacks that say: "234, pitch, 90" and I have no way of knowing which model's variable that data belongs to.

I could possibly recompile the DLL (as it is an OSG plugin) to take additionally a pointer to that instance, or an id, or something, and return it in the callback, but I'd really like to avoid that if possible.

I've read about thunking, but it looks like that and most other ideas require access to the code that creates the callback. Any ideas?

drearyworlds
  • 341
  • 2
  • 6

1 Answers1

0

You need to pass a pointer to method, but the uvarupdate is pointer to function, these are different types. Pointer to a method contains implicit pointer to this of an instance, it doesn't fit into function-pointer. You need to pass this in some another way.

If you do not change signature of the callback, you have to calculate an instance (this) somehow. If it can be determined from name parameter, well, it's easy. Another way is to create a trampoline for each instance you have. If there are only few instances, you can write a separate trampoline function for each instance. Creating trampolines dynamically (in run-time) is tricky and non-portable: in fact, you need to write some machine instructions into RAM so that they call your method with the correct this parameter. But that's also possible, that's what some libraries do (e.g. VCL in Delphi).

nullptr
  • 11,008
  • 1
  • 23
  • 18
  • I have never heard of a trampoline. I will read up on that. Would that still require changing the signature of uvarupdate? If so, I think I'm just going to end up trying to recompile the plugin myself with the added features I need. – drearyworlds Aug 27 '13 at 21:13
  • A trampoline is a plain (non-member) function that calls a C++ method. There is no need to change signature of `uvarupdate` in this case, you just pass a pointer to a trampoline into the `setUserUpdate`. But you will need a different trampoline for each instance of class, that's how instances are distinguished. – nullptr Aug 28 '13 at 18:52