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/


2014. 5. 18. 16:38

■OpenGL: Very Simple Textured Text[1]


하 FreeType 라이브러리를 하다 OpenGL 2.0이 필요해서 잠깐 스톱을 했다. 2.0을 써야 하다니 난 그냥 1.0기준의 OpenGL 로 간단한 폰트를 만들고 싶은데.....더 검색을 해 보았다. 


요번에는 참고 1 사이트를 기준으로 작업을 하고자 한다.


흠 우선 폰트를 TGA 파일로 만드는 구나. 그래픽 어플리케이션을 만들때 폰트들을 만들어서 쓴다고 한다. 간단하게 김프(Gimp)라는 어플을 사용한다고 함.


우선  김프 사용법은 다음에 또 알아보고 사이트에서 제공되는 font.tga파일을 통해 폰트를 찍어 보자. 


step 1: 텍스쳐 및 블렌딩 설정

1
2
3
4
5
glEnable(GL_TEXTURE_2D);
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );
glEnable (GL_BLEND);
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);


step 2: 심플 폰트 코드 설정 

- 문자 맵 텍스쳐의 차원, 각 문자의 사이즈, 텍스쳐 ID

- TGA texture을 읽기 위해 NeHe Lesson 33에서 사용된 Texture 클래스를 사용함

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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
class Font
{
public:
    Font(GLuint init_texture, GLuint init_m_width, GLuint init_m_height,
           GLuint init_c_width, GLuint init_c_height);
     void drawText(GLfloat x, GLfloat y, GLint w, GLint h, char * text);
private:
    GLuint texture;
    GLint c_per_row;
 
    //bitmap setting
    GLuint m_width;
    GLuint m_height;
 
    //character settings
    GLuint c_width;
    GLuint c_height;
};
 
Font::Font(GLuint init_texture, GLuint init_m_width, 
                    GLuint init_m_height,
                    GLuint init_c_width, GLuint init_c_height) :
    texture(init_texture), m_width(init_m_width),
    m_height(init_m_height), c_width(init_c_width), 
    c_height(init_c_height)
    {
         c_per_row = m_width/c_width;
    }
 
void Font::drawText(GLfloat x, GLfloat y, GLint w, GLint h, char * text)
{
    glLoadIdentity();
    glTranslatef(x, y, 0.0f);
    glBindTexture( GL_TEXTURE_2D, texture );
    glBegin( GL_QUADS );
 
     //character location and dimensions
    GLfloat cx = 0.0f;
    GLfloat cy = 0.0f;
    GLfloat cw = float(w);
    GLfloat ch = float(h);
 
     //calculate how wide each character is in term of texture coords
     GLfloat dtx = float(c_width)/float(m_width);
     GLfloat dty = float(c_height)/float(m_height);
 
     for (char * c = text; *c != 0; c++, cx += cw) {
         // subtract the value of the first char in the character map
        // to get the index in our map
        int index = *c - '0';
        int row = index/c_per_row;
        int col = index%c_per_row;
 
        if (index < 0)
              throw GameException(__FILE__, __LINE__, "Character outside of font");
 
         // find the texture coords
         GLfloat tx = float(col * c_width)/float(m_width);
         GLfloat ty = float(row * c_height)/float(m_height);
 
         glTexCoord2d(tx,ty); glVertex2f(cx,cy);
         glTexCoord2d(tx+dtx,ty); glVertex2f(cx+cw,cy);
         glTexCoord2d(tx+dtx,ty+dty); glVertex2f(cx+cw,cy+ch);
         glTexCoord2d(tx,ty+dty); glVertex2f(cx,cy+ch);
    }
    glEnd();
}


step 3: 폰트 생성

1
2
3
Image image;
image.loadTGAImage("../images/font.tga");
font = new Font(Texture::build_texture(&image), 256, 256,19, 29);

Texture::bulid_texture 함수는 OpenGL texture ID를 반환함

TGA 폰트 이미지 사이즈가 256*256 그리고 각 폰트의 사이즈 19*29 임 


step 4: 폰트 그리기

1
2
glColor4f(1.0f, 0.0f, 0.0f, 1.0f); //make the text red
font->drawText(x, y, desired_width, desired_height, str);

폰트를 찍는데 요구된 사이즈에 좌표값 그리고 해당 str에 원하는 폰트를 넣어 프린트 하면 된다넹..


위와 같이 코딩해서 만들어 실행한 화면이 다음과 같다 라고 한다.



근데 말이지 난 해보니깐 저렇게 안나와 머징... 킁킁 배경이 투명이고 2D 지오메트릭에 이미지를 불러들인 텍스쳐를 4개의 꼭지점에 맵핑시키고 출력하면 배경과 같이 출력되던뎅...



