class relationship question

    This site uses cookies. By continuing to browse this site, you are agreeing to our Cookie Policy.

    • class relationship question

      I am currently developing a UI. I have a few questions about class relationship interaction.

      My class designs:
      A Control class with subclasses Button & Label
      A Screen class with subclass StartScreen
      The StartScreen creates 2 Buttons and 1 Label
      A UIManager which owns the StartScreen class
      A RenderManager which controls setting up D3D and rendering
      The UIManager and the RenderManager are both singletons

      I am drawing the controls from the StartScreen by referencing the UIManager from the RenderManager as such:

      hr = d3dDevice->BeginScene();
      hr = spriteHandler->Begin(NULL);

      hr = spriteHandler->Draw(UIManager::GetSingleton().ss->but_StartButton->GetUnClickedTexture(),
      NULL, &UIManager::GetSingleton().ss->but_StartButton->GetCenter(), &UIManager::GetSingleton().ss->but_StartButton->GetPosition(), D3DCOLOR_XRGB(255, 255, 255));

      hr = spriteHandler->End();
      hr = d3dDevice->EndScene();

      hr = d3dDevice->Present(NULL, NULL, NULL, NULL);

      ===================
      This works (using the singleton reference to access the StartScreen control objects) however I think there may exist a cleaner way to do this. I am thinking about how to build the collision detection for button clicks and dont want to continue this method if there is a better way. Any thoughts?

      Also, rather than hardcoding the call to Draw each time per control, how can I iterate through the controls and draw them in a better way?

      Any help is greatly appreciated.

      Thank you
    • Hello,

      I would suggest that you let the UIManager draw the GUI components. With your current design you have to change the RenderManager class whenever you change something on the startscreen and that's a clear indication that something is wrong with your design.

      Have all renderable classes inherit from an interface, something like IRenderable, which has a (virtual) public draw/render-method which take a reference to a RenderManager object and handles all the drawing :)

      You could change that a bit (as I would) and have a Renderer class which is used for rendering and a RenderManager class where all objects register themselves for drawing and the RenderManager class calls their draw/render-method at an appropriate time.



      Do you own the GCC book? I suggest that you (re-)read the chapters about scene management and user interfaces :)





      Turing.
    • For the creation of the Renderer class, would each renderable class own a renderer which would interface with the RenderManager when drawing is required?

      So Button owns a class called Renderer, Renderer is registered with the RenderManager and the RenderManager iterates through a vector and calls the Draw method in each Renderer owned by each control that can be drawn?

      I am still a bit confused. Thank you for the help.

      P.S. I did reread the GCC chapter on UI, I have the first edition. I will be reading the others you mention tonight.

      Thanks
    • All my controls for the UI are all textures.

      So now I am thinking that each control will have a draw method and register itself with the RenderManager and when the RenderManager calls each controls draw method passing a SpriteHandler by reference for the control to draw.

      Is this a good design?
    • Originally posted by sosa
      For the creation of the Renderer class, would each renderable class own a renderer which would interface with the RenderManager when drawing is required?

      So Button owns a class called Renderer, Renderer is registered with the RenderManager and the RenderManager iterates through a vector and calls the Draw method in each Renderer owned by each control that can be drawn?

      I am still a bit confused. Thank you for the help.

      P.S. I did reread the GCC chapter on UI, I have the first edition. I will be reading the others you mention tonight.

      Thanks

      No, what I meant was the following:

      Source Code

      1. class IRenderable {
      2. public:
      3. virtual ~IRenderable() {}
      4. virtual void render( Renderer& renderer ) = 0;
      5. };
      6. class MyTextBox : public IRrenderable {
      7. public:
      8. virtual void render( Rendere& renderer ) {
      9. /* do some rendering here */
      10. }
      11. };
      12. class RenderManager {
      13. std::vector< IRenderable* > renderables;
      14. Renderer renderer;
      15. public:
      16. void add_renderable( IRenderable* renderable ) {
      17. renderables.push_back( renderable );
      18. }
      19. void draw_all_renderables() {
      20. for( std::vector< IRenderable* >::iterator it = renderables.begin(),
      21. end = renderables.end();
      22. it != end; ++i ) {
      23. (*it)->render( renderer );
      24. }
      25. }
      26. };
      27. int main() {
      28. RenderManager rm;
      29. MyTextBox mtb1, mtb2;
      30. rm.push_back(mtb1);
      31. rm.push_back(mtb2);
      32. rm.draw_all_renderables();
      33. }
      Display All



      That's really just a rough hack of the basic idea, so please don't directly copy 'n paste it.
    • Thank you for your help. The following describes the progress I have made:

      During Initialize I add my controls to the RenderList
      rm->RegisterRenderObject(UIm->ss->but_StartButton);

      During each loop I call Render
      rm->DrawRenderList();

      DrawRenderList iterates through the objects and calls Render(Renderer& renderer)
      which in turn calls Renderer.Draw(&center, &position, texture)

      and this code within the Draw method
      hr = RenderManager::GetSingleton().GetSpriteHandler()->Draw(texture, NULL, center, position, D3DCOLOR_XRGB(255, 255, 255));

      The only thing I don't like at this point is to have to use my Singleton qualifier to get to the SpriteHandler. Is this ok? or should I think of another way?

      Either way Thank you very much for your help with this issue.
    • Originally posted by sosa
      Thank you for your help. The following describes the progress I have made:

      During Initialize I add my controls to the RenderList
      rm->RegisterRenderObject(UIm->ss->but_StartButton);

      Why is Ulm oder ss not registering its own objects?


      During each loop I call Render
      rm->DrawRenderList();

      DrawRenderList iterates through the objects and calls Render(Renderer& renderer)
      which in turn calls Renderer.Draw(&center, &position, texture)

      and this code within the Draw method
      hr = RenderManager::GetSingleton().GetSpriteHandler()->Draw(texture, NULL, center, position, D3DCOLOR_XRGB(255, 255, 255));

      The only thing I don't like at this point is to have to use my Singleton qualifier to get to the SpriteHandler. Is this ok? or should I think of another way?

      Either way Thank you very much for your help with this issue.

      If you need the RenderManager inside the Renderer you should consider to pass a reference to it into the Draw function. Without any further information I can't comment on your design of the RenderManager and SpriteHandler. Is it a class that manages all sprites? If yes, do you even need that? I know only ID3DXSprite and I've never seen a reason why I would need several objects of this class (so there's no need to manage them, in my opinion).
      It's basically just a class to render 2d overlays in a 3d space, so it could even be just a bunch of helper functions.
    • RenderManager is a class that owns all rendering and the RenderList

      SpriteHandler is simply a LPD3DXSPRITE that I use for drawing. it is just a variable rather than a class.

      I am still reworking the design based on your feedback. Also what book or sources can I read to help with good design layout for interaction between Rendering, UI, etc?

      Thanks
    • Originally posted by sosa
      RenderManager is a class that owns all rendering and the RenderList

      SpriteHandler is simply a LPD3DXSPRITE that I use for drawing. it is just a variable rather than a class.

      I am still reworking the design based on your feedback. Also what book or sources can I read to help with good design layout for interaction between Rendering, UI, etc?

      Thanks

      I would move the SpriteHandler into the Renderer, or make it completely independet, by moving it in its own class and let the Renderer keep one of those objects as a member variable (or the user passes it into the Renderer).

      In a Renderer class I was working on, some years ago, I wrapped the ID3DXSprite class into a wrapper called Sprite and my Renderer class had a member of this class and offered the following functions:

      Source Code

      1. /**
      2. * @brief Tells the device that sprite drawing is needed.
      3. *
      4. * @param flags Influences the behaviour of the sprite drawing. See the
      5. * Sprite documentation for all possible flags. For drawing text you
      6. * should always specify alphablend.
      7. *
      8. * @note This function must be called inside a beginScene() endScene()
      9. * block.
      10. */
      11. void beginSprite( Sprite::Flag flags = Sprite::alphablend );
      12. /**
      13. * @brief Tells the device that sprite drawing is finished.
      14. *
      15. * @note This function must be called inside a beginScene() endScene()
      16. * block.
      17. */
      18. void endSprite();
      19. /**
      20. * @brief Returns a reference to the Sprite object of the renderer.
      21. *
      22. * @note Although you can call begin() and end() of the Sprite directly
      23. * you should use the functions of the %Renderer interface, because they
      24. * contain some sanity checks.
      25. */
      26. Sprite& getSprite()
      27. {
      28. return *mSprite;
      29. }
      30. /**
      31. * @brief Draws a Texture object onto the rendering surface.
      32. *
      33. * For details see the documentation of the Sprite::draw function.
      34. *
      35. * @param tex The texture (=image) to draw from.
      36. * @param pos The position to where the sprite should be drawn.
      37. * Default is 0,0,0.
      38. * @param center The center of the sprite. Default is 0,0,0.
      39. * @param rect Specify a rectangle to draw only a part from the texture.
      40. * If you set all 4 values to 0, the whole texture is used. The x,y values
      41. * are the upper left coordinate and the z,w values are the lower right
      42. * coordinate.
      43. * @param col The color and alpha channels are modulated by this value,
      44. * specify 0xffffffff to maintain the original value.
      45. */
      46. void draw( Texture& tex,
      47. const math::Vector3& pos = math::Vector3( 0.0f, 0.0f, 0.0f ),
      48. const math::Vector3& center = math::Vector3( 0.0f, 0.0f, 0.0f ),
      49. const Rect& rect = Rect( 0, 0, 0, 0 ),
      50. color col = 0xffffffff );
      Display All


      As you can see the Renderer is just holding a Sprite object for the user, so that he doesn't have to create one and it only offers some sanity checks in relation to beginscene and endscene calls and for quick overlay drawing it offers a draw function. For everything more sophisticated the user has to grab a reference to the Sprite object, or create one himself.
      From a purely OOA perspective you wouldn't do that, because Sprite management is clearly not the job of the Renderer class, but it makes life for the user clearly easier and so I found this tradeoff between strict OO and usability.

      The post was edited 1 time, last by Turing ().

    • Here are my results which are working:

      Control is a IRenderable & is a XSprite
      Button is a Control
      Label is a Control

      The Render method is within the XSprite class but called from the Control class
      RenderManager has a Renderer as a member
      Renderer has a draw method

      for ( ; it != end; ++it)
      {
      (*it)->Render( renderer); // IRenderable class Render method takes Renderer as a parameter
      }

      void Control::Render(Renderer& renderer)
      {
      hr = renderer.Draw(&center, &position, texture);
      }

      if this is confusing let me know and will attempt to explain more.
    • I followed your advice and made XSprite a member of Control rather than a parent class.

      I had to "forward" a couple of method calls such as the following:

      private:
      XSprite m_XSprite

      void Control::SetCenter(float x, float y, float z)
      {
      m_XSprite.SetCenter(x, y, z);
      }

      Is this ok?

      I am next going to have the UIManager "know" what the active screen is and know which controls it has so I can detect button clicks. I have tried keeping the relative coordinates from DirectInput in sync with Windows ::GetCursorPos but seem to be missing something. Is it ok to use this? rather than the DirectInput method?

      Thanks
    • Originally posted by sosa
      I followed your advice and made XSprite a member of Control rather than a parent class.

      I had to "forward" a couple of method calls such as the following:

      private:
      XSprite m_XSprite

      void Control::SetCenter(float x, float y, float z)
      {
      m_XSprite.SetCenter(x, y, z);
      }

      Is this ok?

      Yes, that is fine :)

      Originally posted by sosa
      I am next going to have the UIManager "know" what the active screen is and know which controls it has so I can detect button clicks. I have tried keeping the relative coordinates from DirectInput in sync with Windows ::GetCursorPos but seem to be missing something. Is it ok to use this? rather than the DirectInput method?

      Thanks

      I don't think that it's a good idea to use both input APIs, why don't you stick with one? Afaik is DirectInput deprecated anyway, so I would use the messaging mechanism from winapi (except that I would use it in any case).
      I've heard a long time ago, that the winapi message mechanism is too slow for high resolution games (input wise), like ego shooters...
    • Search the DirectX SDK they have samples of Raw input message handling WM_INPUT. Microsoft says that this is how keyboard and mouse input should be handled. XInput is the API for using the XBox game pad. If your game supports joysticks DirectInput is still a valid choice.

      gb
    • I think WM_LBUTTONDOWN will suffice for my UI needs. I am trying to call a method from within WinProc as such:

      case WM_LBUTTONDOWN:
      xPos = GET_X_LPARAM(lParam);
      yPos = GET_Y_LPARAM(lParam);
      UIm->PostMouseMessage(xPos, yPos);
      break;

      Even though I have created UIm in my initialize() method I am still getting an error related to unknown class (left of -> etc.)

      In what order is the compiler checking the existence of the class? it doesn't seem to be in execution order?

      Thanks