Jump to content
  • Advertisement
Sign in to follow this  
El OsO AntiGuo

Help with Dependency Injection Scenario

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

I currently have 3 classes which are listed below and a description of them is followed:

CDesktopWindow - Contains the window creation code, message loops, window handle, etc...

CRenderer - Contains all directx related code and HWND to initialize directx so it knows where it needs to draw to.

IRenderer - Interface that contains 1 pure virtual function call draw()

class CDesktopWindow
{
  HWND m_hwnd;
  IRenderer* m_renderer

   CDesktopWindow(IRenderer* renderer)
   {
     m_renderer = renderer;
   }



  void Draw()
  {
     // Drawing logic here
     m_renderer->Draw();
  }
};

My renderer interface looks like so:

struct IRenderer
{
     pure virtual void Draw() =0;
};

Summary:

 

The issue i am running into is that my CDesktopWindow class "has-a" IRenderer interface that is in charge of performing all the drawing for my application. The implementation i have for IRenderer ( which is CRenderer ) takes a HWND for a constructor.  It needs this to initialize direct3d properly.  The problem is, the window HWND get's created later on.  I hope this makes sense.  Does anyone have any recommendations on how to solve this circular depedency.

 

Essentially, all i want to do is inject a IRenderer interface to be used within CDesktopWindow, except the concrete implementation of IRenderer that i have MUST have a handle to the window, which isn't created until CDesktopWindow.Create() is called.

 

// Example of object creation/ dependency injection

{

     IRenderer* renderer = new CRenderer( {I need window handle here } );    // How do i get the below created window handle in here?
     CDesktopWindow* desktopWindow = new CDesktopWindow( renderer );
     desktopWindow.CreateWindow();    // Create HWND for application window
     desktppWindow.Run();   // run message loop

}
Edited by El OsO AntiGuo

Share this post


Link to post
Share on other sites
Advertisement

Is there a reason why the window works with a renderer and not the other way around?

 

It is not supposed to be a suggested solution ... I'm just trying to do something similar and currently I'm hoping the window does not need to know anything about the render module.

I'd also kinda expect to find the DirectX initialization stuff in the window class ... isn't it also about input, not just rendering?

Edited by DareDeveloper

Share this post


Link to post
Share on other sites

When not add a "context" parameter to Draw?

class RenderContext
{
public:
HWND getWindowHandle() const;
};

struct IRenderer
{
     pure virtual void Draw(const RenderContext & context) =0;
};

And on each render, CDesktopWindow creates a RenderContext (or reuse a cached one) and pass it to IRenderer.

 

EDIT:

I just reallized you need window handle to intialize DX. So passing the handle to Draw may not solve your problem. Then maybe you can add an "intialize" to IRenderer.

struct IRenderer
{
    virtual void Initialize(HWND windowHandle) = 0;
     pure virtual void Draw() =0;
};

Edited by wqking

Share this post


Link to post
Share on other sites

Is there a reason why the window works with a renderer and not the other way around?

I think that is the right kind of question to ask in cases like this.

CDesktopWindow presumably needs access to the renderer because it needs to invoke it from the message loop. So, eventually, it will also need access to the input-controller, simulation & game-logic too, for the same reason. The other implication is that there is a 1-to-1 relationship between a top-level window and a message loop.

I would suggest that CDesktopWindow should be solely responsible for being a top-level window. Something else, like a CApplication (or just main()), should be responsible for managing the message pump, which includes calling Draw() on the IRenderer.

 

I'd also kinda expect to find the DirectX initialization stuff in the window class ... isn't it also about input, not just rendering?

The OP is using Direct3D, which is exclusively renderering not input, etc. In fact Microsoft has effectively deprecated all but the 2D/3D parts of DirectX. For input it's recommended to just use Raw Input instead.

Share this post


Link to post
Share on other sites

EDIT: LOL. Totally misread your question. Never mind this post.

Forgive me if i've totally misunderstood your question but can't you just create a constructor in your CRenderer to accept the HWND?

 

