🔒 Locked
Multi-API engine
Advertisement
Original Post
I''m trying to make a game engine that supports multiple APIs -- such as DirectX, OpenGL, ... What is the best way to approach this? The engine is organized into classes, right now I have one version of each function for each API (DSetMode() for DirectX, GSetMode() for GL), and a wrapper function that determines the current API and calls the appropriate function. However, that''s a lot more function calls than I need.
I think that the best way to achive this is through inheritance and polymorpishism (sp?). There are a number of standard software design patterns that fit excatly what you are trying to do. Google for software design patterns, I don''t remember off the top of my head but I think that the bridge pattern would suit you quite well!
Basically, you have a class, say, CMesh, that holds all the data for a mesh. Then you have another class, say, CMeshRender which is a base class. You put the API specific rendering code into children of CMeshRender, ie. CMeshDXRender or CMeshOGLRender. Then in the CMesh class you a pointer to the base class CMeshRender. Depending on if you want to render with dx or ogl you make an instance of eigther CMeshDXRender or CMeshOGLRender.
Then in the render function of CMesh you call the render method of CMeshRender. Now depending on if your CMeshRender pointer in your CMesh class points to a CMeshDXRender or a CMeshOGLRender, you will call the correct render function for that API.
Sorry if this sounds a little strange, I''m typing this off the top of my head. Feel free to ask more questions!
Then in the render function of CMesh you call the render method of CMeshRender. Now depending on if your CMeshRender pointer in your CMesh class points to a CMeshDXRender or a CMeshOGLRender, you will call the correct render function for that API.
Sorry if this sounds a little strange, I''m typing this off the top of my head. Feel free to ask more questions!
why not partition your engine into components, so that you have
a math lib, a Geometry lib and a mesh lib and a sprite lib etc then you can create an abstract way of displaying everything. You
would then need to create a driver that displays correctly
using different API''s, using the same data from the meshes and
sprites.
a math lib, a Geometry lib and a mesh lib and a sprite lib etc then you can create an abstract way of displaying everything. You
would then need to create a driver that displays correctly
using different API''s, using the same data from the meshes and
sprites.
You can store vertex and index buffer information in a buffer you allocate and then you can use API-specific classes to feed that buffer data to the individual API.
Here is a little example...
MindEngine Development
http://medev.sourceforge.net
Here is a little example...
CBuffer <- Geometry buffer (api-independent)
/\
CD3DBuffer COGLBuffer <- Feed buffer to API
MindEngine Development
http://medev.sourceforge.net
I have done this in my engine.
I simply have a CBaseRenderer class, and a CBaseTexture class.... Both of those are abstract base classes.
Each renderer defines the implementation of those two in an external dynamic library. That way, the engine is totally API independent, and the engine code does not need to be modified to add support for a new API.
I could even make a raytracing API if I wanted, without modifying the engine code
Looking for a serious game project?
www.xgameproject.com
I simply have a CBaseRenderer class, and a CBaseTexture class.... Both of those are abstract base classes.
Each renderer defines the implementation of those two in an external dynamic library. That way, the engine is totally API independent, and the engine code does not need to be modified to add support for a new API.
I could even make a raytracing API if I wanted, without modifying the engine code
Looking for a serious game project?
www.xgameproject.com
One of the problems w/making a base class w/all the base functions: I have my D3D class, w/a (sorry about all the w/s)function to get the device (GetDevice()), backbuffer (GetBackBuffer()), sprite object, and so on. The GL version has slightly different functions (i.e., no sprite). If I call functions from the base class pointer, I''ll lose a little functionality. Right now, I have a global pointer to each type of main class (GlobalGraphics, GlobalGraphicsD3D, GlobalGraphicsGL, ...).
Oh, and by the way, jwc1138, thanks for bringing up inheritance and polymorphism -- I was so caught up in my design I totally forgot there was even such thing! I think I''ll go w/a simple design of inheritance from the base classes (CGraphics, CAudio, ...), and such.
And a last question -- is there a way to get input besides from DirectInput and the message loop?
Oh, and by the way, jwc1138, thanks for bringing up inheritance and polymorphism -- I was so caught up in my design I totally forgot there was even such thing! I think I''ll go w/a simple design of inheritance from the base classes (CGraphics, CAudio, ...), and such.
And a last question -- is there a way to get input besides from DirectInput and the message loop?
In my software design class we talked a lot about seperating interface from implementation. You mentioned losing some funtionallity when using a class hierarchy. We discussed this. The best method we found to combat this problem is simplly add functions to the base class to address the functionallity gap between the to implementations and then in the implementation class that doesn''t support that functionaillty simply stub out that function and return some sort of error value that says that this implementation doesn''t have that functionaillty. This is not a great soultion, but it works.
Sorry my spelling sucks!
Sorry my spelling sucks!
Remember though there is nothing really that you can''t do in both API''s. Okay it may take a little more work to get the functionality in the other renderer but it can be done. Also in your example with sprites, what if you stub out functionality in OpenGL, but not Direct3D and your game uses sprites for the main character? Then you are making your game unusable in one of the API''s and hence you''ve lost your multiple API support.
I think that everything in your base class should be implemented by the derived classes - enforced by pure virtual functions of course. The problem with supporting multiple API''s is that in some cases it''s very hard to use some of the optimisations that the API provides since the interface is very different from another API which doesn''t provide the functionality.
I think that everything in your base class should be implemented by the derived classes - enforced by pure virtual functions of course. The problem with supporting multiple API''s is that in some cases it''s very hard to use some of the optimisations that the API provides since the interface is very different from another API which doesn''t provide the functionality.
Topic Locked
This topic has been locked by a moderator. New replies are not allowed.
Sign in to reply to this topic.
Advertisement