-
SDL2_ttf 사용하기프로그래밍/기타 2021. 3. 29. 21:03728x90
제가 SDL 라이브러리와 함께 많이 쓰는 라이브러리에는 SDL_image, SDL_ttf, SDL_net이 있습니다. 그중에 SDL2_ttf를 이용하여 FreeType 폰트를 출력하는 방법을 알아보겠습니다.
- SDL2_ttf 사이트: https://www.libsdl.org/projects/SDL_ttf/
먼저 실행 화면을 보시겠습니다. SDL 사용법은 이전 글을 참조하여 주십시오.
이전 글 참조: Visual C++에서 SDL2 라이브러리 사용하기
위 화면의 소스 코드입니다.
#include <stdio.h> #include "SDL.h" #include "SDL_ttf.h" #pragma comment(lib, "SDL2main.lib") #pragma comment(lib, "SDL2.lib") #pragma comment(lib, "SDL2_ttf.lib") SDL_Window* window; SDL_Renderer* renderer; int SDL_main(int argc, char* argv[]) { // Initialize SDL if (SDL_Init(SDL_INIT_VIDEO) < 0) { printf("Could not initialize SDL! (%s)\n", SDL_GetError()); return -1; } // Initialize Font if (TTF_Init() < 0) { printf("Could not initialize font! (%s)\n", TTF_GetError()); return -1; } // Create window window = SDL_CreateWindow("", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, SDL_WINDOW_OPENGL); if (window == NULL) { printf("Could not create window! (%s)\n", SDL_GetError()); return -1; } // Create renderer renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED|SDL_RENDERER_PRESENTVSYNC|SDL_RENDERER_TARGETTEXTURE); if (renderer == NULL) { printf("Could not create renderer! (%s)\n", SDL_GetError()); return -1; } // Clear renderer (white) SDL_SetRenderDrawColor(renderer, 255, 255, 255, SDL_ALPHA_OPAQUE); SDL_RenderClear(renderer); // Draw text TTF_Font* font = TTF_OpenFont("C:\\Windows\\Fonts\\gulim.ttc", 16); if (font == NULL) { printf("Could not open font! (%s)\n", TTF_GetError()); return -1; } SDL_Color color = {255, 0, 255, SDL_ALPHA_OPAQUE}; SDL_Surface* surface = TTF_RenderText_Blended(font, "Test String", color); SDL_Texture* texture = SDL_CreateTextureFromSurface(renderer, surface); SDL_FreeSurface(surface); SDL_Rect r = {0, 0, surface->w, surface->h}; SDL_RenderCopy(renderer, texture, NULL, &r); SDL_DestroyTexture(texture); TTF_CloseFont(font); // Update screen SDL_RenderPresent(renderer); SDL_Event event; int done = 0; while (!done) { SDL_PollEvent(&event); if (event.type == SDL_QUIT) { done = 1; } } SDL_DestroyRenderer(renderer); SDL_DestroyWindow(window); SDL_Quit(); return 0; }
TTF 폰트를 열기위해 4가지 함수가 존재합니다.
extern DECLSPEC TTF_Font * SDLCALL TTF_OpenFont(const char *file, int ptsize); extern DECLSPEC TTF_Font * SDLCALL TTF_OpenFontIndex(const char *file, int ptsize, long index); extern DECLSPEC TTF_Font * SDLCALL TTF_OpenFontRW(SDL_RWops *src, int freesrc, int ptsize); extern DECLSPEC TTF_Font * SDLCALL TTF_OpenFontIndexRW(SDL_RWops *src, int freesrc, int ptsize, long index);
TTF_OpenFont() 함수는 위 예제에서 사용하는 방법을 보여 드렸기에 넘어가고요.
TTF_OpenFontIndex() 함수는 TTF 폰트 한 파일에 여러 개의 폰트가 존재할 경우 index에 어떤 폰트를 사용할지를 지정하여 선택해줍니다.TTF_OpenFontRW() 함수는 파일을 열고 닫는 API가 따로 있거나 ROM과 같은 메모리에 있을 때(또 다른 예는 폰트가 Visual C++라면 리소스에 있을 때) 폰트 데이터를 직접 지정하여 사용하는 함수입니다. 예를 들어 fopen와 같은 함수가 아니라 다른 방식으로 파일을 사용할 때 입니다.
std::ifstream gulim("c:\\Windows\\Fonts\\gulim.ttc", std::ios::binary); gulim.seekg(0, std::ios_base::end); std::istream::pos_type file_size = gulim.tellg(); gulim.seekg(0); std::vector<char> buffer(file_size); std::copy(std::istreambuf_iterator<char>(gulim), std::istreambuf_iterator<char>(), buffer.begin()); SDL_RWops *ops_ctx = SDL_RWFromMem(&buffer[0], file_size); if (ops_ctx == NULL) { printf("SDL_RWFromMem() error! (%s)\n", SDL_GetError()); return -1; } TTF_Font* font = TTF_OpenFontRW(ops_ctx, 0, 16); if (font == NULL) { printf("Could not open font! (%s)\n", TTF_GetError()); return -1; } (... 중략 ...) TTF_CloseFont(font); SDL_RWclose(ops_ctx); gulim.close();
위 예제는 C++의 기능을 사용했지만 임베디드 시스템의 경우 C/C++ 표준 API가 아닌 시스템 고유의 API를 사용하지요. TTF_OpenFontRW() 함수는 그럴 때 사용할 수 있겠습니다.
하지만, 일부러 폰트 데이터를 모두 읽어 메모리에 넣고 TTF_OpenFontRW() 함수를 사용하지는 마십시오. 폰트 데이터를 모두 읽어 메모리에 복사하는 과정에 시간이 꽤 소요됩니다.
TTF_OpenFontIndexRW() 함수는 TTF_OpenFontIndex() 함수와 마찬가지로 폰트 인덱스를 지정할 수 있습니다.
다음은 폰트를 렌더링하는 함수에는 대표적으로 3가지 종류가 있습니다.
extern DECLSPEC SDL_Surface * SDLCALL TTF_RenderText_Solid(TTF_Font *font, const char *text, SDL_Color fg); extern DECLSPEC SDL_Surface * SDLCALL TTF_RenderText_Shaded(TTF_Font *font, const char *text, SDL_Color fg, SDL_Color bg); extern DECLSPEC SDL_Surface * SDLCALL TTF_RenderText_Blended(TTF_Font *font, const char *text, SDL_Color fg);
특징을 설명 드리기 앞서 각각의 함수를 사용한 화면을 보시겠습니다.
Solid 함수는 Font 데이터를 가공하지 않고 그대로 출력해줍니다. Shaded 함수는 그림자 효과가 있구요. 예제에서도 사용했던 Blend 함수는 Anti-aliasing이 적용되어 깔끔한 모습을 보여 줍니다.
또, 텍스트 데이터는 Ansi, UTF-8, 유니코드 형태로 넘겨줄 수 있습니다.
extern DECLSPEC SDL_Surface * SDLCALL TTF_RenderText_Blended(TTF_Font *font, const char *text, SDL_Color fg); extern DECLSPEC SDL_Surface * SDLCALL TTF_RenderUTF8_Blended(TTF_Font *font, const char *text, SDL_Color fg); extern DECLSPEC SDL_Surface * SDLCALL TTF_RenderUNICODE_Blended(TTF_Font *font, const Uint16 *text, SDL_Color fg);
이 외에도 문자열에 굵은 글씨, 이탤릭 스타일이나 밑줄을 그을 수 도 있고, 외각선을 넣을 수도 있습니다.
/* Set and retrieve the font style */ #define TTF_STYLE_NORMAL 0x00 #define TTF_STYLE_BOLD 0x01 #define TTF_STYLE_ITALIC 0x02 #define TTF_STYLE_UNDERLINE 0x04 #define TTF_STYLE_STRIKETHROUGH 0x08 extern DECLSPEC int SDLCALL TTF_GetFontStyle(const TTF_Font *font); extern DECLSPEC void SDLCALL TTF_SetFontStyle(TTF_Font *font, int style); extern DECLSPEC int SDLCALL TTF_GetFontOutline(const TTF_Font *font); extern DECLSPEC void SDLCALL TTF_SetFontOutline(TTF_Font *font, int outline);
함수들에 대한 자세한 정보는 공식 사이트의 문서(링크)를 참조하여 보세요.
728x90'프로그래밍 > 기타' 카테고리의 다른 글
VT터미널에서 컬러 사용하기 (0) 2021.03.28