Platform Independent Graphics Classes

Started by
15 comments, last by LordElectro 23 years ago
Okay, I''m writing some classes for DirectDraw. Or at least I was. Ever since I got into the habit of thinking about ''m gonna do before I write, and even writing plans and other nonsense I have been more thoughtful in the way I structure my code. I looked through my DirectX6 code, looking at how much differently various parts of the API are done in 7/8 than in 6. That''s why I had to start the project of rewriting my classes in the first place. When DX9 comes out, I''ll have to rewrite classes for it too (though i don''t know if I''ll be using DirectDraw anymore, I might because i think 3D graphics are rather ugly, but with the way 3D technology is going, they are slowly starting to near the detail of a good old fashioned sprite, with much more flexibility). And so on. So I figure, why not try and make a set of classes that are API independent, and then just use a API specific implementation for the API i will be using. I am really bent on making this thing portable, mainly cuz i want to test myself. I doubt I''ll ever have the urge to port any of my code to Linux, BeOS, or even OS/2 but hell with it. Anyway, here''s what I have so far. My classes use the same basic structure as DirectDraw, just so writing a DD implementation won''t be too hard. Plus i like the way DD is setup, minus the excessive amount of work it takes to setup anything. So I have a CGDisplay that will work like the DirectDraw object, a CGSurface that will work like DirectDrawSurface, etc. Now when I want to use a DirectDraw version of the classes, I just write a CGDisplayDD class and have it inherit from CGDisplay. So far so good, works pretty well. But what about structures that DD uses that are DD specifc? Like DDCAPS and DDSURFACEDESC2? Actual game code will need to manipulate the information in these structures, but I really dont want to have to change any game code to use a different graphics API. I just want to plug in a different implementation of my classes. I can''t think of any good way to get platform independent structures without making my own, and then incurring the performance penalty and more importantly, programming time waste of converting a certain API specific structure to my version of it. I could theoritcally have a function inside the implementations that coverts a non-API struct to an API struct and a function for vice versa. Wouldn''t take too much longer I guess, but is this the way to do it? Seems not the best way.... Btw, please don''t suggest using COM. From what i hear, .NET is gonna say COM is a big no no and then replace it with something else, and I dont want to learn technology that is on its way out when I am already burdening myself with learning a tonne of new stuff. Plus DirectX uses COM, and well, * shudder *
Get Banner At: http://www.crosswinds.net/~druidgames/resist.jpg
BetaShare - Run Your Beta Right!
Advertisement
LordElectro:

Well I''m sort of doing something similar myself, I''m just not making it platform independent..

But I can give you some help (hopefully)..you MAY want to consider making your base classes, pure virtual ones. In fact you''ll probably HAVE to...

