# 키 입력 예제 : 세상을 둘러 보아요\~ 2 탄:)

이번 장에서는 앞장에서 만든 예제에 키입력 고급 기법을 사용해서 수정해보겠습니다. 새로 추가한 코드에는 주석을 달았습니다.

초기화 부분에 deltaAngle 과 deltaMove 라는 두 개의 변수를 추가했습니다. 이 변수들은 각각 카메라의 회전과 이동을 제어합니다. 0 이 아닐 때에는 카메라가 어떤 행동을 취하고 0 일 때에는 카메라가 고정되어 있습니다. 이 두 변수는 카메라의 초기 상태를 고정 상태로 만들기 위해서 0 으로 초기화합니다.

```cpp
#include <math.h>
#include <gl\glut.h>
#include <gl\gl.h>
#include <gl\glu.h>

float angle=0.0, deltaAngle = 0.0;
float ratio;
float x=0.0f,y=1.75f,z=5.0f;
float lx=0.0f,ly=0.0f,lz=-1.0f;
GLint snowman_display_list;
int deltaMove = 0;

void changeSize(int w, int h)
{
    // 창이 너무 작아졌을때 0 으로 나뉘는 것을 방지합니다.
    if(h == 0)
        h = 1;

    ratio = 1.0f * w / h;
    // 좌표계를 수정하기 전에 초기화합니다.
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    // 뷰포트를 창 전체크기로 설정합니다. 
    glViewport(0, 0, w, h);

    // 절단 공간을 설정합니다.
    gluPerspective(45,ratio,1,1000);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt(x, y, z, 
            x + lx,y + ly,z + lz,
            0.0f,1.0f,0.0f);
}

void drawSnowMan()
{
    glColor3f(1.0f, 1.0f, 1.0f);

    // 몸을 그립니다.
    glTranslatef(0.0f ,0.75f, 0.0f);
    glutSolidSphere(0.75f,20,20);

    // 머리를 그립니다.
    glTranslatef(0.0f, 1.0f, 0.0f);
    glutSolidSphere(0.25f,20,20);

    // 두 눈을 그립니다.
    glPushMatrix();
        glColor3f(0.0f,0.0f,0.0f);
        glTranslatef(0.05f, 0.10f, 0.18f);
        glutSolidSphere(0.05f,10,10);
        glTranslatef(-0.1f, 0.0f, 0.0f);
        glutSolidSphere(0.05f,10,10);
    glPopMatrix();

    // 코를 그립니다.
    glColor3f(1.0f, 0.5f , 0.5f);
    glRotatef(0.0f,1.0f, 0.0f, 0.0f);
    glutSolidCone(0.08f,0.5f,10,2);
}

GLuint createDL()
{
    GLuint snowManDL;

    // 디스플레이리스트를 생성하고 id 를 반환합니다.
    snowManDL = glGenLists(1);

    // 디스플레이리스트를 시작합니다.
    glNewList(snowManDL,GL_COMPILE);

    // 렌더링을 수행하는 함수를 호출합니다.
    drawSnowMan();

    // 디스플레이리스트를 끝마칩니다.
    glEndList();

    return(snowManDL);
}

void initScene()
{
    glEnable(GL_DEPTH_TEST);
    snowman_display_list = createDL();
}

void orientMe(float ang) 
{
    lx = sin(ang);
    lz = -cos(ang);
    glLoadIdentity();
    gluLookAt(x, y, z, 
            x + lx,y + ly,z + lz,
            0.0f,1.0f,0.0f);
}

void moveMeFlat(int i)
{
    x = x + i*(lx)*0.1;
    z = z + i*(lz)*0.1;
    glLoadIdentity();
    gluLookAt(x, y, z, 
            x + lx,y + ly,z + lz,
            0.0f,1.0f,0.0f);
}
```

아래 함수에 추가된 코드가 있습니다. 이 함수는 각각의 카메라 액션을 뜻하는 두 개의 변수가 0 이 아닌지 검사하고 0 이 아니라면 카메라의 필요한 동작에 적절한 함수를 호출합니다.

```cpp
void renderScene(void)
{
    if (deltaMove)
        moveMeFlat(deltaMove);
    if (deltaAngle)
    {
        angle += deltaAngle;
        orientMe(angle);
    }

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    // 지형을 그립니다.
    glColor3f(0.9f, 0.9f, 0.9f);
    glBegin(GL_QUADS);
        glVertex3f(-100.0f, 0.0f, -100.0f);
        glVertex3f(-100.0f, 0.0f, 100.0f);
        glVertex3f( 100.0f, 0.0f, 100.0f);
        glVertex3f( 100.0f, 0.0f, -100.0f);
    glEnd();

    // 36개의 눈사람을 그립니다.
    for(int i = -3; i < 3; i++)
        for(int j=-3; j < 3; j++)
        {
            glPushMatrix();
                glTranslatef(i*10.0,0,j * 10.0);
                glCallList(snowman_display_list);;
            glPopMatrix();
        }
    glutSwapBuffers();
}
```

다음에 나오는 함수들은 각각 특수키의 콜백함수로 일반키가 놓였을 때 호출되는 콜백함수로 등록합니다.

```cpp
void pressKey(int key, int x, int y)
{
    switch (key)
    {
    case GLUT_KEY_LEFT : 
        deltaAngle = -0.01f;
        break;
    case GLUT_KEY_RIGHT : 
        deltaAngle = 0.01f;
        break;
    case GLUT_KEY_UP : 
        deltaMove = 1;
        break;
    case GLUT_KEY_DOWN : 
        deltaMove = -1;
        break;
    }
}

void releaseKey(int key, int x, int y)
{
    switch (key)
    {
    case GLUT_KEY_LEFT : 
    case GLUT_KEY_RIGHT : 
        deltaAngle = 0.0f;
        break;
    case GLUT_KEY_UP : 
    case GLUT_KEY_DOWN : 
        deltaMove = 0;
        break;
    }
}
```

main 함수에는 세 줄의 코드를 추가했습니다.:

반복되는 키입력을 정지하기 위해서 glutIgnoreKeyRepeat 함수를 0 이 아닌 값을 인자로 주어 호출했고 그 다음에 glutSpecialUpFunc 와 glutKeyboardUpFunc 함수로 콜백함수를 등록했습니다.

```cpp
int main(int argc, char **argv)
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
    glutInitWindowPosition(100,100);
    glutInitWindowSize(640,360);
    glutCreateWindow("SnowMen from 3D-Tech");

    initScene();

    glutIgnoreKeyRepeat(1);
    glutKeyboardFunc(processNormalKeys);
    glutSpecialFunc(pressKey);
    glutSpecialUpFunc(releaseKey);

    glutDisplayFunc(renderScene);
    glutIdleFunc(renderScene);

    glutReshapeFunc(changeSize);

    glutMainLoop();

    return(0);
}
```

[VC 6.0 프로젝트 파일](https://github.com/skyfe79/GLUT-Tutorial/tree/master/glut53) 을 받아서 카메라 설정 함수들을 카메라 설정 함수들을 가지고 놀아보세요 :)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://sungcheol-kim.gitbook.io/glut-tutorials/chapter7.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
