Sign in to follow this  
hotpixel

when to use static?

Recommended Posts

hotpixel    156
Hi guys, I'm trying to write a game engine in C++/DX and I thought it would be a good idea to define a 'RenderDevice' which contains my LPDIRECT3DDEVICE9 object so I can do a simple RenderDevice::GetDevice() anywhere in my project to grab my device. I also thought I could do RenderDevice::Init() so that only one device could ever be referenced. Now the class members need to be static, which is fine because I only want one of them but I have to redefine them as static in my static methods which doesn't seem right to me, if I don't it complains about an unlinked object:
Quote:
#ifndef _RENDERDEVICE_H #define _RENDERDEVICE_H class RenderDevice { private: static LPDIRECT3DDEVICE9 m_pd3dDevice; static HWND m_hWindow; static int m_width; static int m_height; public: static LPDIRECT3DDEVICE9 GetDevice(){return m_pd3dDevice;} static HWND GetWindow(){return m_hWindow;} static void Init(LPCWSTR name, int width, int height); static int Update(); static LRESULT CALLBACK WndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ); }; #endif
Quote:
/*static*/ void RenderDevice::Init(LPCWSTR name, int width, int height) { ***missing code*** LPDIRECT3DDEVICE9 pd3dDevice; if( FAILED( pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, m_hWindow, D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp, &pd3dDevice ) ) ) HANDLE_MESSAGE(L" unable to create D3D device "); static LPDIRECT3DDEVICE9 m_pd3dDevice = pd3dDevice; ShowWindow( m_hWindow, SW_SHOWDEFAULT ); }
so you can see here that I am having to define a local d3d device so that I can pass it into the CreateDevice() method and then redefine my actual device as static and then pass my local render device back into my static render device. Does this seem right? Am I doing this right? Should I be instancing my RenderDevice? Thanks, Andy

Share this post


Link to post
Share on other sites
scjohnno    236
Can you think of any benefits this has over simply declaring a global RenderDevice*?

Note also that it is not an error to create multiple Direct3D devices.

Share this post


Link to post
Share on other sites
hotpixel    156
I suppose my train of thought was that I would only ever have to worry about one RenderDevice. Although multiple D3D Devices are possible I can't think of ever wanting to let anyone use more than one.

Share this post


Link to post
Share on other sites
Guthur    101
You should initialise static variables.

eg in your cpp file place the following at the top

LPDIRECT3DDEVICE9 RenderDevice::m_pd3dDevice = NULL;

But if you are just going to arbitarily use RenderDevice::m_pd3dDevice all over the place then maybe a global *cringe* is the answer. Oh my I can't believe I said that :p

Share this post


Link to post
Share on other sites
hotpixel    156
no my m_pd3dDevice definately wants to be a private variable, and use GetDevice() to return it, I don't want people accessing it whenever they feel like it.

I want RenderDevice to handle all the DX stuff so that if I ever decide I want to port my engine onto other platforms then all I have to do is change class RenderDevice and any other WINDOWS/DX specific code

Share this post


Link to post
Share on other sites
rip-off    10979
Quote:
Original post by hotpixel
no my m_pd3dDevice definately wants to be a private variable, and use GetDevice() to return it, I don't want people accessing it whenever they feel like it.


Really? I can still access it:

class Audio
{
Audio()
{
RenderDevice::Init("=P",200,100);
}
};



Quote:

I want RenderDevice to handle all the DX stuff so that if I ever decide I want to port my engine onto other platforms then all I have to do is change class RenderDevice and any other WINDOWS/DX specific code

But your class exposes all its implementation details in a most horrific way. I would probably need to rewrite all the calling code if you stopped using DirectX and starting using some other API.

Share this post


Link to post
Share on other sites
hotpixel    156
I want my static functions to be accessed globally, then if something is breaking I can stick a breakpoints in my method and see when and why they are being accessed.

Quote:

But your class exposes all its implementation details in a most horrific way.


How so? You mean the fact that RenderDevice can always be initialised from where ever? Which was something I did think about... obviously this is just an idea that I haven't implemented yet which is why I'm asking what you think.

The idea was given to me by the guy who programmed the graphics for Viva Pinata on the PC. He splits his code into 3 main areas, game code, engine code and API specific code. None of his engine references any of the DX stuff. Everything obviously uses some sort of 'RenderDevice', everything uses vectors and matrices, uses shaders and needs to draw polygons so in theory it works.