class IGraphics {public: IGraphics(){}; virtual ~IGraphics(){};  virtual BOOL init() = 0; //pure virtual function virtual BOOL destroy() = 0; //another p.v. function};

Now you can derive classes (classes containing pure virtual
functions CANNOT be themselves instantiated) from IGraphics..

In my code, I implement the derived classes into 2 Win32 DLL''s...one for OpenGL, one for Direct3D...so at runtime, you
can just drop in the module you need, avoiding the normal static
linking stuff..._

So in the user''s code (using your library), they only need to
know the base classes functions to use your methods...

class D3DEngine : public IGraphics {//d3d code herepublic:  //constructor, destructor  virtual BOOL init();  virtual void destroy();};class OGLEngine : public IGraphics {//ogl code herepublic:  //constructors, etc here..  virtual BOOL init();  virtual void destroy();};//now in your game code you''d have something like...IGraphics *myGraphics;//now select which one to use (ie. which DLL to load up)switch(engine_needed){   case OPENGL:        myGraphics = new &OGLEngine        break;   case D3D:        myGraphics = new &D3DEngine        break;}//now we want to initialize our engine//because our base class is a pure virtual one,//any methods we call, will now in effect, be //directed to our selected engine''s implementation//of the virtual functions..myGraphics->init();


So we are kind of using the same design approach as COM, but
not implementing the #@$#@ up version by MS..

I hope this helps...hell I just hope I''m on the right track with my implementation..

Wazoo



Learn about game programming!Games Programming in C++: Start to Finish
That''s what I''m doing. I have a pure virtual base class, for example CGDisplay. Then for the DirectDraw version i have CGDisplayDD.

Now here''s some code, not guarenteed to by syntax correct im just typing it out right now, not pasting out of anywhere specific.

CGDisplay *MyDisplay;

MyDisplay = new CGDisplayDD;

Now if i want to use some sort of Linux thing, all i do is change the code to MyDisplay = new CGDisplayLinux where CGDisplayLinux is a Linux implementation of CGDisplay. So far so good. But the problem im running into, and the one u probably will, is a result of wanting for a slight more bit of performance, and sheer laziness. DirectDraw has some nice structures that it uses for passing the obese amount of parameters a function like CreateSurface needs. Now, I would prefer if i could use these structures, since I think that for the most part they are pretty good. Plus then I can pass the info straight to the functions in my class, instead of using my own structures, then converting them to DD structures in the CGDisplayDD functions, and then passing the stuff onto DD.

Seems to be a hell of a lot of extra work. Is there anyway I can make my code make use of those structures, without it automatically requiring the DirectX SDK even when im not using a DD implementation of the classes?




Get Banner At: http://www.crosswinds.net/~druidgames/resist.jpg
BetaShare - Run Your Beta Right!
ahhhhh I see where you''re going..

Well I thought of that from the outset of my design as well, and I still don''t know what the "correct" answer is...

My decision was to implement things in both Directx and OpenGL (in my two derived classes from IGraphics) and just use their own fastest implementations of stuff....

ie. When you''re using the Direct3D implementation, it takes advantage of EVERYTHING I can find to optimize Direct3D performance..whether it be vertex buffers, index buffers, etc...

the same thing for OpenGL..

Mind you, I''m only doing a 2d engine right now, so perhaps later when I port it to 3d, I''ll have to change a few of the classes around...(ie. when I think of models and 3d animation, etc..)

I don''t think there''s an easy answer here Electro...MAYBE a possible way to think about it, is that when someone uses your platform independent library, they''re running ON a platform. So if you designed your classes the pure virtual way, just have a Linux implementation, DirectX (win32) implementation and an OpenGL implementation, and optimize for each of the platforms...I mean if you''re running your library on Linux, you''d want everything as optimized for Linux as possible, rather than a "generic" Linux graphics library which DOES run everywhere but sucks ass...am I right??

That''s my 2cents of it anyhow...

Wazoo
Learn about game programming!Games Programming in C++: Start to Finish
I just wanna be able to port a game without having to change code that isn''t directly responsible for graphics. I dont want to hunt down all the lines where I''m creating surfaces or blting stuff to them. Maybe I''ll just go with OpenGL, since it has support for multiple platforms. It''s a less than ideal solution, but it would spare me a lot of work.


Get Banner At: http://www.crosswinds.net/~druidgames/resist.jpg
BetaShare - Run Your Beta Right!
I think you need to remember that your code will not be running on Win/Linux in the same binaries.

I just set up a conditional compile, so that if it's compiling on Win32, it uses the windows set of header files (and VC++ compiles/links the correct source files), but if (not tested yet!) I were to compile them on Linux, I would just add a clause to the condtional header inclusion, and add the correct source file to the makefile.

