■ 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/
'OpenGL' 카테고리의 다른 글
OpenGL: 2D Scatter Plot(Demo Video) (1) | 2014.05.25 |
---|---|
OpenGL: Tutorial on using FreeType Fonts in OpenGL (1) | 2014.05.21 |
OpenGL: Very Simple Textured Text (1) | 2014.05.18 |
Visual Studio: Setting FreeType Library (0) | 2014.05.16 |
OpenGL: Modern OpenGL Tutorial Text Rendering 01 (0) | 2014.05.15 |