저렇게 나오던뎅.. 소스도 약간수정했다.

우선 텍스쳐 맵핑에 대한 개념을 잡은거 같다. 

수정한 부분은 아래와 같음 그리고 참고사이트에 가면 소스파일이 있는데 다운 받아서 util.c, util,hpp, font.tga 파일을 써야 하는데 util.hpp 파일내에 FONT 클래스가 C++에서는 미리 정의된 클래스로 사용해선 안됨 때문에 적절하게 FONT 클래스 이름을 바꾸어서 사용해야함


1
2
3
4
        glTexCoord2d(tx, ty); glVertex2f(cx, cy + ch);
        glTexCoord2d(tx + dtx, ty); glVertex2f(cx + cw, cy + ch);
        glTexCoord2d(tx + dtx, ty + dty); glVertex2f(cx + cw, cy);
        glTexCoord2d(tx, ty + dty); glVertex2f(cx, cy);


왜 난 다르게 나올까... 한참 생각해 본다. 혹시 아시는 고수분들 계시면 뎃글 부탁 드립니다.


[1] http://www.andrewewhite.net/wordpress/2007/06/06/very-simple-text-in-opengl/

2014. 5. 16. 12:09

■ Visual Studio: Setting FreeType Library


FreeType는 폰트처리용 오픈소스 라이브러리이며 GPL 라이센스를 따른다.


이 글에서는 Windows 운영체제에서 Visual Studio(C++/MFC)를 기준으로 어떻게 FreeType 라이브러리 개발환경을 구현해야 하는지 알아보자 


1. FreeType Library 다운로드

http://freetype.sourceforge.net/download.html#stable : FreeType 사이트 

http://sourceforge.net/projects/freetype/files/ : FreeType 파일 

sourceforge에서 FreeType 파일 받기 



파일 받은 후 경로 상관 없이 압축풀기 


2. FreeType Library 빌드

압축풀려진 폴더에서 해당 visual 버전별 폴더로 이동 하여 프로젝트 파일 열기 

......\ft253\freetype-2.5.3\builds\windows\vc2010


프로젝트 열면 솔루션 탐색기에서 다음과 같이 FreeType 소스코드와 헤더 파일을 확인할 수 있음


솔루션 빌드 하면 다음과 같이 freeType253_D.lib가 생성됨 욘속을 사용해야 함


생성된 lib 파일 확인: 다른 환경의 라이브러리를 만들기 위해서는 빌드시 플랫폼을 설정하면 됨

.......\ft253\freetype-2.5.3\objs\win32\vc2010



3. 새 프로젝트 생성 및 FreeType 헤더파일 추가

MFC-대화상자 기반 프로젝트 생성

생성된 프로젝트 폴더에 FreeType 헤더파일 폴더 복사 

Copy the include Folder of FreeType to User Project Folder

.......\ft253\freetype-2.5.3\include


생성된 프로젝트에 복사된 FreeType 헤더파일 폴더


4. 프로젝트 속성 설정 

프로젝트 속성-> 구성속성 -> C/C++  -> 추가 포함 디렉토리 -> 편집 -> Include 폴더 선택 


추가된 FreeType 헤더파일 확인 


라이브러리 추가 

프로젝트 속성-> 구성속성 -> 링커 -> 일반 -> 추가라이브러리 디렉토리 -> 이전 생성된 라이브러리 있는 폴더 선택 

.......\ft253\freetype-2.5.3\objs\win32\vc2010


추가 종속성 설정 

링커 -> 입력 -> 추가 종속성 -> freetype253_D.lib;


5. FreeType 초기화 및 프로젝트 빌드 

가. 헤더파일 선언

#include <ft2build.h>

#include FT_FREETYPE_H


나. 라이브러리 초기화 (OnInitDialog() 에서 확인)

FT_Library ft;


if (FT_Init_FreeType(&ft)) {

fprintf(stderr, "Could not init freetype library\n");

return 1;

}


다. 컴파일 및 확인 

흠 우선은 에러 없이 잘 컴파일 되었넹 what a wonderful work!!!!

씨익 ^____________________^


참고 사이트

   - http://mgun.tistory.com/115

   - http://blog.naver.com/PostView.nhn?blogId=pumpguy&logNo=30098170538

   - http://www.sccs.swarthmore.edu/users/03/sven/freetype_tut/

'OpenGL' 카테고리의 다른 글

OpenGL: Modern OpenGL Tutorial Text Rendering 02  (0) 2014.05.20
OpenGL: Very Simple Textured Text  (1) 2014.05.18
OpenGL: Modern OpenGL Tutorial Text Rendering 01  (0) 2014.05.15
OpenGL: Text in OpenGL  (0) 2014.05.15
OpenGL: Selection and Picking  (0) 2014.05.05