Sign in to follow this  

Cross-Platform Architecture

This topic is 3549 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

Hey, I'm going to write a new graphics engine, after having experimented for some years with some little game projects... I'd like to build a multi-platform and multi-api ( only in compiling ) architecture but writing only the PC/DX10 part.. ( Abstraction could be useful in future ). I've never written a multi-platform engine, and i would like to present my idea to know if i'm working well or if there're better methods to do abstraction. In my little test project i've done it this way: This is the Core class, it should be the main class of the engine, the one which has pointers to the other classes ( Renderer, etc ) and which inits the Window and the Render abstract classes with their os-specific implementation: class Core { public: Core( const char* title, short width, short height, bool windowed ); ~Core(); }; Core::Core( const char* title, short width, short height, bool windowed ) { #if EPLATFORM = EWIN32 mWindow = new WindowWin32( title, width, height, windowed ); #endif } This is the Window class: class Window { protected: Window( const char* title, short width, short height, bool windowed ); ~Window(); }; This is a Win32 Window implementation: class WindowWin32 : public Window { protected: Window( const char* title, short width, short height, bool windowed ); ~Window(); }; WindowWin32::WindowWin32( const char* title, short width, short height, bool windowed ) : Window( title, width, height, windowed ) { /** Inits the Window. **/ } Main.cpp: INT WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, INT nCmdShow ) { Core* Application = new Core( "Test Application", 640, 480, true ); //** etc etc... **/ } I don't like the fact that Core accepts some parameters for the construction of the window and it passes them to the Window class, I think it's not a clean way and there're better ones :) Please, could you help me to improve or my architecture or to write a better one ? Thanks, Bye! :)

Share this post


Link to post
Share on other sites
1) This is a big undertaking.

2) Use the Pimpl idiom, it will make your days sunny where they would otherwise be not. You'll need a well setup file-structure (file-system) to make things easy, although this step isn't too hard.

3) Seriously, this is a big undertaking. Different platforms do things differently, and your "abstract architecture" may work with WIN32 lovely, but as soon as you write the Wii implementation (or heaven forbid the DS one), you'll run into problems as soon as you try and implement the "window" class, and realise such a thing is a foreign concept to said platforms. Furthermore, different platforms require different compilers, and not all are as forgiving (or conforming) as MSVC. Whilst fixing things in your code that MSVC leniently accepts isn't much trouble (and indeed is a good thing), restructuring your code to work on CodeWarrior can be a pain. User input is also drastically different (think Wii/DS, or even a controller vs. mouse and keyboard). Keep these things in mind.

4) You're going to have to re-implement a few things from the standard library. Such a sacrosanct thing such as std::string will require rewriting for the DS to use string-tables internally to cut down on memory, as it's very limited. This is one of the few instances where reinventing the wheel is necessary. Overloading the global new and delete may also be necessary (although probably not).

5) Be really careful about how large the stack is for your platforms. This is a worser problem than dynamic memory allocation.


6) Oh, you wanted to talk about writing an abstract graphics API too? [grin]

Share this post


Link to post
Share on other sites
Thanks for the answers.
So do you suggest writing a PC-only engine ?
My original idea was to write only the PC part, but abstracting and giving the possibility of writing other implementations in the future ? Is too complex for two coders ?

Share this post


Link to post
Share on other sites
Quote:
Original post by jwein
Thanks for the answers.
So do you suggest writing a PC-only engine ?
My original idea was to write only the PC part, but abstracting and giving the possibility of writing other implementations in the future ? Is too complex for two coders ?


You could support Win32 and OSX. That would be a good introduction to cross-platform problems and their solutions.

Share this post


Link to post
Share on other sites
Hey, i'm going to write only the PC part but i've decided to try to mantain abstraction for some classes...
Please, how should i write the Window Class ? It doesn't exist in the consolles ( obviously ), so... Do you have some ideas ?
Thanks :)

Share this post


