# 점그리기

* GL\_POINTS
* glPointSize()
* glVertex2f(), glVertex3f()

앞 장에서는 윈도우즈에서 쉽게 OpenGL 을 이용한 어플리케이션을 만들기 위해서 윈도우용 OpenGL 프레임웤을 만들어 보았다. 그 프레임웤을 사용해서 OpenGL 에 대해서 알아보자. 그 첫번재 과정으로 점(Point) 그리기부터 알아볼 것이다. 점(Point)은 정점(Vertex)이라고 부르는 2차원 이상의 좌표계 위치 조합으로 나타낸다. X축과 Y축으로 표현되는 2D 정점은 OpenGL 에 의해서 Z 축도 포함하게 된다. OpenGL 은 모든 정점을 4가지 좌표축의 위치 조합(X축, Y축, Z축, W축)으로 나타낸다. 이 좌표계를 동차좌표계(homogeneous coordinate system) 이라고 하는데 자세한 내용은 OpenGL 전문서적을 참고하자. 만약 W 가 0 이 아니라면 이 정점은 유클리드 3D 좌표계(X/W, Y/W, Z/W) 의 점에 해당된다. OpenGL 명령어에서 W 를 사용할 수 있으나 거의 쓰이지 않는다. 만약 W 가 쓰이지 않는다면 그 값을 1.0 으로 생각하면 된다. 즉, glVertex2f(1.0f, 1.0f) 라 하면 (1.0, 1.0, 0.0, 1.0) 의 정점을 나타내는 것이다. 다음은 정점을 나타내는 OpenGL 의 함수 그룹이다. 함수는 두 그룹으로 나뉘는데 직접 좌표계 위치를 받는 것과 각 좌표계 위치의 배열을 받는 것이 있다. 배열을 받는 것은 함수의 이름 끝에 v 자 붙는다.

```cpp
void glVertex2d( GLdouble x, GLdouble y ) 
void glVertex2f( GLfloat x, GLfloat y ) 
void glVertex2i( GLint x, GLint y ) 
void glVertex2s( GLshort x, GLshort y ) 
void glVertex3d( GLdouble x, GLdouble y, GLdouble z ) 
void glVertex3f( GLfloat x, GLfloat y, GLfloat z ) 
void glVertex3i( GLint x, GLint y, GLint z ) 
void glVertex3s( GLshort x, GLshort y, GLshort z ) 
void glVertex4d( GLdouble x, GLdouble y, GLdouble z, GLdouble w ) 
void glVertex4f( GLfloat x, GLfloat y, GLfloat z, GLfloat w ) 
void glVertex4i( GLint x, GLint y, GLint z, GLint w ) 
void glVertex4s( GLshort x, GLshort y, GLshort z, GLshort w )
```

```cpp
void glVertex2dv( const GLdouble *v )
void glVertex2fv( const GLfloat *v ) 
void glVertex2iv( const GLint *v ) 
void glVertex2sv( const GLshort *v ) 
void glVertex3dv( const GLdouble *v ) 
void glVertex3fv( const GLfloat *v ) 
void glVertex3iv( const GLint *v ) 
void glVertex3sv( const GLshort *v ) 
void glVertex4dv( const GLdouble *v ) 
void glVertex4fv( const GLfloat *v ) 
void glVertex4iv( const GLint *v ) 
void glVertex4sv( const GLshort *v )
```

OpenGL 에서 그리기는 glBegin() 함수와 glEnd() 함수 사이에서 할 수 있는데 그릴 수 있는 것은 다음과 같은 종류가 있다.

