Sign in to follow this  
Dae

Switch between D3D and OGL

Recommended Posts

Dae    160
I'm sorry if there are topics on this. I did a search and found some information, but not much. I wanted to initially set the structure of my engine up so that I could switch between OGL and D3D on the fly. I know that my program would have to be structured well, and I might need to use a few if/else statements somewhere to see if the program is running D3D or OGL. This is basicly what I'm trying to accomplish:
#include <iostream>

namespace D3D {

class CFramework
{
private:

protected:

public:
	CFramework() {}
	void Draw() { std::cout << "D3D Draw();" << std::endl; }
};

}

namespace OGL {

class CFramework
{
private:

protected:

public:
	CFramework() {}
	void Draw() { std::cout << "OGL Draw();" << std::endl; }
};

}


class CFramework
{
private:
	enum libChoice {D3D, OGL};
	libChoice lib;

protected:

public:
	D3D::CFramework*    m_pD3DFrame;
	OGL::CFramework*    m_pOGLFrame;

	CFramework()
	{
		lib = D3D;
		if(lib == D3D)
			m_pD3DFrame = new D3D::CFramework();
		else if(lib == OGL)
			m_pOGLFrame = new OGL::CFramework();
	}
};
           


int main()
{
    CFramework* frame = new CFramework();
	
	//frame->m_pD3DFrame->Draw();
    frame.Draw();

    std::cin.get();
    
    return 0;
}
frame.Draw() doesn't work of course, that was just an idea, but wouldn't be a good idea because I'd have to make a function in that framework that D3D and OGL have. That or I have the instance of my choice, D3D or OGL, returned to me and I call Draw() from that. How would I get that working? or would I be forced to use if/else statements everywhere, or would I be able to if they were derived from the same hierarchy? Thanks for any info. :)

Share this post


Link to post
Share on other sites
Bezben    202
You could create a common interface class:

class IFramework
{
public:
void Draw( void ) = 0;
void Release( void ) = 0;
};

Them make your concrete versions:

class D3DFramework : public IFramework
{
public:
void Draw( void ) {cout << "D3D" << end;}
void Release( void ) {delete this;}
};

class OGLFramework : public IFramework
{
public:
void Draw( void ) {cout << "OGL" << end;}
void Release( void ) {delete this;}
};

etc...

Then make a loader function:

enum libChoice {D3D, OGL};

IFramework* GetFramework( libChoice lib )
{
if(lib == D3D)
return new D3DFramework();
else if(lib == OGL)
return new OGLFramework();
}


int main()
{
IFramework* frame = GetFramework( D3D );

frame->Draw();
std::cin.get();

frame->Release();
return 0;

}


And trust me when I say this, it'll take a hell of a lot of work to make decent wrappers.

Share this post


Link to post
Share on other sites
Dae    160
Haha, alright thanks man. Its too bad theres no like generic pointer that would point to D3D or OGL even though they are different classes. Deriving them from the same class works.. but eh wouldn't that be a little high maintenance.

If anyone knows of another way too I'd really appreciate it! :)

Share this post


Link to post
Share on other sites
Bezben    202
If that were the case we'd only have one api...

My version runs to a class interface with about 60 odd methods, but that included texture/vertex and index buffers/pixel and vertex shaders. And it took bloody ages. A simple version with simple texture primitives wouldn't take too long to write.

Share this post


Link to post
Share on other sites
Dae    160
How does that mean we'd only have one api?

Thanks for the help again, this is much more fun than c to f programs ;)

I had to get some help with this in IRC, and I've modified it a bit. It was recommended that I use an ADT (I think), and have a Mutex because the Instance() method wasn't safe. I think its coming along okay at least. If anyone comes across this topic (like I came across others) and wants to see more code.

#include <iostream>
#include <vector>
#include <windows.h>

class CMutex
{
private:

protected:

public:
HANDLE Create();
bool Lock(HANDLE);
bool Unlock(HANDLE);
};

HANDLE CMutex::Create()
{
HANDLE hMutex = 0;

// Create a mutex with no initial owner.
hMutex = CreateMutex(
NULL, // default security attributes
FALSE, // initially not owned
NULL);

if (hMutex == NULL) {
std::cout << "CreateMutex error: \n" << GetLastError() << std::endl;
} else {
if (GetLastError() == ERROR_ALREADY_EXISTS) {
std::cout << "CreateMutex opened existing mutex. \n" << std::endl;
} else {
std::cout << "CreateMutex created new mutex. \n" << std::endl;
}
}

return hMutex;
}