It's where I got the idea for my RenderDevice but obviously he can't show me any of the code :(. He uses a RenderDevice class in a similar way, I'm just trying to figure it out!

Share this post


Link to post
Share on other sites
hotpixel    156
I suppose that's a valid point, why would you want to create a class you are never going to implement other than perhaps keeping it clean. ie you know you mean your RenderDevice when you want to GetDevice() and its all ecompassed in a RenderDevice file. It could get quite messy else, if there are a few things you only want to implement once.

Share this post


Link to post
Share on other sites
rip-off    10979
Quote:
Original post by hotpixel
I want my static functions to be accessed globally, then if something is breaking I can stick a breakpoints in my method and see when and why they are being accessed.

Why would access to a renderer be required to be global? I don't see the need. If you design your code properly, very little code needs to actually draw anything. The rest of your game logic doesn't care how (or even if) stuff is rendered

Quote:
Quote:

But your class exposes all its implementation details in a most horrific way.


How so? You mean the fact that RenderDevice can always be initialised from where ever? Which was something I did think about... obviously this is just an idea that I haven't implemented yet which is why I'm asking what you think.

The idea was given to me by the guy who programmed the graphics for Viva Pinata on the PC. He splits his code into 3 main areas, game code, engine code and API specific code. None of his engine references any of the DX stuff. Everything obviously uses some sort of 'RenderDevice', everything uses vectors and matrices, uses shaders and needs to draw polygons so in theory it works.

It's where I got the idea for my RenderDevice but obviously he can't show me any of the code :(. He uses a RenderDevice class in a similar way, I'm just trying to figure it out!


It is possible, but it can be a lot of work. If you want cross platform drawing, just use OpenGL from the start.

What you need to do is design the public interface so that none of the implementation details leak through. If you want to hide DirectX, you don't want any DirectX specific stuff to leak. Lets take a look at your public interface:

static LPDIRECT3DDEVICE9 GetDevice(){return m_pd3dDevice;}
static HWND GetWindow(){return m_hWindow;}
static void Init(LPCWSTR name, int width, int height);
static int Update();
static LRESULT CALLBACK WndProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam );


With the exception of "Update", every function makes use of a DirectX or Windows type. So any code that uses this class is probably going to have DirectX or Windows specific code too.

You need to think at a much higher level. You want to design an interface that works around concepts that people actually want to deal with. Look for interesting nouns: A Texture, not a IDirect3DTexture9, a Shader, not a IDirect3DVertexShader9, etc.

Share this post


Link to post
Share on other sites
rip-off    10979
Quote:
Original post by hotpixel
I suppose the question is then, is static the correct thing to use if you only want to implement something once?


Something is implemented once by definition. Additional implementations cause linker errors.

What you are probably talking about is instantiation. You shouldn't try to artificially limit the number of times something can be instantiated. Its generally more work that it is worth. Unless it is a critical error for there to be two instances, then simply don't.

Share this post


Link to post
Share on other sites
hotpixel    156
Quote:
Original post by rip-off
You need to think at a much higher level. You want to design an interface that works around concepts that people actually want to deal with. Look for interesting nouns: A Texture, not a IDirect3DTexture9, a Shader, not a IDirect3DVertexShader9, etc.


Ha, you sound like Richard. So would you 'typedef IDirect3DTexture9 Texture' and just reference Texture or is there more to it than that?

Share this post


Link to post
Share on other sites
gekko    478
Quote:
Original post by HomerSp
If you're going to make everything static, why use a class in the first place? That seems very unnecessary in my opinion.


Utility pattern, isn't all that uncommon. http://en.wikipedia.org/wiki/Utility_pattern

If your whole goal is to only ever allow one instance of your class, why don't you make it a singleton? It's designed for exactly that purpose.

Share this post


Link to post
Share on other sites
rip-off    10979
Quote:
Original post by hotpixel
Quote:
Original post by rip-off
You need to think at a much higher level. You want to design an interface that works around concepts that people actually want to deal with. Look for interesting nouns: A Texture, not a IDirect3DTexture9, a Shader, not a IDirect3DVertexShader9, etc.


Ha, you sound like Richard. So would you 'typedef IDirect3DTexture9 Texture' and just reference Texture or is there more to it than that?


Typically a lot more, but it depends.

My advice: write some of the calling code first. See how you want it to look. Then see if that can be implemented. Sometimes you might have to compromise to get it to work.

For example, write "pong". Pretend that any graphic function you want to call is available.

Simple example:

int main()
{
Window window("Pong",800,600,Window::WINDOWED);

Renderer &renderer = window.renderer();

Paddle paddles[2];

Texture paddleTextures[2] =
{
Texture("left.png"),
Texture("right.png"),
};

Ball ball;

Texture ballTexture("ball.png");

Pong pong(ball,paddles);

while(pong.running() && window.open())
{
for(int i = 0 ; i < 2 ; ++ i)
{
renderer.drawRect(paddleTextures[i],paddles[i].position(),paddles[i].dimensions());
}
renderer.drawCircle(ballTexture,ball.position(),ball.radius());

renderer.update();
pong.update();
}
}

Share this post


Link to post
Share on other sites
rip-off    10979
Quote:
Original post by gekko
Quote:
Original post by HomerSp
If you're going to make everything static, why use a class in the first place? That seems very unnecessary in my opinion.


Utility pattern, isn't all that uncommon. http://en.wikipedia.org/wiki/Utility_pattern


That is to get around language restrictions, where free functions aren't allowed.

Quote:

If your whole goal is to only ever allow one instance of your class, why don't you make it a singleton? It's designed for exactly that purpose.


Search for "Singleton" on this site. You will get arguments against Singletons, but more importantly the arguments against artificially restricting the number of instances you can make, in addition to arguments against global access. You need to think very carefully before infecting your code with these ideas.

The people who argue against Singletons are probably in the same camp as myself, when we first saw Singletons we thought they looked great. It was only later - much later - when we were struggling with codebases that were difficult if not impossible to manage that we realized the error of our ways.

There is a small (tiny) number of cases where the Singleton "pattern" might be appropriate, but I've yet to see a great argument made for any of the usual suspects (Renderers, Loggers, ResourceLoaders, FooManagers, etc).

Share this post


Link to post
Share on other sites
hotpixel    156
I like this 'Pong' idea it reads well and is kind of the solution I am looking for, I think I'm trying to go too big too soon. I think I will probably try and start with that idea and make a pong style game in this way.

Thanks rippoff!

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