```cpp
glBegin( GL_POINT);
    점을 그린다.
glEnd();

glBegin( GL_LINES );
    선을 그린다.
glEnd();

glBegin( GL_POLYGON );
    다각형을 그린다.
glEnd();

glBegin( GL_TRIANGLES );
    삼각형을 그린다.
glEnd();

glBegin( GL_QUADS );
    사각형을 그린다.
glEnd();

glBegin( GL_LINE_STRIP );
    겹친 선을 그린다.
glEnd();

glBegin( GL_LINE_LOOP );
    겹치지 않고 연결 된 선을 그린다.
glEnd();

glBegin( GL_TRIANGLE_STRIP );
    삼각형이 연결된 도형을 그린다.
glEnd();

glBegin( GL_TRIANBLE_FAN );
    한점을 중심으로 삼각형이 연결된 도형을 그린다.
glEnd();

glBegin( GL_QUAD_STRIP );
    사각형이 이어진 도형을 그린다.
glEnd();
```

아래의 그림을 보면 이해하는데 도움이 될 것이다.

![](/files/-M3x25ANYQ-bDz_JyvLW)

5 개의 점을 그리는 코드를 쓰면 아래와 같다.

```cpp
glBegin( GL_POINTS )
    glVertex2f( 1.0f, 1.0f ); //v0
    glVertex2f( 1.5f, 0.5f ); //v1
    glVertex2f( 2.0f, 0.0f ); //v2
    glVertex2f( 2.5f, 0.5f ); //v3
    glVertex2f( 3.0f, 1.0f ); //v4
glEnd();
```

점의 크기는 항상 일정한 것이 아니라 변경가능하다. 점의 크기를 변경하는 OpenGL 함수는 아래와 같다. 점의 크기로 설정할 수 있는 최대값은 MS 에서 구현한 OpenGL 에서는 10.0 까지이다. OpenGL 스펙에서는 1.0 만지원된다.

```cpp
void glPointSize( GLfloat size );
```

이 내용을 바탕으로 점이 커졌다 작아졌다 하는 프로그램을 만들어보자.

![](/files/-M3x25APsNreUBc2uQrO)

위의 그림은 프로그램을 실행시킨 결과 이고 아래의 코드는 위 프로그램의 코드이다. 앞에서 만든 프레임웤을 바탕으로 만들어진 것임을 기억하자.

```cpp
#include <windows.h>
#include "lib\egl.h"

struct Point3D
{
    GLfloat x, y, z;
};

class eglSubWindow : public eglWindow
{
private:
    GLfloat mPointSize; //점의 크기
    Point3D mPointList[5]; //점의 리스트 
public:
    virtual void RenderGLScene(void);
    virtual void OnCreate(WPARAM wParam, LPARAM lParam);
};

void eglSubWindow::OnCreate(WPARAM wParam, LPARAM lParam)
{
    //점의 위치를 초기화한다.
    mPointList[0].x = 0.0f;
    mPointList[0].y = 0.0f;
    mPointList[0].z = -10.0f;

    mPointList[1].x = 1.0f;
    mPointList[1].y = 1.0f;
    mPointList[1].z = -10.0f;

    mPointList[2].x = 2.0f;
    mPointList[2].y = 2.0f;
    mPointList[2].z = -10.0f;

    mPointList[3].x = -1.0f;
    mPointList[3].y = -1.0f;
    mPointList[3].z = -10.0f;

    mPointList[4].x = -2.0f;
    mPointList[4].y = -2.0f;
    mPointList[4].z = -10.0f;

    //점의 크기를 초기화한다.
    mPointSize = 1.0f;
}

void eglSubWindow::RenderGLScene(void)
{
    static int i=0;
    static GLfloat step=0.1f;

    eglWindow::RenderGLScene();

    glColor3f(1.0f, 0.0f, 0.0f); //점의 색을 빨강색으로 설정한다.
    glPointSize(mPointSize); //점의 크기를 설정한다.
    glBegin(GL_POINTS); //점을 그린다.
        for(i=0; i<sizeof(mPointList)/sizeof(Point3D); ++i)
        {
            glVertex3f(mPointList[i].x, mPointList[i].y, mPointList[i].z);
        }
    glEnd();

    mPointSize += step;

    if(mPointSize >= 10.0f)
    {
        step = -step;
    }
    else if(mPointSize <= 0.0f)
    {
        step = -step;
    }
}

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
    eglSubWindow app;
    app.Create(FALSE,"OpenGL glPoint");
    return app.Run();
}
```

