Adding a new parm to a GL3.0 callback function

Creative function overloading

I needed to pass a pointer to my own data to a virtual callback function in GL3.0. This article describes the fairly simple way to do this, without having to wrestle with the GL folks (i.e. Keith) to get a void * parm added for my use. (I suppose I should add at this point that Keith pointed this idea out; I just implemented it... And strictly speaking, this isn't a GL trick, just a C++ trick that seemed kinda slick.)

The GL-related problem was this:

I needed to call GetFeatureInfo() to get access to a user-defined display type, (i.e. 3584-4095, or 0x0E00-0x0FFF, as defined in the GPVF 1.0 doc). Inside CVMap::GetFeatureInfo(), if it's determined that the requested DT has a base type of "other", then GetOtherInfoHook() gets called.

GetOtherInfoHook() is a virtual function defined in CMap, whose default behavior is to do nothing. I derived CSAVMapLocal from CVMapLocal, which is in turn derived from CVMap. I was then able to override GetOtherInfoHook(), and get called with pointers to the user and text data for that grid.

The problem, then, was that I needed to pass other info along into GetOtherInfoHook(). Since I was searching for a given item in the grid, I needed to pass in the search term.

My first thought was to use a global variable. It would need to be visible to the calling code, which was in a separate source file from the CSAVMapLocal code. It would have worked, but globals are decidedly unelegant.

In the world of Windows programming, and actually in the straight C programming world as well, a commonly accepted way of doing this would be for GetFeatureInfo() to provide a void pointer to the caller, who would then pack up his data into a struct (or class) and pass it along with the other parms. GetFeatureInfo() would then treat it as a little black box, and simply pass it along to any call to GetOtherInfoHook() and any other hooks it provides. At this point, I took this idea to Keith, who, true to form, would have preferred walking over hot coals to changing the GL3.0 API, even to add a parm with a default value. (And as mentioned above, proceeded to provide the following idea, which worked quite nicely.)

The solution was this: Since I already had a CVMap-derived class, I would add another version of GetFeatureInfo() that would include a parm for my pointer. I would also add the pointer as a member of my derived class. My new GetFeatureInfo() function would do nothing more than set this pointer and call CVMap::GetFeatureInfo() as usual. When CVMap::GetFeatureInfo() gets around to calling GetOtherInfoHook(), GetOtherInfoHook() can reference the pointer as if it was a part of CVMap. And indeed, at this point, the pointer is a part of my CVMap, which is CSAVMapLocal.

As you'll see below, there is one other concern here. In CMap and CVMap, our base classes, GetFeatureInfo is virtual. The first task is to add the new function, with the extra parameter, which sets the pointer and calls the base class method. This works fine, but breaks any calls to the old, four-parm version of GetFeatureInfo(). So we add a second, virtual, four-parm version of GetFeatureInfo() that simply calls the base class method.

The relevant parts of CMap, CVMap, CVMapLocal and CSAVMapLocal are shown below:

class CLASSEXPORT CMap
   {
   .
   .
   .
public:
   virtual GLBOOL GetFeatureInfo(const SFeatureHandle& stFH,
                     SFeatureInfo* pstFI, L_POINT* plptShapePoints,
                     void* pOther);
protected:
   //This function is called by GetFeatureInfo for user-type DTs
   virtual GLBOOL GetOtherInfoHook(uSHORT usDT, void* pUserData,
                     uSHORT usUserDataSize, char* pszTextData);
   .
   .
   .
   }; //CMap

class CVMap : public CMap
   {
   .
   .
   .
public:
   // Same as in CMap [DWJ]
   virtual GLBOOL GetFeatureInfo(const SFeatureHandle& stFH,
                     SFeatureInfo* pstFI, L_POINT* plptShapePoints,
                     void* pOther);
   .
   .
   .
   }; //CVMap

class CLASSEXPORT CVMapLocal : public CVMap
   {
   .
   .
   .
   }; //CVMapLocal

class CLASSEXPORT CSAVMapLocal : public CVMapLocal
   {
protected:
   void *m_pUserHookPtr;
   .
   .
   .
   //This function is called by GetFeatureInfo for user-type DTs
   virtual GLBOOL GetOtherInfoHook( uSHORT usDT,
                                    void  *pUserData,
                                    uSHORT usUserDataSize,
                                    char  *pszTextData );
public:
   inline virtual GLBOOL GetFeatureInfo( const SFeatureHandle &stFH,
                                         SFeatureInfo         *pstFI,
                                         L_POINT              *plptShapePoints,
                                         void                 *pOther )
      {
      return ( CVMapLocal::GetFeatureInfo( stFH, pstFI, plptShapePoints,
                                           pOther ) );
      }

   inline GLBOOL GetFeatureInfo( const SFeatureHandle &stFH,
                                 void                 *pUserHookPtr,
                                 SFeatureInfo         *pstFI,
                                 L_POINT              *plptShapePoints,
                                 void                 *pOther )
      {
      m_pUserHookPtr = pUserHookPtr;
      return ( CVMapLocal::GetFeatureInfo( stFH, pstFI, plptShapePoints,
                                           pOther ) );
      m_pUserHookPtr = NULL;
      }
   .
   .
   .
   };

CSAVMapLocal::CSAVMapLocal()
   : CVMapLocal()
{
   .
   .
   .
   m_pUserHookPtr = NULL;
   .
   .
   .
}

Hosted by www.Geocities.ws

1