bool CMutex::Lock(HANDLE hMutex)
{
DWORD dwWaitResult;

// Request ownership of mutex.

dwWaitResult = WaitForSingleObject(
hMutex, // handle to mutex
5000L); // five-second time-out interval

switch (dwWaitResult) {
// The thread got mutex ownership.
case WAIT_OBJECT_0:
return true;

// Cannot get mutex ownership due to time-out.
case WAIT_TIMEOUT:
return false;

// Got ownership of the abandoned mutex object.
case WAIT_ABANDONED:
return false;
}

return true;
}

bool CMutex::Unlock(HANDLE hMutex)
{
if (!ReleaseMutex(hMutex)) {
// Deal with error.
return false;
}
}

CMutex* Mutex = new CMutex;

//extern CMutex* Mutex;

class D3DFramework;
class OGLFramework;

//C*class name* = Class
//A*class name* = Abstract Class

class ARenderSystem
{
private:

public:
virtual void Draw(void) = 0;
virtual void Release(void) = 0;

};

class CSystem
{
private:
enum libChoice {D3D, OGL};
static libChoice lib;

static ARenderSystem* m_aRender;
static CSystem* m_cInstance;
static std::string m_sClassName;

protected:
CSystem() {}

public:
void SwitchRenderSystem();

static ARenderSystem* Render();
static CSystem* Instance();
};

CSystem* CSystem::m_cInstance = 0;
ARenderSystem* CSystem::m_aRender = 0;
CSystem::libChoice CSystem::lib = D3D;
std::string CSystem::m_sClassName = "CSystem";

namespace D3D
{

class CRenderSystem : public ARenderSystem
{
public:
virtual void Draw(void) { std::cout << "D3D" << std::endl; }
virtual void Release(void) { }
};

}

namespace OGL
{

class CRenderSystem : public ARenderSystem
{
public:
virtual void Draw(void) { std::cout << "OGL" << std::endl; }
virtual void Release(void) { }
};

}

ARenderSystem* CSystem::Render()
{
if(m_aRender == 0)
if(lib == D3D)
m_aRender = new D3D::CRenderSystem();
else if(lib == OGL)
m_aRender = new OGL::CRenderSystem();

return m_aRender;
}

CSystem* CSystem::Instance()
{
HANDLE hMutex = Mutex->Create();
Mutex->Lock(hMutex);
if(m_cInstance == 0)
m_cInstance = new CSystem();
Mutex->Unlock(hMutex);

return m_cInstance;
}

void CSystem::SwitchRenderSystem()
{
if(lib == D3D) {
lib = OGL;
m_aRender = new OGL::CRenderSystem();
} else {
lib = D3D;
m_aRender = new D3D::CRenderSystem();
}

//call updates required
}

int main()
{
CSystem* System = CSystem::Instance();
CSystem* Something = CSystem::Instance();

System->Render()->Draw();

System->SwitchRenderSystem();

System->Render()->Draw();

std::cin.get();

System->Render()->Release();
return 0;
}

Share this post


Link to post
Share on other sites
Bezben    202
I don't think you really need mutexes unless you are doing multi-threading, and even then I think it's a bad idea to have rendering code in multiple threads.

You'd want to stick a Release call in your switchrendersystem method to release the current system if there is one, or you'll get a memory leak. I've never seen a setup that uses both opengl and directx at the same time though...

Share this post


Link to post
Share on other sites
_goat    804
Quote:
Original post by Dae
Haha, alright thanks man. Its too bad theres no like generic pointer that would point to D3D or OGL even though they are different classes. Deriving them from the same class works.. but eh wouldn't that be a little high maintenance.

If anyone knows of another way too I'd really appreciate it! :)


That's how you'd do it. That's how I've done it. It works quite well actually. Very little fuss.

Share this post


Link to post
Share on other sites
Grain    500
Quote:
Original post by Dae
Haha, alright thanks man. Its too bad theres no like generic pointer that would point to D3D or OGL even though they are different classes. Deriving them from the same class works.. but eh wouldn't that be a little high maintenance.

If anyone knows of another way too I'd really appreciate it! :)
Look up the Bridge design pattern.

Share this post