Or another solution is for the IRenderer to accept like a generic initial data parameter (struct/class) that can contain generic data. Something like

struct RendererConfig
{
 int screenWidht;
 int screenHeight;
 bool bWindowed;
 bool bVSync;
 void *pParam1; //You can store HWND here then typecast it to HWND in your renderer constructor
 void *pParam2; // Other data you may want to pass
};

Making it void* makes the HWND invisible to your interface and will only be shown in your Windows/DX specific code if you're aftering a multi-platform design.

Edited by BrentChua

Share this post


Link to post
Share on other sites

Is there a reason why the window works with a renderer and not the other way around?

 

My reasoning is that the renderer should be able to draw to many targets and not just "windows".  Therefore the IRenderer should represent the operation of performing drawing operations, regardless of destination.  CDesktopWindow "is-implemented-in-terms-of" an IRenderer to perform the actual drawing.

 

This is my Opinion :)  Let me know if i seem wrong for thinking this

Edited by El OsO AntiGuo

Share this post


Link to post
Share on other sites

 

When not add a "context" parameter to Draw?

class RenderContext
{
public:
HWND getWindowHandle() const;
};

struct IRenderer
{
     pure virtual void Draw(const RenderContext & context) =0;
};

And on each render, CDesktopWindow creates a RenderContext (or reuse a cached one) and pass it to IRenderer.

 

EDIT:

I just reallized you need window handle to intialize DX. So passing the handle to Draw may not solve your problem. Then maybe you can add an "intialize" to IRenderer.

struct IRenderer
{
    virtual void Initialize(HWND windowHandle) = 0;
     pure virtual void Draw() =0;
};

Hehe you understand my question right on!  

 

1.) Adding an Initialize function - I could but does it really make sense for an interface to have a method called initialize? to me it doesn't really make sense from an interface perspective.

 

2.) Passing HWND into a member function as a parameter - I was wanting to avoid passing a HWND directly to the interface.  Why might you ask?  What if i wanted ot use this IRenderer interface with some other platform( linux..etc ).  Linux doesn't use HWND's and therefore i would be strictly creating this interface for windows programs to use.

 

Any other advice is greatly appreciated.

 

Share this post


Link to post
Share on other sites

EDIT: LOL. Totally misread your question. Never mind this post.

Forgive me if i've totally misunderstood your question but can't you just create a constructor in your CRenderer to accept the HWND?

 

Or another solution is for the IRenderer to accept like a generic initial data parameter (struct/class) that can contain generic data. Something like

struct RendererConfig
{
 int screenWidht;
 int screenHeight;
 bool bWindowed;
 bool bVSync;
 void *pParam1; //You can store HWND here then typecast it to HWND in your renderer constructor
 void *pParam2; // Other data you may want to pass
};

Making it void* makes the HWND invisible to your interface and will only be shown in your Windows/DX specific code if you're aftering a multi-platform design.

This approach seems actually like a good idea since i am wanting to hide the implementation detail of a HWND from my calling code.  How would u go about using this struct?  like where would u initialize it and where would u pass it in?

Share this post


Link to post
Share on other sites

Unfortunately I don't know enough about the window handle HWND.

I thought you probably didn't worry about a complete abstraction layer until you wrote that you want a solution that makes a Linux implementation possible.

 

I think you want the CDesktopWindow to stay pure and anything that can draw gets an implementation of IRenderer (for example CRendererDirectX and CRendererOpenGL).

It seems you think about CDesktopWindow more as a widget.

 

Maybe you should have two different window classes:

1.) CGUIWindow without anything OS specific like a window handle. It should just be an IWidget with a draw(IRenderer renderer) function.

2.) COSWindow ... you'll probably need CWindowOpenGL and CWindowDirectX pretty soon. That is probably where the initialization of DirectX and OpenGL should go.

And those windows could be the Renderers (implement IRenderer).

 

Guess writing IRenderer functions that allow anything that can be done in DirectX will be a pain ...

but I don't think there is another way to create a real abstraction layer.

Edited by DareDeveloper

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!