Link to post
Share on other sites
Quote:
Original post by jwein
Hey, i'm going to write only the PC part but i've decided to try to mantain abstraction for some classes...
Please, how should i write the Window Class ? It doesn't exist in the consolles ( obviously ), so... Do you have some ideas ?
Thanks :)


To be honest, if you can get a well-working cross-platform architecture on WIN32 and OSX (and for bonus points, Posix-conforming Linux), alongside a well-working graphics API abstraction, you're doing better than 90%* of people who try. And if you actually make a game with it, well that's better than 99.9999%* of people. Maybe you should disregard console support for the first four years.



*Note: Numbers are estimates and are not based upon fact

Share this post


Link to post
Share on other sites
Quote:
Original post by jwein
I know... But I don't want to add consolle support...
I want to add the possibility of future consolle support making the engine modular ...
I think it's different :)
I think one of the points people are trying to make here is that in order to leave open the possibility of support for platform X in the future, you have to have enough of an understanding of platform X that you can pull out the 'common denominators', as it were, and build them into your engine's interface from the beginning.

Anyway, I don't know that people are going to be able to tell you 'how to write the Window class', etc. This is a hard task you have in mind, one that requires a great deal of experience in software design and with the particulars of each of the platforms you wish to support.

If you're intent on it though, you might look at some existing cross-platform renderers (e.g. Ogre) and see if you can pick up a few ideas that way.

Share this post


Link to post
Share on other sites
@jwein

What's wrong with Agar? Currently only that it is built upon SDL and OpenGL and only works on platforms that support them. Version 1.4 may fix that but still you're left with the problem that there is no DirectX support except that which is provided with SDL.

You could also look into using developer tools other than Visual Studio or the Express Editions since their manifests are totally unportable to other platforms.

Cross-platform is not just a bolt-on feature for an engine. It has to be designed with cross-platform compatibility built in from the start. You should be familiar with non-PC platforms from the start if you want to design a cross-platform engine.

Also, keep track of endianness of variables that get loaded from and saved to disk accesses so that it will work on PowerPC as well as Intel/AMD.

Post back here when you have looked at some other cross-platform code.

Share this post