Link to post
Share on other sites
Quote:
Original post by Dae
Haha, alright thanks man. Its too bad theres no like generic pointer that would point to D3D or OGL even though they are different classes. Deriving them from the same class works.. but eh wouldn't that be a little high maintenance.

If anyone knows of another way too I'd really appreciate it! :)


Well, C++ is not PHP [smile]. Having this kind of generic pointer is not compatible with the C++ notion of strict and safe typing.

In fact, this code:

class OglRenderer { ... };
class D3dRenderer { ... };
class Renderer { ... };
// ...
Renderer *r = (Renderer *)(new OglRenderer());

Will compile. If you carrefully craft both Renderer, OglRenderer and D3dRenderer then it may also work, if you are luck enough. To create binary compatible classes, they must have the same member variables AND the same functions. Then, maybe the compiler will let you do this (of course, this is horrible, non standard, is not proven to work, is more than hard to maintain (doh! I forgot that I added a dword in OglRenderer), break encapsulation (because the only way to have the same variables in OglRenderer and D3dRenderer is to have all your variables, meaning that the OglRenderer will need to declare some room for the D3D variables, even if it don't need them), and have a bunch of other problems that may prevent it to work (what destructor get called when you delete your false Renderer object?).

Deriving a class is far more easier than you might think. First, it doesn't add much maintenance to your project - it is certainly not a high maintenance. If you want to add one public function to your Renderer then you have to add it in OglRenderer and D3dRenderer - this is not what I'd call "a lot of work" [smile]. Moreover, the compiler will automatically call the correct function, use the correct variable, and so on. In fact, once you'll get used to it, you'll see that it is damn easy.

(Actually it is so easy that your next step is probably to abuse inheritance. Don't worry, that's a normal move [smile])

HTH,

Share this post


Link to post
Share on other sites
TheOther    150
Been down this road a few times and as long as you stick to the Fixed Function Pipeline model of D3D/OGL, then you're fine.

The real mind/brain-warp begins when you want to add shaders into the mix. Blech.

Instead of charging ahead though, I'd really evaluate if you need to support them or not.

Other than that, you're pretty much on the right track IMHO. I'd second the opinion that you should stay away from multithreaded code at this point, especially when you're just starting to get the rendering framework off the ground.

hth,

Share this post


Link to post
Share on other sites
Hello again :)

Quote:
Original post by Grain
Quote:
Original post by Dae
Haha, alright thanks man. Its too bad theres no like generic pointer that would point to D3D or OGL even though they are different classes. Deriving them from the same class works.. but eh wouldn't that be a little high maintenance.
If anyone knows of another way too I'd really appreciate it! :)
Look up the Bridge design pattern.


The bridge pattern is implemented by defining something like this:

class Abstraction
{
private:
Implementation *mImplementation;
public:
void doSomething() { mImplementation->doSomething(); }
};

class Implementation // abstract class
{
public:
virtual void doSomething() = 0;
};


And then you inherit Implementation to provide yours. Of course, you are also able to inherit Abstraction in order to create some other abstraction, but that's not the point here. In fact, the bridge pattern is only interesting when you inherit Abstraction and then modify the behavior of the doSomething() method (have a look to the GoF for a more concrete example of this pattern).

The fact is that the OP (Dae) needs to create the Implementation part and its derived classes. Thus, the bridge pattern will not really be usefull in this case.

Of course, the advise is still good: the more pattern description you read, the faster you'll progress in OO design ;)

Regards,

Share this post


Link to post
Share on other sites
Dae    160
Oh, yeah that makes sense Emmanuel Deloget. You can do that in Flash AS too, and thats because everything is derived from Object. Which seems to be working here, and its definetly not as hard as I though it would have been. Good to know I shouldn't try this with pointers. Thanks!

I'll definetly be looking into more design patterns. I know theres a book on them, but I wont be able to pick it up for a while. For now I'm going to have to hope to see their name (Singleton, Bridge, etc) used somewhere so I can look them up on google.

Ah, I see about the purpose of the Release function Bezben. I see how it would be useful in the original code. Now that I've got the object within a system class, I can simply delete the object from within the system class.

I also think it's a bad idea to have rendering code in multiple threads. See I don't get it. I got some help at EFNet, #C++, and it was said that two calls to Instance() could occur at the same time, which could lead to multiple instances when its a Singleton. I haven't read up on multithreading or synchronization, because I thought I had to take some indirect method to multithread. But in IRC I was told that calling Instance() twice would lead to multiple threads, and so was recommended to use a Mutex around the new in Instance(). Many other good programmers saw me using it and all seemed to think it was necessary.

So I'm definetly going to have to read up on synchronization and design patterns. I just noticed the link, that book has the exact topics I need. Its not even out yet, haha. Thanks for the link, TheOther.

Thanks for the help so far guys, this is fun. Again, this much better than misc assignments that only use a class to encapsolate for the hell of it.

Share this post


Link to post
Share on other sites
TheOther    150
Quote:
Original post by Dae
So I'm definetly going to have to read up on synchronization and design patterns. I just noticed the link, that book has the exact topics I need. Its not even out yet, haha. Thanks for the link, TheOther.

Thanks for the help so far guys, this is fun. Again, this much better than misc assignments that only use a class to encapsolate for the hell of it.


T-minus 15 days and it should be on the shelves (or at least available via Amazon).

Share this post


Link to post
Share on other sites
Grain    500
Quote:
Original post by Emmanuel Deloget

The fact is that the OP (Dae) needs to create the Implementation part and its derived classes. Thus, the bridge pattern will not really be usefull in this case.

Regards,

How is it not useful? His problem is exactly what the bridge pattern is for.



class Abstraction
{
private:
Implementation *mImplementation;
public:
void doSomething() { mImplementation->doSomething(); }
};

class Implementation // abstract class
{
public:
virtual void doSomething() = 0;
};

To make this useful for him he would need to do:

class OpenGL_Implementation :public Implementation
{
...
};

class D3D_Implementation :public Implementation
{
...
};

Then you can render through the Abstraction interface. And when you want to switch between OpenGL and Direct3D you change the mImplementation pointer to either a OpenGL_Implementation instance or a D3D_Implementation instance



Quote:
Original post by Dae
I'll definetly be looking into more design patterns. I know theres a book on them, but I wont be able to pick it up for a while. For now I'm going to have to hope to see their name (Singleton, Bridge, etc) used somewhere so I can look them up on google.


Wikipedia has some interesting articles on design patterns

http://en.wikipedia.org/wiki/Design_pattern_%28computer_science%29

Share this post


Link to post
Share on other sites
Dae    160
Sweet, thank you Grain!

I'm actually using that exact pattern now btw. I guess I am using the Bridge pattern, its posted up there.

Can anyone shed light on why I was recommended to add a Mutex for that new statement? It was said that mutliple threads might try to access it, even when I dont have plans to make multiple threads, and should add it. While Bezben says he doesnt think I don't need the Mutex.

Share this post


Link to post
Share on other sites
Yann L    1802
Quote:
Original post by Grain
How is it not useful? His problem is exactly what the bridge pattern is for.

Because the additional dereference over the Abstraction object is completely useless in this case. The bridge pattern is usefull, if you want to switch Implementation on the fly. For example, if you'd have both a OpenGL_Implementation and a D3D_Implementation object instanciated, and switch between both at runtime. But you can't do that. You either use the one or the other. You select one at startup, create an object of that type, and access it over the Implementation base class. If you want to change renderers, you destroy the current rendering object (don't forget the virtual dtor !), and create a new one. Two instanciated OpenGL and D3D objects can and should never coexist at the same time.

Going over Abstraction is just useless overhead.

Quote:

Can anyone shed light on why I was recommended to add a Mutex for that new statement? It was said that mutliple threads might try to access it, even when I dont have plans to make multiple threads, and should add it. While Bezben says he doesnt think I don't need the Mutex.

Unless you plan to multithread your rendering code (which you should probably not do), Mutexes are not needed. Some people like to put them everywhere, because "just in case", but this shows a lack of understanding of what a mutex actually is. Adding them in your context (ie. single threaded rendering) is not only useless from a functional point of view, but can also become a performance problem. Mutexes add overhead, so use them only where actually needed.

Share this post


Link to post
Share on other sites
ProgramMax    162
I agree about the fixed function vs shader deal.

I have been working on a platform & api independent engine for a while now. There were a few problems at first like ...I forget the specifics...but I think for vertex colors D3D wanted RGBA and OGL wanted ARGB.

That was no big deal. As I loaded models I could just swizzle the data around.

But then it got a little more tricky. A computer's video card wants vertex data to be interleaved: XYZ UV XYZ UV. But the GameCube wants these in seperate streams: XYZ XYZ UV UV. Okay...so more swizzling.

But all this swizzling effectively means I'm loading the model to some buffer, then converting it and saving it in a seperate buffer. This two-stage loading clearly shows preference to one platform or api. My goal is to make an engine that works *just as well* on any given system. I don't want anyone to say "Yeah it claims it is cross-platform, but it sucks on GameCube so no one would use it."

So I implemented something that managed how the model was loaded. It would read the file and fill the buffers according to what that specific platform/api wanted. This shows no preference and solves my problem.

Significantly more complicated, but it still is do-able. Same concept for shaders.

Anyway, I think you will find that a D3DRenderer and OGLRenderer that derive from RendererInterface is only the beginning. Loading models or textures into either is vastly different.

And I highly suggest AGAINST "obviously I will have to put a few if/thens in the code based on the renderer." That means your renderer isn't written correctly. Your interface takes care of the abstraction between D3D/OGL. You shouldn't need if/thens for abstraction.

The reason I say this is something I hinted to before. For example, a friend of mine worked with the Unreal Engine (not sure which version). Because of things like that, the code wasn't portable at all. Despite the fact that the engine claims that it is cross platform. A truely solid example of this is Dues Ex being ported to the PS2. The PS2 has, what, 4mb of video memory? After your front and back buffer you have maybe 2? Fitting textures into 2mb of memory is not easy. Sony knew this and so they made that memory crazy fast. The idea being you can load maybe a handful of textures, render those objects, the unload the textures. Continue until the entire scene is drawn.

From what I understand the Unreal Engine didn't take care of that. So your code would have to do the texture loading and unloading. That means tons of if/thens in game code based on the platform/renderer. That means the game is effectively not portable.

Share this post


Link to post
Share on other sites
Yann L    1802
Quote:
Original post by ProgramMax
I have been working on a platform & api independent engine for a while now. There were a few problems at first like ...I forget the specifics...but I think for vertex colors D3D wanted RGBA and OGL wanted ARGB.

By default, OpenGL expects RGBA. Using vertex shaders and/or extensions, you can make it accept pretty much any format you want.

Quote:
Original post by ProgramMax
But then it got a little more tricky. A computer's video card wants vertex data to be interleaved: XYZ UV XYZ UV. But the GameCube wants these in seperate streams: XYZ XYZ UV UV. Okay...so more swizzling.

The video card doesn't care about the vertex layout. Might it be interleaved or in separate streams, it will render it. The performance is usually better on interleaved data though, so most people use that. But you can very well interleave a part of your vertex data (for example XYZU0V0) and use a separate stream for other parts (eg. colours).

Note that this functionality is only supported on OpenGL, not on D3D. So if you want vertex layout compatibility, stay with an interleaved format.

Quote:
Original post by ProgramMax
But all this swizzling effectively means I'm loading the model to some buffer, then converting it and saving it in a seperate buffer. This two-stage loading clearly shows preference to one platform or api. My goal is to make an engine that works *just as well* on any given system. I don't want anyone to say "Yeah it claims it is cross-platform, but it sucks on GameCube so no one would use it."

Making an engine run on PC and consoles is an entirely different world than a simple D3D/OGL renderer, due to the fact that current console hardware is very different to PC 3D hardware. But I don't think this matters to the OP. Both D3D and OGL access the same hardware, making this task much easier.

Quote:
Original post by ProgramMax
Anyway, I think you will find that a D3DRenderer and OGLRenderer that derive from RendererInterface is only the beginning. Loading models or textures into either is vastly different.

Not really, both are in fact very similar.

Quote:
Original post by ProgramMax
And I highly suggest AGAINST "obviously I will have to put a few if/thens in the code based on the renderer." That means your renderer isn't written correctly. Your interface takes care of the abstraction between D3D/OGL. You shouldn't need if/thens for abstraction.

Very true. But don't abstract too much. As I said, D3D and OGL are very, very similar - or can be made similar to each other using the appropriate extensions in OpenGL (matrix transpose, BGRA formats, etc). Try to keep as much code API independent, and then route the rest through abstracted adapter objects.

Share this post


Link to post
Share on other sites
TheOther    150
Quote:
Original post by Yann L
Very true. But don't abstract too much. As I said, D3D and OGL are very, very similar - or can be made similar to each other using the appropriate extensions in OpenGL (matrix transpose, BGRA formats, etc). Try to keep as much code API independent, and then route the rest through abstracted adapter objects.


True true Yann L.

Mind you, the very first question you should be asking yourself is:

"Do you really need to support multiple renderers?"

What exactly is your reason for going down this path?

There's loads of existing 3D renderer projects around such as Irrlicht, Ogre, Torque, etc, that get you starting to make game content out of the box, rather than fiddle for 6-12 months putting your own framework together.

Ages ago, I tried to be "cool" by supporting both renderers in an old engine I made. The original intent was to use it for my shareware games. I quickly sunk way too much time into it, and really stalled the whole process of working on the GAMES I want to (as opposed to an ENGINE).

Personally in my case, I would've been much much more productive (and happier) just sticking with one API and going from there.

Feel free to ignore me, but really keep asking yourself what you want out of a project of this size. Is it just ego, or do you have legitimate reasons for doing so?

(There's nothing wrong with going down this path, btw. Don't get me wrong.)

hth,

Share this post


Link to post
Share on other sites
ProgramMax    162
Quote:
Original post by Yann L
By default, OpenGL expects RGBA. Using vertex shaders and/or extensions, you can make it accept pretty much any format you want.


I don't remember what the problem was off the top of my head. I'll check and get back to you.

Quote:
Original post by Yann L
The video card doesn't care about the vertex layout. Might it be interleaved or in separate streams, it will render it. The performance is usually better on interleaved data though, so most people use that. But you can very well interleave a part of your vertex data (for example XYZU0V0) and use a separate stream for other parts (eg. colours).


Right, for PCs. That's exactly what I was saying. But the GameCube does care. It is specifically designed to be similar to the N64 in that respect. Even the docs recommend that you don't interleave the data.

Quote:
Original post by Yann L
Making an engine run on PC and consoles is an entirely different world than a simple D3D/OGL renderer, due to the fact that current console hardware is very different to PC 3D hardware. But I don't think this matters to the OP. Both D3D and OGL access the same hardware, making this task much easier.


Agreed.

Quote:
Original post by Yann L
Very true. But don't abstract too much. As I said, D3D and OGL are very, very similar - or can be made similar to each other using the appropriate extensions in OpenGL (matrix transpose, BGRA formats, etc). Try to keep as much code API independent, and then route the rest through abstracted adapter objects.


Again, agreed. The Dues Ex example I gave is due to the Unreal Engine not being origionally designed with consoles in mind. The console port is in turn not as good. I think you should definatly get a clear definition of what you want your engine to do. If it doesn't have to port to consoles, don't worry about them.

Share this post


Link to post
Share on other sites
ProgramMax    162
I guess I didn't choose my words well when I said "the video card wants..."

What I mean is what Yann L said. The video card will accept either way. But generally you get better performance if you interleave.

The GameCube is similar. It will take either. But you get better performance for not interleaving.

This all goes back to how I was saying "I don't want my engine to *work* on these platforms, but only work *well* on one or two." So I didn't want to force interleaved and then make my GameCube port useless.

Share this post


Link to post
Share on other sites
Dae    160
Thanks for the input, but theres one post I don't understand.

Quote:
Original post by Yann L
Quote:
Original post by Grain
How is it not useful? His problem is exactly what the bridge pattern is for.

Because the additional dereference over the Abstraction object is completely useless in this case. The bridge pattern is usefull, if you want to switch Implementation on the fly. For example, if you'd have both a OpenGL_Implementation and a D3D_Implementation object instanciated, and switch between both at runtime. But you can't do that. You either use the one or the other. You select one at startup, create an object of that type, and access it over the Implementation base class. If you want to change renderers, you destroy the current rendering object (don't forget the virtual dtor !), and create a new one. Two instanciated OpenGL and D3D objects can and should never coexist at the same time.

Going over Abstraction is just useless overhead.

Quote:

Can anyone shed light on why I was recommended to add a Mutex for that new statement? It was said that mutliple threads might try to access it, even when I dont have plans to make multiple threads, and should add it. While Bezben says he doesnt think I don't need the Mutex.

Unless you plan to multithread your rendering code (which you should probably not do), Mutexes are not needed. Some people like to put them everywhere, because "just in case", but this shows a lack of understanding of what a mutex actually is. Adding them in your context (ie. single threaded rendering) is not only useless from a functional point of view, but can also become a performance problem. Mutexes add overhead, so use them only where actually needed.


Grain's Bridge Pattern is exactly what I'm using, if you take what else he said into account "And when you want to switch between OpenGL and Direct3D you change the mImplementation pointer to either a OpenGL_Implementation instance or a D3D_Implementation instance". That also follows by you saying not to have two objects of each one created at the same time. But you say not to have the extra abstraction? but isn't that sort of necessary because I want to call System->Render() for example and have it return whichever choice my options are (D3D or OGL), and the only way I know how to do that is to return a pointer to the interface. I cant return a pointer to a D3D or OGL specific object, or else I'd be calling System->D3DRender() or something wouldnt I.

Quote:
Feel free to ignore me, but really keep asking yourself what you want out of a project of this size. Is it just ego, or do you have legitimate reasons for doing so?

I am actually only going with OpenGL. I just wanted to add a D3D option in there should I ever want to convert it to D3D, or practice what I learn when I finally learn D3D, or someone who knows D3D want's to help but doesn't use OGL, etc. Other than that I guess just added it for fun.

Share this post


Link to post
Share on other sites
Yann L    1802
Quote:
Original post by ProgramMax
Again, agreed. The Dues Ex example I gave is due to the Unreal Engine not being origionally designed with consoles in mind. The console port is in turn not as good.

The OpenGL port was much worse ;) But you're right of course, porting a 3D engine to a platform it was not originally designed for is very difficult, and will almost always result in sub par quality and performance. But this does also apply to other parts of software development - just try to port any software making extensive use hard casts and assuming Intel byte order to OSX... Welcome to a world of pain. Good upfront planning is extremely important for such projects.

Quote:

Grain's Bridge Pattern is exactly what I'm using, if you take what else he said into account "And when you want to switch between OpenGL and Direct3D you change the mImplementation pointer to either a OpenGL_Implementation instance or a D3D_Implementation instance". That also follows by you saying not to have two objects of each one created at the same time. But you say not to have the extra abstraction?

Well, assume the following class structure:

class CRenderer {
public:
CRenderer() { }
virtual ~CRenderer() { }

virtual void Init() = 0;
virtual void Render() = 0;
... etc ...
};

class CRenderer_OpenGL : public CRenderer {
public:
virtual void Init() { /* OpenGL init */ }
virtual void Render() { /* OpenGL rendering */ }
... etc ...
};

class CRenderer_D3D : public CRenderer {
public:
virtual void Init() { /* Direct3D init */ }
virtual void Render() { /* Direct3D rendering */ }
... etc ...
};


Now in your startup code, you select the renderer based on user input, config files, or whatever, and create a new object of the appropriate type:

Init()
{
CRenderer *Renderer;

switch( whichOneToUse ) {
case OGL: Renderer = new CRenderer_OpenGL; break;
case D3D: Renderer = new CRenderer_D3D; break;
// and more if you like
}

Renderer->Init();

// ...
}


The access to this renderer is then abstracted through the polymorphic base type:

RenderFrame()
{
// pre-frame stuff...

Renderer->Render();

// post-frame stuff...
}

Share this post


Link to post
Share on other sites
ProgramMax    162
What you are doing is fine. The difference is your pointer to an interface isn't quite a bridge.

Think of it this way. What if you had:

MyEngine->Render( );
MyEngine->Render( );

From our point of view it would make sense that these would both call to D3D or both call to OGL. If we switched which it was, then we would expect it to call the other.

But that's from our point of view. That's the key to the bridge.

Suppose we weren't aware that after the first call, the renderer changed. And so the second call went to the other renderer. That's when you would use a bridge.

When you don't know (or don't want to know) which implementation the call is being directed to. But that isn't your case. For your engine you know which renderer the call gets directed to...it's which ever you assigned it.

So though the difference in code is subtle, the difference in concept is drastic. That's why you don't really gain anything from using a bridge.

Share this post


Link to post
Share on other sites
ProgramMax    162
Oops, Yann L got the response in before I did. `,:o) Oh well.

Hey Yann, just out of curiosity...do you have perhaps a post or a page detailing you? How old are you? How long have you been working with 3D programming? I'm interested.

Share this post


Link to post
Share on other sites

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