■ OpenGL: 2D Scatter Plot(Demo Video)
흠냐 우여곡절 끝에 간단한 2D Scatter Plot 그래프를 완성하였다. 미흡하지만 만족한다.
다차원의 패턴을 저차원으로 매핑하는 결과들은 대부분 2-3 차원으로 축소된다. 때문에 2-3차원 scatter, line, bar 그래프가 필요하다. 예전에는 오픈된 라이브러리를 가져다 쓰니 내 맘에 맞게 못고치는 부분이 있었다. 초심으로 돌아가 하나씩 만들어가고자 한다.
- font : FreeType library
- using vertex array for drawing geometrics
- useing gluPerspective()
- based on MFC(MDI)
Sample Data: Result of SAMANN(Sammon Artificial Neural Network): not De-Normalized Data
화질이 좀 안좋게 나오네... 저렇게 나쁘지 않음..
'OpenGL' 카테고리의 다른 글
OpenGL: Tutorial on using FreeType Fonts in OpenGL (1) | 2014.05.21 |
---|---|
OpenGL: Modern OpenGL Tutorial Text Rendering 02 (0) | 2014.05.20 |
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 |
■ OpenGL: Tutorial on using FreeType Fonts in OpenGL[1]
네헤 라는 곳!!! 여기에 좋은 글들이 많네 .. 자 이 내용을 중심으로 이 사람은 어떻게 FreeType library를 활용했는지 보자.
1. MSVC(Microsoft Visual C++) 새 프로젝트 생성
- FreeType Library - Include folder 포함
- 라이브러리 설정(OpenGL.dlls, FreeType.dlls)
2. FreeType 설정 및 빌드를 위한 파일 복사
참고 사이트 하단에 가면 "DOWNLOAD visual C++ code for This Lesson"
- 클릭해서 다운로드
- 폴더 내에 "freetype.cpp" and "freetype.h" 파일을 생성한 프로젝트에 복사
- *.dll 파일도 생성한 프로젝트에 복사
3. FreeType 헤더파일 분석
-#include <xxxx.h> 파일들은 핸들링 및 보다 쉬운 디버깅을 위해 선언
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 | #ifndef FREE_NEHE_H #define FREE_NEHE_H // FreeType Headers #include <ft2build.h> #include <freetype/freetype.h> #include <freetype/ftglyph.h> #include <freetype/ftoutln.h> #include <freetype/fttrigon.h> // OpenGL Headers #include <windows.h> // (The GL Headers Need It) #include <GL/gl.h> #include <GL/glu.h> // Some STL Headers #include <vector> #include <string> // Using The STL Exception Library Increases The // Chances That Someone Else Using Our Code Will Correctly // Catch Any Exceptions That We Throw. #include <stdexcept> // MSVC Will Spit Out All Sorts Of Useless Warnings If // You Create Vectors Of Strings, This Pragma Gets Rid Of Them. #pragma warning(disable: 4786) |
- WGL(Window OpenGL)
- 폰트 저장을 위해 구조체 선언 및 네임스페이스로 욘속이 freetype 이라고 이름 지어줌 낭낭
- 머 13장에서 배웠던 내용이라는데 난 그냥 이글만 봐서... 느낌상 위 구조체를 사용함으로써 하나의 명령 glCAllLists 를 사용하여 문자열을 출력할 수 있는 좋은 능력을 보여준다고 하넹 +_+ 흣(대단한 녀석이군)
- 128ASCII 코드를 사용하기 때문에 128개의 텍스쳐를 만들어야 함. 마지막 비트는 폰트의 픽셀 높이 정보라는군.
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 | ///Wrap everything in a namespace, that we can use common ///function names like "print" without worrying about ///overlapping with anyone else's code. namespace freetype { //Inside of this namespace, give ourselves the ability //to write just "vector" instead of "std::vector" using std::vector; //Ditto for string. using std::string; //This holds all of the information related to any //freetype font that we want to create. struct font_data { float h; ///< Holds the height of the font. GLuint * textures; ///< Holds the texture id's GLuint list_base; ///< Holds the first display list id //The init function will create a font of //of the height h from the file fname. void init(const char * fname, unsigned int h); //Free all the resources assosiated with the font. void clean(); }; //The flagship function of the library - this thing will print //out text at window coordinates x,y, using the font ft_font. //The current modelview matrix will also be applied to the text. void print(const font_data &ft_font, float x, float y, const char *fmt, ...) ; } #endif |
마지막으로 우리는 문자열을 출력할 수 있는 프로토타입(prototype)가 필요하다고 하는군. 위 코드 마지막 줄에 프린트 욘속을 말함.
4. FreeType.cpp 파일 분석
- 각 문자를 찍기 위해 텍스쳐를 사용함.
- OpenGL 텍스쳐들은 2의 제곱을 가지는 차원수를 가져야 한다고 함.
1 2 3 4 5 6 7 8 9 | // This Function Gets The First Power Of 2 >= The // Int That We Pass It. inline int next_p2 (int a ) { int rval=1; // rval<<=1 Is A Prettier Way Of Writing rval*=2; while(rval<a) rval<<=1; return rval; } |
해서 위와 같은 소스로 2제곱을 해서 리턴함
다음 함수가 제일 중요함 각 폰트의 Glyph 정보를 읽고 bitmap 저장
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | // Create A Display List Corresponding To The Given Character. void make_dlist ( FT_Face face, char ch, GLuint list_base, GLuint * tex_base ) { // The First Thing We Do Is Get FreeType To Render Our Character // Into A Bitmap. This Actually Requires A Couple Of FreeType Commands: // Load The Glyph For Our Character. if(FT_Load_Glyph( face, FT_Get_Char_Index( face, ch ), FT_LOAD_DEFAULT )) throw std::runtime_error("FT_Load_Glyph failed"); // Move The Face's Glyph Into A Glyph Object. FT_Glyph glyph; if(FT_Get_Glyph( face->glyph, &glyph )) throw std::runtime_error("FT_Get_Glyph failed"); // Convert The Glyph To A Bitmap. FT_Glyph_To_Bitmap( &glyph, ft_render_mode_normal, 0, 1 ); FT_BitmapGlyph bitmap_glyph = (FT_BitmapGlyph)glyph; // This Reference Will Make Accessing The Bitmap Easier. FT_Bitmap& bitmap=bitmap_glyph->bitmap; |
이제 OpenGL Texture를 위한 legal source를 만들기 위해 빈공간에 저장된 bitmap 정보를 저장함
- OpenGL에서 bitmap는 픽셀당 8bit 정보 저장
- grays를 저장할 수 있음(anti-aliased text를 만드는데 필요한 정보임)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | // Use Our Helper Function To Get The Widths Of // The Bitmap Data That We Will Need In Order To Create // Our Texture. int width = next_p2( bitmap.width ); int height = next_p2( bitmap.rows ); // Allocate Memory For The Texture Data. GLubyte* expanded_data = new GLubyte[ 2 * width * height]; // Here We Fill In The Data For The Expanded Bitmap. // Notice That We Are Using A Two Channel Bitmap (One For // Channel Luminosity And One For Alpha), But We Assign // Both Luminosity And Alpha To The Value That We // Find In The FreeType Bitmap. // We Use The ?: Operator To Say That Value Which We Use // Will Be 0 If We Are In The Padding Zone, And Whatever // Is The FreeType Bitmap Otherwise. for(int j=0; j <height;j++) { for(int i=0; i < width; i++){ expanded_data[2*(i+j*width)]= expanded_data[2*(i+j*width)+1] = (i>=bitmap.width || j>=bitmap.rows) ? 0 : bitmap.buffer[i + bitmap.width*j]; } } |
위 작업 후 OpenGL Texture 를 만들어야 함.
- 알파 값을 통해 투명도 설정 가능하게 해놨음
1 2 3 4 5 6 7 8 9 10 11 12 13 | // Now We Just Setup Some Texture Parameters. glBindTexture( GL_TEXTURE_2D, tex_base[ch]); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); // Here We Actually Create The Texture Itself, Notice // That We Are Using GL_LUMINANCE_ALPHA To Indicate That // We Are Using 2 Channel Data. glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, expanded_data ); // With The Texture Created, We Don't Need The Expanded Data Anymore. delete [] expanded_data; |
이제 우리는 텍스트를 그리기 위해 텍스쳐가 맵핑된 quads를 사용할 거얌!
- quads를 이용함으로써 장점: 회전, 크기 변경, 문자열 사용 가능, 색상 적용 가능
흣 +_+
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 | // Now We Create The Display List glNewList(list_base+ch,GL_COMPILE); glBindTexture(GL_TEXTURE_2D,tex_base[ch]); glPushMatrix(); // First We Need To Move Over A Little So That // The Character Has The Right Amount Of Space // Between It And The One Before It. glTranslatef(bitmap_glyph->left,0,0); // Now We Move Down A Little In The Case That The // Bitmap Extends Past The Bottom Of The Line // This Is Only True For Characters Like 'g' Or 'y'. glTranslatef(0,bitmap_glyph->top-bitmap.rows,0); // Now We Need To Account For The Fact That Many Of // Our Textures Are Filled With Empty Padding Space. // We Figure What Portion Of The Texture Is Used By // The Actual Character And Store That Information In // The x And y Variables, Then When We Draw The // Quad, We Will Only Reference The Parts Of The Texture // That Contains The Character Itself. float x=(float)bitmap.width / (float)width, y=(float)bitmap.rows / (float)height; // Here We Draw The Texturemapped Quads. // The Bitmap That We Got From FreeType Was Not // Oriented Quite Like We Would Like It To Be, // But We Link The Texture To The Quad // In Such A Way That The Result Will Be Properly Aligned. glBegin(GL_QUADS); glTexCoord2d(0,0); glVertex2f(0,bitmap.rows); glTexCoord2d(0,y); glVertex2f(0,0); glTexCoord2d(x,y); glVertex2f(bitmap.width,0); glTexCoord2d(x,0); glVertex2f(bitmap.width,bitmap.rows); glEnd(); glPopMatrix(); glTranslatef(face->glyph->advance.x >> 6 ,0,0); // Increment The Raster Position As If We Were A Bitmap Font. // (Only Needed If You Want To Calculate Text Length) // glBitmap(0,0,0,0,face->glyph->advance.x >> 6,0,NULL); // Finish The Display List glEndList(); } |
다음 init함수는 FreeType Font 라이브러리를 초기화 하고 주어진 폰트 파일을 읽은 다음 폰트 사이즈를 설정한 후 해당 갯수의 텍스쳐를 생성하여 정보를 저장하는 작업
준비 작업임
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 | void font_data::init(const char * fname, unsigned int h) { // Allocate Some Memory To Store The Texture Ids. textures = new GLuint[128]; this->h=h; // Create And Initilize A FreeType Font Library. FT_Library library; if (FT_Init_FreeType( &library )) throw std::runtime_error("FT_Init_FreeType failed"); // The Object In Which FreeType Holds Information On A Given // Font Is Called A "face". FT_Face face; // This Is Where We Load In The Font Information From The File. // Of All The Places Where The Code Might Die, This Is The Most Likely, // As FT_New_Face Will Fail If The Font File Does Not Exist Or Is Somehow Broken. if (FT_New_Face( library, fname, 0, &face )) throw std::runtime_error("FT_New_Face failed (there is probably a problem with your font file)"); // For Some Twisted Reason, FreeType Measures Font Size // In Terms Of 1/64ths Of Pixels. Thus, To Make A Font // h Pixels High, We Need To Request A Size Of h*64. // (h << 6 Is Just A Prettier Way Of Writing h*64) FT_Set_Char_Size( face, h << 6, h << 6, 96, 96); // Here We Ask OpenGL To Allocate Resources For // All The Textures And Display Lists Which We // Are About To Create. list_base=glGenLists(128); glGenTextures( 128, textures ); // This Is Where We Actually Create Each Of The Fonts Display Lists. for(unsigned char i=0;i<128;i++) make_dlist(face,i,list_base,textures); // We Don't Need The Face Information Now That The Display // Lists Have Been Created, So We Free The Assosiated Resources. FT_Done_Face(face); // Ditto For The Font Library. FT_Done_FreeType(library); } |
폰트와 관련된 텍스쳐와 displaylist를 초기화 시키는 함수
1 2 3 4 5 | void font_data::clean() { glDeleteLists(list_base,128); glDeleteTextures(128,textures); delete [] textures; } |
자원을 썼으니 반납하시오!!!!
윈도우 화면 투영 함수
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | // A Fairly Straightforward Function That Pushes // A Projection Matrix That Will Make Object World // Coordinates Identical To Window Coordinates. inline void pushScreenCoordinateMatrix() { glPushAttrib(GL_TRANSFORM_BIT); GLint viewport[4]; glGetIntegerv(GL_VIEWPORT, viewport); glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); gluOrtho2D(viewport[0],viewport[2],viewport[1],viewport[3]); glPopAttrib(); } // Pops The Projection Matrix Without Changing The Current // MatrixMode. inline void pop_projection_matrix() { glPushAttrib(GL_TRANSFORM_BIT); glMatrixMode(GL_PROJECTION); glPopMatrix(); glPopAttrib(); } |
폰트 출력함수
출력함수는 lesson13과 매우 흡사하나 두가지 중요한 점이 다르다.
- 비트멥들 대신 2채널의 텍스쳐를 사용하기 위해 OpenGL 활성화 flags 설정
- 새로운 라인을 다루기 위해 추가적인 기능을 넣었음.
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 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 | ///Much like Nehe's glPrint function, but modified to work ///with freetype fonts. void print(const font_data &ft_font, float x, float y, const char *fmt, ...) { // We want a coordinate system where things coresponding to window pixels. pushScreenCoordinateMatrix(); GLuint font=ft_font.list_base; float h=ft_font.h/.63f; //We make the height about 1.5* that of char text[256]; // Holds Our String va_list ap; // Pointer To List Of Arguments if (fmt == NULL) // If There's No Text *text=0; // Do Nothing else { va_start(ap, fmt); // Parses The String For Variables vsprintf(text, fmt, ap); // And Converts Symbols To Actual Numbers va_end(ap); // Results Are Stored In Text } //Here is some code to split the text that we have been //given into a set of lines. //This could be made much neater by using //a regular expression library such as the one avliable from //boost.org (I've only done it out by hand to avoid complicating //this tutorial with unnecessary library dependencies). const char *start_line=text; vector<string> lines; for(const char *c=text;*c;c++) { if(*c=='\n') { string line; for(const char *n=start_line;n<c;n++) line.append(1,*n); lines.push_back(line); start_line=c+1; } } /* if(start_line) { string line; for(const char *n=start_line;n<c;n++) line.append(1,*n); lines.push_back(line); } */ glPushAttrib(GL_LIST_BIT | GL_CURRENT_BIT | GL_ENABLE_BIT | GL_TRANSFORM_BIT); glMatrixMode(GL_MODELVIEW); glDisable(GL_LIGHTING); glEnable(GL_TEXTURE_2D); glDisable(GL_DEPTH_TEST); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glListBase(font); float modelview_matrix[16]; glGetFloatv(GL_MODELVIEW_MATRIX, modelview_matrix); //This is where the text display actually happens. //For each line of text we reset the modelview matrix //so that the line's text will start in the correct position. //Notice that we need to reset the matrix, rather than just translating //down by h. This is because when each character is //draw it modifies the current matrix so that the next character //will be drawn immediatly after it. for(int i=0;i<lines.size();i++) { glPushMatrix(); glLoadIdentity(); glTranslatef(x,y-h*i,0); glMultMatrixf(modelview_matrix); // The commented out raster position stuff can be useful if you need to // know the length of the text that you are creating. // If you decide to use it make sure to also uncomment the glBitmap command // in make_dlist(). // glRasterPos2f(0,0); glCallLists(lines[i].length(), GL_UNSIGNED_BYTE, lines[i].c_str()); // float rpos[4]; // glGetFloatv(GL_CURRENT_RASTER_POSITION ,rpos); // float len=x-rpos[0]; glPopMatrix(); } glPopAttrib(); pop_projection_matrix(); } |
5. 사용방법
step 1: 헤더파일 선언
1 | #include "freetype.h" // Header for our little font library. |
step 2: 전역 font_data object 생성
1 2 | // This holds all the information for the font that we are going to create. freetype::font_data our_font; |
step 3: 폰트 자원의 메모리 할당 및 해제
1 | our_font.init("test.TTF", 16); //Build the freetype font |
종료 함수에 삽입
1 | our_font.clean(); |
step 4: 폰트 드로웅~~~
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 | int DrawGLScene(GLvoid) // Here's Where We Do All The Drawing { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear Screen And Depth Buffer glLoadIdentity(); // Reset The Current Modelview Matrix glTranslatef(0.0f,0.0f,-1.0f); // Move One Unit Into The Screen // Blue text glColor3ub(0,0,0xff); // Position the WGL Text On The Screen glRasterPos2f(-0.40f, 0.35f); glPrint("Active WGL Bitmap Text With NeHe - %7.2f", cnt1); // Print GL Text To The Screen // Here We Print Some Text Using Our Freetype Font // The Only Really Important Command Is The Actual Print() Call, // But For The Sake Of Making The Results A Bit More Interesting // I Have Put In Some Code To Rotate And Scale The Text. // Red Text glColor3ub(0xff,0,0); glPushMatrix(); glLoadIdentity(); glRotatef(cnt1,0,0,1); glScalef(1,.8+.3*cos(cnt1/5),1); glTranslatef(-180,0,0); freetype::print(our_font, 320, 200, "Active FreeType Text - %7.2f", cnt1); glPopMatrix(); // Uncomment This To Test Out Print's Ability To Handle Newlines. // freetype::print(our_font, 320, 200, "Here\nthere\nbe\n\nnewlines\n.", cnt1); cnt1+=0.051f; // Increase The First Counter cnt2+=0.005f; // Increase The First Counter return TRUE; // Everything Went OK } |
step 5: 예외처리 함수 삽입(+____+;;;)
1 2 3 4 | MSG msg; // Windows Message Structure BOOL done=FALSE; // Bool Variable To Exit Loop try { |
1 2 3 4 5 6 7 8 9 10 | // Shutdown KillGLWindow(); // Kill The Window // Catch Any Exceptions That Were Thrown } catch (std::exception &e) { MessageBox(NULL,e.what(),"CAUGHT AN EXCEPTION",MB_OK | MB_ICONINFORMATION); } return (msg.wParam); // Exit The Program } |
Now if we ever hit an exception, we will get a little message box telling us what happened. Note that exception handling can slow down your code, so when you are compiling a release version of your program, you may want to go to Project->Settings->C/C++, switch to the "C++ Language" category, and turn off exception handling.
So that's it! Compile the program and you should see some nice FreeType rendered text moving around underneath the original bitmapped text from lesson 13.
마지막 글
약간의 버그가 있다고 하넹
http://nehe.gamedev.net/data/lessons/http://www.cs.northwestern.edu/~sco590/fonts_tutorial.html
위 사이트 가서 버그를 샤샤삭~~~
뚜둥 실행화면
자 이렇게 나온단다.
나는 MFC 기반의 프로젝트를 만들고 있기 때문에 아마 좀 다르게 나오겠지 적용방법도 다르고 한번 해보자구웃!
역시나 제대로 출력이 안되넹
glPrint("FreeType using multi texture!!"); 요렇게 해서 찍어 봤지..
뒤에 g라는 욘속이 들어 가네 왜 그러징.. ㅋㅋ
흣... 이거 제대로 찍을라면 소스를 좀 수정해야 함.
아놔운서!!!(-_ㅡ;;)
수정해야 하는 소스는 다음과 같다.
위치: FreeType.cpp : void print(const font_data &ft_font, float x, float y, const char *fmt, ...)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | const char *start_line=text; vector<string> lines; for(const char *c=text;*c;c++) { if(*c=='\n') { string line; for(const char *n=start_line;n<c;n++) line.append(1,*n); lines.push_back(line); start_line=c+1; } } if(start_line) { string line; for(const char *n=start_line;n<c;n++) line.append(1,*n); lines.push_back(line); } |
위와 같이 되어 있는데.. 우선 데이터가 잘 넘어오는지 다 확인하고 나중에 lines 의 값을 찍어 보니 맹탕 알고 보니 위 소스를 보면 아하하고 아놔운서를 불렀더랬지
- 위 소스의 의도는 여러 줄을 찍는 것을 가능하게 해 주는 소스이다. 즉 넘거 받은 문자열 중에 개행문자를 만나면 줄을 바꾸고 저장.. 요런식으로 여러 줄을 찍을라고 한 작업이다.
1 2 3 4 5 6 7 8 | const char *start_line=text; vector<string> lines; string line; for (const char *c = text; *c; c++) { if (*c != '\n') line.append(1, *c); }lines.push_back(line); |
수정된 소스라오. 난 한줄만 찍어도 충분하다.
본인은 폰트를 찍어서 회전시켜야 하는 일이 생겼다. 대부분의 그래픽 응용에서 폰트에 회전을 줄 필요는 없는 듯 보였다. 그래서 몇일 작업했더랬지.. 그래서 결국에는 회전 성공.. 하 지금은 텍스쳐를 여러개 만들어서 하는 방법이다. 이 방법보다 좋은것은 텍스쳐 아틀라스로 하나의 텍스쳐에서 좌표를 가져와 버텍스 매핑하는 방법이 되겠지 우선 여기까지만 해도 괜찮을듯 하다. 여러번해보고 버그 생기면 다시 고쳐야겠지 아뵤 힘내세요.
[1]http://nehe.gamedev.net/tutorial/freetype_fonts_in_opengl/24001/
'OpenGL' 카테고리의 다른 글
OpenGL: 2D Scatter Plot(Demo Video) (1) | 2014.05.25 |
---|---|
OpenGL: Modern OpenGL Tutorial Text Rendering 02 (0) | 2014.05.20 |
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 |
■ 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 |
■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/
'OpenGL' 카테고리의 다른 글
OpenGL: Tutorial on using FreeType Fonts in OpenGL (1) | 2014.05.21 |
---|---|
OpenGL: Modern OpenGL Tutorial Text Rendering 02 (0) | 2014.05.20 |
Visual Studio: Setting FreeType Library (0) | 2014.05.16 |
OpenGL: Modern OpenGL Tutorial Text Rendering 01 (0) | 2014.05.15 |
OpenGL: Text in OpenGL (0) | 2014.05.15 |
■ 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 |