    #ifdef WIN32#include <Win32Core.h>#elseifdef LINUX#include<LinuxCore.h>#elseifdef BEOS#include<BEOSCore.h>#endif    


And of course, you need to set up the project and makefiles as well....

As long as you can design using OOP even half decently, this approach works great!

[edit] Added example (I give up on the formating. You get the idea)[/edit]

Edited by - mr_jrt on March 22, 2001 6:10:00 AM
Waassaap!!

I have been thinking about platform/API independence a bit lately, and I have come to conclusion that virtual classes will only cause problems with portability.

They way I think of it, I have "basic" GfxDev-class (video mode, backbuffer (no access to frontbuffer, ever!), and basic drawing; lines, recs, sprites, software textures etc).
To access pixels (in backbuffer, texture, sprite or whatever) I use generic PixelBuffer class.
For 3D, I implement a "sub"class, GfxDev3D or something like that, which contains most (if not all) of the 3D pipeline.

Okay, doesn''t sound very portable, yet... Here''s the trick, however: All basic engine classes (GfxDev, GfxDev3D, PixelBuffer, Pixel, Image, Tri, TriList ... ) define only the API of system. The implementation may vary; GfxDev3D may contain software, directx, opengl or whatever - it''s completely transparent.

Now, for some programmers out there this won''t work; I you do can''t sit down and PLAN the API PROPERLY before starting to write code, this is an hopeless effort. Also, you need to understand that this kind of system is a tradeoff between portability and speed; you need to give up the control and can''t anymore call, say, DrawPrimitive directly. A year ago that would have been impossible for me, but guess I have matured a bit since then... Again, with proper initial design most of the speed penalties of this system are minimal. So you want to call DrawPrimitiveVB(...)? Why not gfxdev3D->render(m_trilist) instead? The speed penalty actually *is* next to none...

Oh, and later on, when I need it, I will implement similar system to sound and controls...

~~~ "'impossible' is a word in the dictonary of fools" --Napoleon
i dont think u guys *quite* get what i mean. I''ll try one more shot at explaining, here goes

My approach, on paper at least, works beautifully and will result in a perfectly platform independent *game* assuming u write an implementation of the graphics library for each API u want the game to run on. So about a week or so of work. I intend to stay away from Win API functions, except in the map editor, which for now will have to be Windows only, but boo hoo. Now, functions and stuff work fine, but when i want to pass data to a function through a structure, or receive such data, i cannot use the DirectX (or other APIs'') structures. This kinda ticks me off, because first off, i have to re-invent the wheel and make my own structures that are more or less the same as the DirectDraw ones. Then i have to write and more importantly, call functions that convert my graphics library structures to API specific structures. I was hoping there is a better solution for this, but no one has really jumped up and slapped me about my approach, so im guessing im forced to do this. It''s not terribly bad, since stuff like blt doesnt need structures passed to it, but it IS an annoyance.

Anyway thanks, and i welcome (demand actually) any feedback on this appraoch.


Get Banner At: http://www.crosswinds.net/~druidgames/resist.jpg
BetaShare - Run Your Beta Right!
Use FOX C++ GUI....

http://www.cfdrc.com/FOX/fox.html
quote:Original post by LordElectro

My approach, on paper at least, works beautifully and will result in a perfectly platform independent *game* assuming u write an implementation of the graphics library for each API u want the game to run on. So about a week or so of work. I intend to stay away from Win API functions, except in the map editor, which for now will have to be Windows only, but boo hoo. Now, functions and stuff work fine, but when i want to pass data to a function through a structure, or receive such data, i cannot use the DirectX (or other APIs'') structures. This kinda ticks me off, because first off, i have to re-invent the wheel and make my own structures that are more or less the same as the DirectDraw ones. Then i have to write and more importantly, call functions that convert my graphics library structures to API specific structures. I was hoping there is a better solution for this, but no one has really jumped up and slapped me about my approach, so im guessing im forced to do this. It''s not terribly bad, since stuff like blt doesnt need structures passed to it, but it IS an annoyance.



LordElectro, it''s been a while since I''ve used DirectDraw, but what kind of structure do you need to pass to your DirectDraw graphics API? Can you give an example?


- Houdini

This topic is closed to new replies.

Advertisement