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는 어떻게 다른가?


Wednesday, November 21, 2012

코드 분석 : 데이터의 표현법(자료구조), 알고리즘

코드 분석의 첫 번째 이야기를 해보려고 합니다.

우선 가장 기본은 자신이 생각하고 있는 것을 사용하는 프로그래밍 언어로 어떻게 데이터로 표현하고 그 데이터를 가공하기 위해 로직을 어떻게 작성해야 하는지만 알면 기본은 갖추어 졌다고 봅니다.

기본을 갖추고 나서 필요한 것은 지금까지 많은 선배 프로그래머들이 만들어 놓았던 자료구조, 알고리즘을 공부하는 것입니다. 결국 컴퓨터가 하는 것은 주어진 데이터를 조작하고 로직에 의해 변형하고 그 결과를 어떠한 형태로든 우리가 얻는 것입니다. 이때 데이터를 어떻게 표현하느냐, 알고리즘을 어떠한 것을 사용했느냐에 따라서 프로그램의 성능에 큰 차이를 만들게 됩니다.

데이터를 표현하는 방법 그리고 그 데이터를 효과적으로 사용하는 방법이 굉장히 많은데 이러한 방법들을 두루두루 알고 있을 때 다른 사람이 작성한 코드를 분석한다거나 큰 프로젝트에 임했을 때 많은 도움이 됩니다.

자료구조에서 특히 많이 사용되는 것은 배열, 리스트, 해쉬테이블, 스택입니다. 그 외에도 많은 것들이 있지만 4가지는 기본중의 기본입니다. 이러한 기본을 공부할 때 좋은 방법은 이러한 자료구조를 이용해서 실제 응용 프로그램에 적용하는 것입니다.

예를 들어 스택은 그림판의 Undo기능에 사용될 수 있습니다. (이 부분에 대한 자세한 내용은 제가 작성한 워드 문서가 따로 있습니다.) 가령 그림판에 A, B, C순으로 어떠한 도형을 그리고 Undo를 했을 때 최종적으로 그렸던 C는 사라지고 A, B만 화면에 나타나야 합니다. 그리고 이후 D, E를 그리고 다시 Undo를 하면 A, B, D만 화면에 나오게 됩니다. 이러한 것을 구현할 때 스택을 이용하면 됩니다.

그리는 동작(보통 command, action이라고 합니다.)을 스택에 넣어주고 Undo를 했을 때 해당 동작을 빼주기만 하면 됩니다. 중요한 것은 스택의 이러한 특성입니다. 스택의 구현법은 다양한데 그 특성은 변하지 않습니다. 그것만 기억한다면 다른 사람의 코드를 분석할 때 많은 도움이 됩니다. 가령 스택 자료구조를 사용한다면 해당 자료구조를 사용하는 로직들을 살펴 볼 때 많은 도움이 됩니다. 왜 배열, 리스트를 사용하지 않고 스택을 사용했는가? 라는 질문을 스스로 하면서 코드를 읽으면 더 이해가 쉽기 때문이죠.

나머지 리스트, 해쉬테이블, 배열 역시 마찬가지입니다. 각각의 자료구조 마다 특성이 있고 그것을 사용하는 로직을 분석할 때 그 특성을 인지하고 읽어 나가면 로직을 이해하기가 더 쉽습니다.

코드 분석이라 함은 로직의 이해입니다. 다른 사람이 어떠한 의도로 로직을 작성했는지 그리고 의도대로 돌아가는지는 증명하고 이해하는것이 코드 분석입니다.

그리고 이것을 잘하기 위해서는 기본적인 컴퓨터 자료구조, 알고리즘의 이해가 필요합니다.

코드 분석에 관한 글을 조금씩 써보려고 합니다.

앞으로 시간 날 때 마다 코드 분석이라는 주제로 글을 좀 써보려고 합니다.
본인이 직접 코드를 작성하는 것은 프로그래머의 기본이지만 남의 코드를 읽고
수정하고 발전 시키는것도 대단히 중요합니다. 그러한 능력을 배양하는데 있어
필요한 각종 팁이나 제가 자주 사용하는 방법들에 대해서 이야기 해보려고 합니다.

Git에서 주어진 파일의 히스토리를 보고 싶다면

gitk -- filename

가령

gitk -- Project/Classes/Char/CharInfo.m

와 같이 하면 해당 파일의 모든 히스토리를 볼 수 있다. 퍼포스의 time lapse view기능과 비슷하다.

Tuesday, November 20, 2012

Thursday, November 8, 2012

코드를 하나씩 작성하는것 보다 중요한 것은 필요하지 않은 코드를 버리는거다.

ㅇㅇ

C#의 Matrix Order는?

열 우선이다.

좀 더 보충해야 겠다.

가령 Matrix의 경우 6개의 요소를 1차원 배열로 가지고 있는데. 이때
0번요소가 M11이고, 1번 요소가 M21라는 소리다. Matrix의 4,5는 각각 X, Y축 이동이다.
행렬 곱 형태로 나타낼 수 없고 직접 계산해야 한다.

Wednesday, November 7, 2012

C#에서 지네릭 클래스 사용하기

C++에서 템플릿 클래스를 사용하듯이 C#에서도 지네릭 클래스라는 것이 있다.
문제는 지네릭 클래스가 C++의 템플릿 클래스와는 다르다는데 있다.

컨테이너를 만들 때 보통 템플릿을 사용하듯이 C#에서도 지네릭 클래스를 사용한다. 가령

List<int>

List<float>

와 같이 말이다.

혹은 Vector클래스를 만들 때도 지네릭화 할 수 있다.

가령

Vector<int>

Vector<float>

와 같이 쓸 수 있으면 얼마나 좋겠나? C#에서는 안타깝게도 이를 구현하기가 어렵다.
가능은 하다. 다음 문서를 읽어 보자.

http://geekswithblogs.net/Mathoms/archive/2008/08/26/applied-generics--vector-class.aspx

http://www.codeproject.com/Articles/10780/Operator-Overloading-with-Generics

읽고 나서 나는 Vector2DInt, Vector2DFloat를 따로 만들어서 썼다.

차라리 Copy and Paste가 훨씬 쉽고 나중에 C#에서 제대로 지원할 때 지네릭을 사용하는 편이 낫겠다.


Task in UnrealEngine

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