Archived

This topic is now archived and is closed to further replies.

Platform Independent Graphics Classes

This topic is 6107 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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

Share this post


Link to post
Share on other sites
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 here
public:
//constructor, destructor
virtual BOOL init();
virtual void destroy();

};

class OGLEngine : public IGraphics {
//ogl code here
public:
//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



Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites

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...

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Use FOX C++ GUI....

http://www.cfdrc.com/FOX/fox.html

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
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

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
DirectDraw has structures for a lot of things, but key concerns are:

Surface description strucuture
Device capabilities/description structure
Color key structure

There''s more, but u get the idea. My library, being based a lot on the DD archetecture (seeing as it is probably only ever going to be for DD, i just want to leave myself the ability to be able to port it in the future, or even upgrade it to DirectDraw9 if MS ever make it) uses similiar structures. it would be really nice if i didnt have to convert my structures to DD structures, but having thought over it for a week, i see no other way


Get Banner At: http://www.crosswinds.net/~druidgames/resist.jpg

Share this post


Link to post
Share on other sites
quote:
Original post by LordElectro

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


save yourself some( a lot ) of work
http://www.libsdl.org/

Share this post


Link to post
Share on other sites
quote:
Original post by zedzeek

[quote]Original post by LordElectro

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


save yourself some( a lot ) of work
http://www.libsdl.org/



No for two reasons:

1) I want to write my own library. That''s the point of all this, to try my hand at writing code that isn''t rooted in Windows. To show myself that it is possible, and that Bill Gates doesn''t have to be sitting there on my neck, and jumping down on my back. I want the PRACTICE. If i just cared about the graphics, I would be done by now, and have written a simple but effective set of wrapper classes for DirectDraw.

2) The particular library you pointed out is C, i need a C++ one :p

Anyway, I am gonna go the route of making my own structures too. It will keep me from being lazy but oh well


Get Banner At: http://www.crosswinds.net/~druidgames/resist.jpg

Share this post


Link to post
Share on other sites
One other method to consider is quite different; Instead of using the base class/derive class thing, create a platform and API-neutral interface for the class in your header file. Then in your source files for implementing the class for a certain API/platform, use static global variables for all of the platform or API-specific stuff. For example, your LPDIRECTDRAW stuff or HGLRC stuff, or whatever would be in there that's not neutral. Now, you're probably tempted to jump on me for even mentioning global variables. But note that I said static global variables, which means that they'll never be accessable from anywhere else. And since these source files should contain the implementation of only that class, the effect is identical to having those variables as members of that class, except that those non-neutral variables aren't exposed in the interface.

These are the advantages of this method:
- the header file isn't littered with #ifdefs and exposes only one platform and API-neutral interface
- there's no need for virtual functions since there's no need for inheritance (this will give you a bit of speed), and you can go as far as to make all functions static so there's no need to thrash around a this pointer, assuming you'll only need one instance of the class
- you still can build the implementation into a DLL and use that to choose the implementation you want to use at runtime (this negates the static function case)


Edited by - merlin9x9 on March 26, 2001 4:06:20 AM

Share this post


Link to post
Share on other sites
quote:
Original post by LordElectro

DirectDraw has structures for a lot of things, but key concerns are:

Surface description strucuture
Device capabilities/description structure
Color key structure

There''s more, but u get the idea. My library, being based a lot on the DD archetecture (seeing as it is probably only ever going to be for DD, i just want to leave myself the ability to be able to port it in the future, or even upgrade it to DirectDraw9 if MS ever make it) uses similiar structures. it would be really nice if i didnt have to convert my structures to DD structures, but having thought over it for a week, i see no other way




I think your problem is that you need to make your graphics API more "high level". Your main program shouldn''t have to deal with those structures you mentioned, except for the possible exception of the device capabilities.

As far as surface description goes, all you need to pass to your Surface class to create a new surface is the Width, Height, BPP, and Fullscreen. Your surface class would create an instance of the DDSURFACEDESC2 and fill in elements from the parameters you passed, and fill in the rest of the necessary elements by itself.

Same with color key. You could pass an RGB color variable to your surface class that just tells it the color to set the color key for your surface. The surface class would call DDSetColorKey, and pass that returned structure to SetColorKey.

For display modes, I would recommend querying all modes, and store those structures in a linked list, all done automatically by your graphics API. If your main program is just going to ask if a specific mode is available, it just calls IsDisplayModeAvailable from your graphics API, passing the width, height, bpp, etc. This function would return a bool true or false value.

If you want to retrieve all good display modes, then I would suggest creating a simple generic structure that holds the basic information needed, and you can pass the whole linked list back to the main app.

Overall, making your graphics API higher level makes it much easier to make it API independant, plus makes it easier to program with. There will be a slight performance decrease, but it''s a small price to pay for usability and maintainability.


- Houdini

Share this post


Link to post
Share on other sites