Game Development Community

OpenGL / DirectX Wrapper Procedure ...

by Melv May · in Torque Game Engine · 04/07/2002 (12:35 pm) · 1 replies

I've been adding hardware OpenGL vertex program / shader support today.

I've gone through the code which handles the abstraction layer between the psuedo OpenGL calls that Torque uses and the subsequent code execution and I thought I would explain it here for anyone who is interested in doing the same.

When Torque starts, the platform layer attempts to add three devices, namely "OpenGL", "DirectX" and "Voodoo 2" (you can see this activity in the console window).

It then proceeds to do it's internal OpenGL command mapping. This is done by attempting to set the current device as the "$pref::Video::displayDevice" variable dictates. If this fails then "OpenGL", "D3D" and finally "Voodoo2" are tried. This may fail if the associated "$pref::Video::allow" is reset.

The setting of a device involves a call to the function 'activate(...)' from the appropriate class based upon the "DisplayDevice" class. These are "OpenGLDDevice", "D3DDevice" and "Voodoo2Device" classes.

The 'activate(...)' function of each class initialises the internal OpenGL commands by calling the common 'QGL_Init(...)' with the currently selected driver name. It's in here that the really interesting work takes place.

All the internal commands are mapped to the loaded DLL file using GetProcAddress(...). Some of the more interesting ones are the mapping of 'glGetString(...)' that allows the D3D DLL to intercept calls for 'GL_EXTENSIONS' as well as vendor information. Also 'GetProcAddress(...)' that allows the DLL to return it's internal implementation of OpenGL extensions.

After this has happened a call to 'QGL_EXT_Init' happens that maps required extensions to the DLL implementation. This way, OpenGL extensions can be used by emulating it's functionality within the other driver dlls.

All in all, quite a nice implementation although there is a tendancy for the driver to be repeatedly initialised due to the code that handles device switching during a game, which takes time.

Implementation of a new driver call requires that you define the appropriate function declarations within 'platformGL.h', a type-definition for the direct call and a subsequent function-pointer declaration of the function and a static dll declaration used for the logging system within 'winGL.cc'.

Additionally you are required to create an entry for the actual mapping (as described above) within 'QGL_Init(...)'.

This takes the form as:-
glVertex2s = dllVertex2s = (glVertexs_t) GPA_GL("glVertex2s");

if your new function is an OpenGL extension then you will additionally need to add a line within 'QGL_EXT_Init(...)' in which you can make the appropriate tests for the extension. Note that this call may actually go to the 'DirectX' or 'VooDoo2' driver and so it will need to be implemented there as well. You may also want to output to the console here to signify the status of the support to the console under the 'Enabled/Disabled Extensions' output.

It's here that you will also want to signal whether the extension or extension group was found. You can easily do this by adding your own entry within the Torque GL-State flags. You will find this structure in 'platformGL.h' (struct GLState) which has a list of supp entries. Also, if you are doing this, don't forget to add an inline dglDoesSupport function (below it) so that developers can interrogate for support.

Also, you will need to add a function which is used for logging named using the convention (gl = log). The format of this function is fairly simple but involves outputing log information followed by a call to the actual mapped DLL function. You can find these static functions in 'winGL.cc' (line 1847).

To actually implement logging functionality you do this by finding the ConsoleFunction in 'winGL.cc' (line 5391) and add two entries that redirect the internal OpenGL call to the new log function you created (which itself calls the DLL function) and redirect directly back to the DLL function.

That just about covers it, apart from the fact that implementation of OpenGL commands require the additional work of actually emulating the function in question. This is done by editing the 'OpenGL2D3D' project. In the header you are required to create an exported function prototype followed by the obvious implementation.

If you are adding 'GL_EXTENSION' support, you will need to add it to the 'glGetString(...)' command so that the standard OpenGL method of acquiring extensions is not broken. Without this the extension with never be reported as available!

Also, 'GL_EXTENSION' support requires that you also modify 'wd3dGetProcAddress(...)' to include the new function within it's switch statement. If you don't do this then you may get a valid response for support, ask for the address which returns NULL and you could then be in a bad situation if you don't check the return value.

Phew!

No-one said it was easy but hopefully this could be used as a guide. I hope I've not missed anything out as there are lots of stages.

Of course, you could just sit back and let a muppet like me do it! :)

- Melv.

#1
08/15/2003 (2:30 pm)
Thanks for the post Melv, it was just what I was looking for, still gotta check it all out and get my head around it all, but full Kudos to the muppet :o)