Thursday, November 22, 2012

코드 분석 : Mainloop를 찾는다.

어떠한 프로그램의 소스를 분석할 때 제일 처음으로 할 것은 바로 메인루프(Mainloop)을 찾는 것 입니다. 메인 루프의 구성법은 만들어낼 프로그램이 무엇인가에 따라 많이 다릅니다. 크게 나누어 보면 이벤트(혹은 메세지) 드리븐 방식과 폴링 방식이 있습니다.

제가 모든 소스를 곁들어 가면서 설명하기에는 시간이 많지 않기 때문에 살펴보면 좋은 소스들의 리스트를 나열하고 몇 가지는 제가 인용해서 설명하겠습니다. 이 작업을 할 때 잃어버리지 않아야 할 것은 절대로 다른 소스까지 읽어가면서 다 분석하려고 하지 말고 메인 루프의 구성이 어떻게 되어 있나만 살펴 보는 것입니다. 물론 시간이 많아서 모든 소스를 다 분석하면 좋겠지만요 :)

1. Win32 Application의 메인 루프 구성
2. GLUT의 메인 루프 구성
3. SDL의 메인 루프 구성
4. Quake3의 메인 루프 구성
5. GameEngine Architecture(책)의 메인 루프 부분 챕터

우선 3번 SDL의 메인 루프 구성을 살펴 보도록 하죠.

참고 링크
http://sourcecodebrowser.com/a7xpg/0.11.dfsg1/classabagames_1_1util_1_1sdl_1_1_main_loop_1_1_main_loop.html


while (!done) {
      SDL_PollEvent(&event);
      input.handleEvent(&event);
      if (input.keys[SDLK_ESCAPE] == SDL_PRESSED || event.type == SDL_QUIT)
       done = 1;

      nowTick = SDL_GetTicks();
      frame = (int) (nowTick-prvTickCount) / interval;
      if (frame <= 0) {
       frame = 1;
       SDL_Delay(prvTickCount+interval-nowTick);
       if (accframe) {
         prvTickCount = SDL_GetTicks();
       } else {
         prvTickCount += interval;
       }
      } else if (frame > maxSkipFrame) {
       frame = maxSkipFrame;
       prvTickCount = nowTick;
      } else {
       prvTickCount += frame * interval;
      }
      for (i = 0; i < frame; i++) {
       gameManager.move();
      }
      screen.clear();
      gameManager.draw();
      screen.flip();
    }


Quake3의 메인 루프 부분

참고링크
http://fabiensanglard.net/quake3/index.php


int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
    {
       
        Com_Init
        
        NET_Init
        
        while( 1 )
        {
            // Common code
            IN_Frame()  // Add Win32 joystick and mouse inputs  as event_t to unified event queue.
            {
              IN_JoyMove                                    
              IN_ActivateMouse
              IN_MouseMove
            }
         
            Com_Frame
            {
                 // Common code
                 Com_EventLoop    // Pump win32 message, UDP socket and console commands to the queue (sysEvent_t eventQue[256]) 
                 Cbuf_Execute
                 
                 // Server code
                 SV_Frame
                 {
                     SV_BotFrame                                 // Jump in bot.lib
                     VM_Call( gvm, GAME_RUN_FRAME, svs.time )    // Jump in Game Virtual Machine where game logic is performed
                     
                     SV_CheckTimeouts
                     SV_SendClientMessages                       // Send snapshot or delta snapshot to connected clients
                 } 
                 
                 // Common code
                 Com_EventLoop
                 Cbuf_Execute
                  
                 // Client code
                 CL_Frame
                 {
                     CL_SendCmd                                 // Pump the event queue and send commands to server.
                     
                     SCR_UpdateScreen
                        VM_Call( cgvm, CG_DRAW_ACTIVE_FRAME);   // Send message to the Client Virtual Machine (do Predictions).
                             or
                        VM_Call( uivm, UI_DRAW_CONNECT_SCREEN); // If a menu is visible a message is sent to the UI Virtual Machine.
                     
                     S_Update                                   // Update sound buffers
                 }
            }
            
        }
    }




마지막으로 GLUT의 메인 루프 구성

참고링크
http://graphics.stanford.edu/courses/cs248-01/OpenGLHelpSession/code_example.html


int main(int argc, char** argv)
{
  // GLUT Window Initialization:
  glutInit (&argc, argv);
  glutInitWindowSize (g_Width, g_Height);
  glutInitDisplayMode ( GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
  glutCreateWindow ("CS248 GLUT example");
  // Initialize OpenGL graphics state
  InitGraphics();
  // Register callbacks:
  glutDisplayFunc (display);
  glutReshapeFunc (reshape);
  glutKeyboardFunc (Keyboard);
  glutMouseFunc (MouseButton);
  glutMotionFunc (MouseMotion);
  glutIdleFunc (AnimateScene);
  // Create our popup menu
  BuildPopupMenu ();
  glutAttachMenu (GLUT_RIGHT_BUTTON);
  // Get the initial time, for use by animation
#ifdef _WIN32
  last_idle_time = GetTickCount();
#else
  gettimeofday (&last_idle_time, NULL);
#endif
  // Turn the flow of control over to GLUT
  glutMainLoop ();
  return 0;
}

그리고 렌더링, 키보드와 같은 것들은 다른 콜백 함수로 연결되어 있습니다.
가령 키보드를 처리하는 콜백 함수는

void Keyboard(unsigned char key, int x, int y)
{
  switch (key)
  {
  case 27:             // ESCAPE key
   exit (0);
   break;
  case 'l':
   SelectFromMenu(MENU_LIGHTING);
   break;
  case 'p':
   SelectFromMenu(MENU_POLYMODE);
   break;
  case 't':
   SelectFromMenu(MENU_TEXTURING);
   break;
  }
}


와 같습니다.리스트 5번에 말씀드린 책을 참고하시면 Uncharted의 경우도 비슷한 메인 루프를 구성하고 있습니다. 참고로 피파도 비슷합니다만 더 발전된 형태로 되어 있습니다. :)

여러 프로젝트의 메인 루프 구성을 살펴 보는것은 대단히 중요한데 그 이유는 이 메인 루프가 어떻게 구성되어 있는지 모르면 프로젝트의 전체를 볼 수 없기 때문입니다. 모든 프로젝트를 분석하기 이전에는 반드시 메인 루프 구성을 먼저 살펴 보는것이 분석을 순조롭게 하기 위해서 좋습니다.

생각해 볼 점.
1. SDL과 GLUT의 입력 처리를 하는 방식에 있어서 어떤 차이점이 존재하는가?
2. Win32 Application을 작성할 때 입력 처리를 하는 방식과 Quake3는 어떻게 다른가?


No comments:

Post a Comment

Task in UnrealEngine

 https://www.youtube.com/watch?v=1lBadANnJaw