다음은 마우스 커서가 위치한 곳에서 마우스 왼쪽 버튼을 누르면 점을 찍는 프로그램을 만들어보자.

![](/files/-M3x25ARYECY-yApQ5Ft)

아래는 이 프로그램의 소스이며 주석과 굵은 글씨로 적혀있는 코드를 주의해서 보자. 참고로 프레임웤에 몇가지의 파일이 추가되어 내용이 업데이트 되었다.

```cpp
#define EGL_USE_STL
#include "lib\egl.h"

struct Point3D
{
    GLfloat x, y, z;
    Point3D(GLfloat ax, GLfloat ay, GLfloat az) { x=ax; y=ay; z=az; }
};

typedef vector<Point3D> point_list;
typedef vector<Point3D>::iterator piter;

class eglSubWindow : public eglWindow
{
private:
    point_list mPointList;
    GLsizei ClientWidth; //윈도우의 너비
    GLsizei ClientHeight; //윈도우의 높이
    GLfloat Range; //클리핑 영역의 범위
public:
    virtual void RenderGLScene(void);
    virtual void OnCreate(WPARAM wParam, LPARAM lParam);
    virtual void OnLButtonDown(WPARAM wParam, LPARAM lParam);
    virtual void OnSize(WPARAM wParam, LPARAM lParam);
};
void eglSubWindow::OnCreate(WPARAM wParam, LPARAM lParam)
{
    ClientWidth = ClientHeight = 0;
    Range = 5.0f; //클리핑 영역의 범의를 5 로 초기화한다.
}
void eglSubWindow::OnSize(WPARAM wParam, LPARAM lParam)
{
    GLsizei width = LOWORD(lParam);
    GLsizei height = HIWORD(lParam);

    if (height == 0)
        height = 1; 

    ClientWidth = width;
    ClientHeight = height;

    glViewport( 0, 0, width, height ); 

    glMatrixMode(GL_PROJECTION); 
    glLoadIdentity(); 

    glOrtho(-Range, Range, -Range, Range, 1.0f, 100.0f);

    glMatrixMode(GL_MODELVIEW); 
    glLoadIdentity(); 
}

void eglSubWindow::OnLButtonDown(WPARAM wParam, LPARAM lParam)
{
    GLfloat xPos = (GLfloat)(LOWORD(lParam));
    GLfloat yPos = (GLfloat)(HIWORD(lParam));

    GLfloat glX = ((xPos * (2*Range)) / ClientWidth) - Range;
    GLfloat glY = ((yPos * (2*Range)) / ClientHeight) - Range;

    mPointList.push_back(Point3D(glX, -glY, 0.0f));
    //-glY 인 것은 윈도우즈의 기본 좌표계에서는 Y 축이 아래로 내려 갈 수록 Y 축의 값이 증가한다. 하지만 OpenGL 좌표축은 그와 반대이므로 - 를 해준다.

    TRACE("glVertex3f[ %f , %f , %f ]\n", glX, -glY, 0.0f);
}

void eglSubWindow::RenderGLScene(void)
{
    eglWindow::RenderGLScene();

    glTranslatef(0.0f, 0.0f, -10.0f);
    glColor3f(1.0f, 0.0f, 0.0f);
    glPointSize(10.0f);
    glBegin(GL_POINTS);
        for(piter i=mPointList.begin(); i!=mPointList.end(); ++i)
        {
            glVertex3f((*i).x, (*i).y, (*i).z); 
        }
    glEnd();
}

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
    eglSubWindow app;
    app.Create(FALSE,"EDin's OpenGL : 점찍기");
    return app.Run();
}
```


---

# 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/opengl-tutorial/chapter3.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.
