BLOG main image
FunnyPR (32)
OpenGL (20)
PatternRecognition (7)
Tips (2)
XML (1)
DataMining (1)
Visitors up to today!
Today hit, Yesterday hit
daisy rss
tistory 티스토리 가입하기!
2014. 5. 20. 21:55

■ OpenGL: Modern OpenGL Tutorial Text Rendering 02[1]


FreeType 라이브러리로 폰트를 그리는 두번째 파트 

1. Introduction

이전 파트에서 우리는 각 폰트를 그리기 위한 텍스처를 만들어 그래픽 카드에 옵로딩 하였다. 

 - 요러한 방식이 비효율적이라고 한다.

 - 새롭게 계속 텍스쳐를 그래픽 카드에 올리는 것 보다는 전체 폰트를 그래픽 카드에 옵로드 했다가 쓰는 것이 더 효율적이라고 함.


method 1:

 - 간단한 방법으로 각 폰트에 대한 많은 텍스처를 가지는 것.

 - 즉 각 폰트에 대한 텍스처를 가지고 있다가 quad를 그릴때 텍스처만 바꾸어 주는 방식으로 간다.

 - 하지만 이와 같은 방법은 여러 폰트를 그릴때 엄청나게 많이 반복해서 quad를 그려줘야 함


method 2:

 - 덜 복잡한 방법은 왕 큰 하나의 텍스처에 모든 폰트의 값을 저장하고 있는 거지,

 - 그래서 각 폰트에 대한 텍스처 좌표와 quad의 버텍스를 매핑시키는 거야

 - 이 방법에서는 " texture atlas" 개념을 알고 있어야 한다고 함


texture atlas: 텍스처 아틀라스(atlas:지도책)

여러 이미지를 하나의 파일에 모아놓은 텍스처를 Atlas Texture라고하며, 일반적으로 툴없이

 포토샵으로 하게 될 경우 수정 및 텍스처 공간활용, 좌표 추출 등에서 많은 애를 먹게 된다.


2. texture atlas만들기 

텍스처 아틀라스는 여러 꼬맹이 이미지들이 하나의 패키지처럼 모여 있는 엄마 텍스처라고 생각하면 됨

- 꼬맹이 이미지들이 동일한 사이즈면 만들기 쉽다넹.

- 하지만 뚜둥 폰트 사이즈는 각각 달라!!!

- 텍스처 아틀라스를 만드는 많은 방법이 있지만 여기서는 간단한 방법을 사용한다고 함(휴 *_*)

- 텍스처 아틀라스를 만들기 전에 미리 폰트의 가로 세로 사이즈 등을 미리 알고 있어야 함


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
FT_GlyphSlot g = face->glyph;
int w = 0;
int h = 0;
 
for(int i = 32; i < 128; i++) {
  if(FT_Load_Char(face, i, FT_LOAD_RENDER)) {
    fprintf(stderr, "Loading character %c failed!\n", i);
    continue;
  }
 
  w += g->bitmap.width;
  h = std::max(h, g->bitmap.rows);
 
  /* you might as well save this value as it is needed later on */
  int atlas_width = w;
}

텍스처 아틀라스를 만드는 코드당. FT_GlyphSlot g 변수를 통해 한 폰트에 대한 정보를 가져옴 이 폰트의 사이즈를 미리 알고 ASCII 코드 32번째 부터 쭈우우욱 값을 읽어드림

 - 또한 g에 대한 정보로 아틀라스 사이즈 w, h를 구함 

다음으로는 이 아틀라스 사이즈를 가지고 하나의 빈 텍스처를 만듬(하나씩 찍기 위함이지)


1
2
3
4
5
6
7
GLuint tex;
glActiveTexture(GL_TEXTURE0);
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
 
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, w, h, 0, GL_ALPHA, GL_UNSIGNED_BYTE, 0);


이제 텍스처 아틀라스에 glyph images를 붙여 넣은 준비가 됬고 우리는 glTexSubImage2D()함수로 글립 이미지를 간단하게 텍스처 아틀라스에 넣을 수 있음등!!


1
2
3
4
5
6
7
8
9
10
int x = 0;
 
for(int i = 32; i < 128; i++) {
  if(FT_Load_Char(face, i, FT_LOAD_RENDER))
    continue;
 
  glTexSubImage2D(GL_TEXTURE_2D, 0, x, 0, g->bitmap.width, g->bitmap.rows, GL_ALPHA, GL_UNSIGNED_BYTE, g->bitmap.buffer);
 
  x += g->bitmap.width;
}


3. Caching glyph metrics and texture offsets

자 그럼 폰트를 아틀라스 텍스쳐에서 어떻게 가져와야 함!!!

정확한 위치에 폰트를 가지고 올라면 좌표(x,y) 그리고 x offset 그러니깐 몇행인지 그리고 폰트의 정보가 필요함