Link to post
Share on other sites
Hey, Thanks for the answers...
I think i'll drop the consolle support and i'll write a PC only engine ( Windows, Linux, MacOs ) writing only the PC part...
I've seen the code of ogre, but i don't understand where it switches the rendersystem specific implementations...
My problem now is that i should pass the parameters between Core and Window two times ( i've explained in the first post of this thread )...
Is there a better solution ?
PS: I' ll wrote something using templates instead of bridge, because i need it at compile time and I know the code i've written is not efficient.

Share this post


Link to post
Share on other sites
Hey, I've though i could do something similar...
ECore* Engine = new ECore()
EWindow* Window = new EWindowWin32()
Window = Engine->createWindow( parameters )
In this way the game coder could deicide what Window Implementation he want...
Is it correct ?
I' ve tried studying ogre and irrlicht but they are too complex, i want to build a smaller engine.

Share this post


Link to post
Share on other sites
Quote:
Original post by jwein
I' ve tried studying ogre and irrlicht but they are too complex, i want to build a smaller engine.

If you cut through the all the cruft on top, the core engine of either Ogre or IrrLicht is quite simple. All IrrLicht provides at a basic level is abstractions for the Window (including input), the Renderer (clears the buffer, renders triangles, sets lights), and a partial Materials/Shaders abstraction. If that sounds too complicated, then you should be using an existing engine, not making a new one.

Share this post


Link to post
Share on other sites
Yes, I' ve seen Irrlicht and now I understand it, but I don't like the fact that Irrlicht asks for window size, etc in the main function of the device ( createDevice )... I'd like to abstract the window from the engine...

Share this post


Link to post
Share on other sites
I designed a cross-platform graphics engine once. I didn't really know what I was doing when I started, so I made some mistakes. But it's been used in 5 shipped games (and counting) on every console platform of this and last generation except the DS, so I guess I did a few things right.

As for abstracting things across platforms... I did it in a way that I didn't always like, but it more or less worked. We had special folders for each platform that would only compile on that platform. So you would have two interfaces... Graphics and PlatformGraphics. The original idea was that the PlatformGraphics interface would remain the same for every platform, but the implementation would change and you'd end up with one PlatformGraphics C++ file in each of the platform subfolders. Graphics would contain stuff that didn't need to be different per-platform and would often be the only thing making calls into PlatformGraphics.

I did this with a few different classes, and what ended up happening is that a lot of platform-specific changes were made to the interface via #ifdefs. This was half sloppiness on our part and half a result of designing without forethought, but some classes ended up very very messy... because it turns out that the PSP is very different from Xbox 360 and needs to interact with things in a very different way.

An inheritance system might enforce a little cleaner interaction with your system, but you always know the platform you're working with at the time so you don't specifically need virtual function calls.

After a few years of working with that I have some better ideas for if I ever have to write another cross-platform graphics engine. But unlike some of the posters above I'm going to advise that you do try to write your own. There's no better learning experience than using something you designed and realizing exactly where it fails. Just realize that it can be very time consuming. When I wrote the first version of mine it was up and working on Xbox in a little over 200 hours of work by just one person, but we were always trying to add missing features and improve the pipeline as things came up for different games.

As for where to start abstracting, I'd say your most important abstract concept is Camera... that is a unit containing a list of meshes to draw, a unique render target, and a unique projection matrix and scissor space. The engine I work with now calls this a Scene rather than a Camera. For meshes there are a lot of important things to consider, especially how you separate things that are totally opaque and things with alpha.

Share this post


Link to post
Share on other sites
Hi, thanks for the answer...
I'm going to write a better architecture and almost any problem is solved ( for now, i know others will came :P )..
Please, could you tell me how to manage the Window in a cross-platform engine ?
My problem is consoles don't have a Window and I would like to solve the problem in an elegant way...
Thanks, Bye!

Share this post


Link to post
Share on other sites
Hey, I've though of a solution...
I could put in the Engine class a pointer to the other classes ( ex. Scene, Renderer, Window, etc... ) and some functions to init them...
Then, when i use the engine, i could do something similar in main:
Engine* engine = new Engine()
Window* window = new Window()
window = engine->create( ... )
... for PC platforms, and something similar:
Engine* engine = new Engine()
... without initializing the Window class, for consoles...
Window class is a typedef which come from some ifdefs of the different implementations...
Could this method work ?

Share this post


Link to post
Share on other sites
Maybe the consoles don't need to setup a window, but they certainly also require some initialization. For example on the PSP you have to setup a main thread, some callback functions and initialize the GU. Maybe you should write an "Init()" function that creates a window on PC's and just does some initialization on the other platforms.

Also realize that some of these platforms might not even support C++. I believe a great part of the standard library is ported for the PSP, but keep an eye on this for other consoles. Then there's also some more specific things like the PSP requiring data aligned on 16 bit boundaries, texture swizzling is required for optimal performance, you have to flush the CPU's cache in time to avoid data corruption,... You see, cross platform development is really not easy and there's many tricky little things you should look out for.

Share this post


Link to post
Share on other sites
I found useful to see the code of the WildMagic engine, along with the book "3D Game Engine Design" and on the web: www.geometrictools.com.

It is build using subsystems, so you have an Application subsystem, which handles the creation of the window and the message queue. It has different implementations for directx, opengl under windows, opengl under linux and mac.
Then there is the renderer subsystems, that handles all the API specific functions. The renderer class is abstract, and the different implementations let you use only the implementation you want.
And then there are all the other subsystems, like graphic, physics...

I'm building my own engine with an architecture like that (PC-Only) and I love it!
All subsystems procude static libraries...then if you want an app, you use the SDK
built with those libraries and the headers!

Hope it helps!

Share this post


Link to post
Share on other sites

This topic is 3549 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.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this