HumanView question

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

    • HumanView question

      In the HumanView class we have function which handles application messages

      Source Code

      1. //
      2. // HumanView::VOnMsgProc - Chapter 10, page 279
      3. //
      4. LRESULT CALLBACK HumanView::VOnMsgProc( AppMsg msg )
      5. {
      6. // Iterate through the screen layers first
      7. // In reverse order since we'll send input messages to the
      8. // screen on top
      9. for(ScreenElementList::reverse_iterator i=m_ScreenElements.rbegin(); i!=m_ScreenElements.rend(); ++i)
      10. {
      11. if ( (*i)->VIsVisible() )
      12. {
      13. if ( (*i)->VOnMsgProc( msg ) )
      14. {
      15. return 1;
      16. }
      17. }
      18. }
      19. LRESULT result = 0;
      20. switch (msg.m_uMsg)
      21. {
      22. case WM_KEYDOWN:
      23. if (m_Console.IsActive())
      24. {
      25. // Let the console eat this.
      26. }
      27. else if (m_KeyboardHandler)
      28. {
      29. result = m_KeyboardHandler->VOnKeyDown(static_cast<const BYTE>(msg.m_wParam));
      30. }
      31. break;
      32. ...
      33. default:
      34. return 0;
      35. }
      36. return 0;
      37. }
      Display All


      First we ask screens to handle the message, then the big switch is used to pass message to various input handlers.

      Quote from the book, page 279
      Back to the implementation of HumanView::VOnMsgProc(). Its job is to iterate through the list of screens attached to it, forward the message on to the visible ones, and if they dont eat the message, then ask the pointer and keyboard handler if they can consume it.


      Also on the page 242 (input chapter) we can find that
      If the message is handled, the functions return true; otherwise, they return false.


      The LRESULT result = 0; is assigned from the input handler call however it isn't used and 0 is always returned. Is it the bug or I miss something?

      As I see it, only HumanViews can consume input messages, and if there is only one HumanView (no split screen) and it returns 0 from the function, the loop inside main WndProc will not break however this is just slight performance drop.
      Looking for a job!
      My LinkedIn Profile
    • RE: HumanView question

      You are correct - the return value could have been used to short circuit the loop and recognize that an internal object consumed and handled the message.

      Another good catch for the reprint! And, I think this code has been essentially unchanged since GCC1 - so this bug has been in there since before 2003. So, I guess whatever problems this might have caused have been pretty hard to notice!
      Mr.Mike
      Author, Programmer, Brewer, Patriot
    • I recreate the engine line by line, rewriting everything I don't like and formatting as I see fit. That's why sometimes I catch bugs. Maybe we should create the topic for posting bugs (or something that look like bugs if a person is uncertain).

      Edit: created the topic for bugs, moved last post there
      Looking for a job!
      My LinkedIn Profile

      The post was edited 2 times, last by devast3d ().

    • One more question about HumanView.

      A generic game view has essentially 3 the most important functions, which are called by the game:

      1.

      Source Code

      1. virtual void VOnUpdate(unsigned long deltaMs)=0;

      It's called from

      Source Code

      1. void BaseGameLogic::VOnUpdate(float time, float elapsedTime)

      which itself is called from the

      Source Code

      1. void CALLBACK GameCodeApp::OnUpdateGame()


      2.

      Source Code

      1. virtual void VOnRender(double fTime, float fElapsedTime)=0;

      It's called from

      Source Code

      1. void CALLBACK GameCodeApp::OnD3D11FrameRender()

      iterating through the list of views which are contained in the base game logic.

      3. And the

      Source Code

      1. virtual LRESULT CALLBACK VOnMsgProc( AppMsg msg )=0;

      that is called from

      Source Code

      1. LRESULT CALLBACK GameCodeApp::MsgProc()


      All those 3 GameCodeApp methods are DXUT callbacks, so I can't say for sure about how they are called, but I suppose something like this:

      Source Code

      1. while (1)
      2. {
      3. if (has_message)
      4. {
      5. MsgProc();
      6. }
      7. else
      8. {
      9. OnUpdate();
      10. OnRender();
      11. }
      12. }
      Display All


      Enough for the intro, the confusion itself is centered around the ScreenElementList m_ScreenElements; inside the HumanView.

      Each of those 3 game view calls end up iterating through the m_ScreenElements collection calling appropriate methods. I'll assume that order of Update calls on the screen elements is unimportant. Before calling Render on screens, the list is sorted using elements ordering

      Source Code

      1. m_ScreenElements.sort(SortBy_SharedPtr_Content<IScreenElement>());
      2. for(ScreenElementList::iterator i=m_ScreenElements.begin(); i!=m_ScreenElements.end(); ++i)
      3. {
      4. if ( (*i)->VIsVisible() )
      5. {
      6. (*i)->VOnRender(fTime, fElapsedTime);
      7. }
      8. }

      notice usual forward iteration (i.e. screens with lower order numbers will get rendered first).

      However MsgProc method traverses the list backward (i.e. screens with higher order will process input first)

      Source Code

      1. // Iterate through the screen layers first
      2. // In reverse order since we'll send input messages to the
      3. // screen on top
      4. for(ScreenElementList::reverse_iterator i=m_ScreenElements.rbegin(); i!=m_ScreenElements.rend(); ++i)
      5. {
      6. if ( (*i)->VIsVisible() )
      7. {
      8. if ( (*i)->VOnMsgProc( msg ) )
      9. {
      10. return 1;
      11. }
      12. }
      13. }
      Display All

      Why don't we sort here too? The only thing I came around that last Render() function call already sorted the list for us and no elements were added to the list since then. By the way can they be added during the MsgProc loop? If yes, then considering that pushing is done to the front of the list

      Source Code

      1. void HumanView::VPushElement(shared_ptr<IScreenElement> pElement)
      2. {
      3. m_ScreenElements.push_front(pElement);
      4. }

      then we will make the list longer as we traverse it and introduce unsorted elements. Also deleting elements inside the loop may bring troubles as well (if the screen will remove itself from the list; if that's even possible).
      Looking for a job!
      My LinkedIn Profile
    • Sorting the screen element list prior to processing messages would handle a very specific edge case - where somehow the screen element list became unsorted in between the previous render and the arrival of new messages to process. But, in practice this would be a situation that occurred on a particular frame, which in most games would be less than 40ms or so.

      I could image a case where a pop-up dialog box might be animating from back to front (seems wierd but I could imagine it) and on a particular frame you could click on the image of a UI object that would be covered by the expanding dialog on the next frame, and get the dialog instead. Players could be annoyed by that depending on the exact situation and how often it would likely occur.

      Solving this would indeed be fixed by your suggestion, but the case seems rare enough that it could likely be left the way it is.

      I'm actually spending a lot of my professional programming time now working with optimizing a game for iOS, and one of the culprits is the UI code. The UI has a lot of widgets and processing them every frame is just too expensive for the iPhone4. If I were working on the above code for my currently pokey game I would gladly trade efficiency for the rare problem that might surface. A game that responds slowly to UI input is a recipe for rage quit!
      Mr.Mike
      Author, Programmer, Brewer, Patriot
    • Aha, so my guess was correct.

      I understand that traversal of the screen element collection inside HumanView::MsgProc does not change the collection itself. If some screen element should be deleted or added to the collection via PushElement/RemoveElement an event must be raised inside IScreenElement's Update/MsgProc which will be handled during the next frame in the event manager update (and event management happens before game view management), right?

      Edit: if above sentence is correct, I still don't quite understand why the sorting is done inside Render instead of MsgProc. Is element ordering can be changed inside HumanView::Update w/o using events? If the above is not correct, ignore this edit.

      Edit2: Ignore first edit. Obviously if screen elements handling is done as the result of event handling (in the next frame if QueueEvent was used), then sort is required in the Render method. Sometimes it's better to go to sleep instead of asking dumb questions :)
      Looking for a job!
      My LinkedIn Profile

      The post was edited 4 times, last by devast3d ().