이 정보를 기억하기 위해 다음과 같은 구조체를 만듬, 이 구조체에 위 필요한 정보를 기억하여 캐쉬메모리로 사용해서 필요할때 마다 찾아 갈꺼얌


1
2
3
4
5
6
7
8
9
10
11
12
struct character_info {
  float ax; // advance.x
  float ay; // advance.y
 
  float bw; // bitmap.width;
  float bh; // bitmap.rows;
 
  float bl; // bitmap_left;
  float bt; // bitmap_top;
 
  float tx; // x offset of glyph in texture coordinates
} c[128];


텍스처에 glyph images를 넣는 루프에서 다음과 같이 수행해서 구조체에 정보를 쏘옥~

1
2
3
4
5
6
7
8
9
10
  c[*p].ax = g->advance.x >> 6;
  c[*p].ay = g->advance.y >> 6;
 
  c[*p].bw = g->bitmap.width;
  c[*p].bh = g->bitmap.rows;
 
  c[*p].bl = g->bitmap_left;
  c[*p].bt = g->bitmap_top;
 
  c[*p].tx = (float)x / w;


4. Rendering lines of text using the atlas

실제 텍스쳐 그리는 소스는 다음과 같다구웃!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
void render_text(const char *text, atlas * a, float x, float y, float sx, float sy) {
    const uint8_t *p;
 
    /* Use the texture containing the atlas */
    glBindTexture(GL_TEXTURE_2D, a->tex);
    glUniform1i(uniform_tex, 0);
 
    /* Set up the VBO for our vertex data */
    glEnableVertexAttribArray(attribute_coord);
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glVertexAttribPointer(attribute_coord, 4, GL_FLOAT, GL_FALSE, 0, 0);
 
    point coords[6 * strlen(text)];
    int c = 0;
 
    /* Loop through all characters */
    for (p = (const uint8_t *)text; *p; p++) {
        /* Calculate the vertex and texture coordinates */
        float x2 = x + a->c[*p].bl * sx;
        float y2 = -y - a->c[*p].bt * sy;
        float w = a->c[*p].bw * sx;
        float h = a->c[*p].bh * sy;
 
        /* Advance the cursor to the start of the next character */
        x += a->c[*p].ax * sx;
        y += a->c[*p].ay * sy;
 
        /* Skip glyphs that have no pixels */
        if (!w || !h)
            continue;
 
        coords[c++] = (point) {
        x2, -y2, a->c[*p].tx, a->c[*p].ty};
        coords[c++] = (point) {
        x2 + w, -y2, a->c[*p].tx + a->c[*p].bw / a->w, a->c[*p].ty};
        coords[c++] = (point) {
        x2, -y2 - h, a->c[*p].tx, a->c[*p].ty + a->c[*p].bh / a->h};
        coords[c++] = (point) {
        x2 + w, -y2, a->c[*p].tx + a->c[*p].bw / a->w, a->c[*p].ty};
        coords[c++] = (point) {
        x2, -y2 - h, a->c[*p].tx, a->c[*p].ty + a->c[*p].bh / a->h};
        coords[c++] = (point) {
        x2 + w, -y2 - h, a->c[*p].tx + a->c[*p].bw / a->w, a->c[*p].ty + a->c[*p].bh / a->h};
    }
 
    /* Draw all the character on the screen in one go */
    glBufferData(GL_ARRAY_BUFFER, sizeof coords, coords, GL_DYNAMIC_DRAW);
    glDrawArrays(GL_TRIANGLES, 0, c);
 
    glDisableVertexAttribArray(attribute_coord);
}


................\wikibooks-opengl-modern-tutorials\text02_atlas

위 폴더에서 text.cpp 파일을 실행시키면 되는데 

point coords[6 * strlen(text)]; 아이에서 배열 상수식 선언 에러 나올꺼야. 또 

coords[c++] 요라인도 

고칠라면 point coords 배열을 동적배열로 사용하고 

구조체 접근 또한 coords[c].x = x2; 요러한 형식으로 진행해야 하지 


최종 실행 결과


2번째 싸이트 방문해 보면 텍스쳐 아틀라스를 만들어 사용하는 것을 확인할 수 있다. 

3번째 싸이트 가면 텍스쳐를 여러개 만들어서 사용하는 방법이다. 

2번째 싸이트 보니 하... 그래서 3번째 싸이트 내용을 가지고 또 연습해 보자. 


[1] http://en.wikibooks.org/wiki/OpenGL_Programming/Modern_OpenGL_Tutorial_Text_Rendering_02

[2] http://lazyfoo.net/tutorials/OpenGL/23_freetype_fonts/index.php

[3] http://www.sccs.swarthmore.edu/users/03/sven/freetype_tut/