/* NFont: A font class for SDL and SDL_Renderer by Jonathan Dearborn See NFont.h for license info. */ #include "NFont.h" #include "SDL_FontCache.h" #include #include #ifndef M_PI #define M_PI 3.14159265358979323846 #endif #include #include #include using std::string; using std::list; #ifdef NFONT_USE_SDL_GPU #define NFont_Target GPU_Target #define NFont_Image GPU_Image #define NFont_Log GPU_LogError #else #define NFont_Target SDL_Renderer #define NFont_Image SDL_Texture #define NFont_Log SDL_Log #endif #define MIN(a,b) ((a) < (b)? (a) : (b)) #define MAX(a,b) ((a) > (b)? (a) : (b)) #define NFONT_BUFFER_SIZE 1024 // vsnprintf replacement adapted from Valentin Milea: // http://stackoverflow.com/questions/2915672/snprintf-and-visual-studio-2010 #if defined(_MSC_VER) && _MSC_VER < 1900 #define vsnprintf c99_vsnprintf static int c99_vsnprintf(char *outBuf, size_t size, const char *format, va_list ap) { int count = -1; if (size != 0) count = _vsnprintf_s(outBuf, size, _TRUNCATE, format, ap); if (count == -1) count = _vscprintf(format, ap); return count; } #endif static inline SDL_Surface* createSurface24(Uint32 width, Uint32 height) { #if SDL_BYTEORDER == SDL_BIG_ENDIAN return SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, 24, 0xFF0000, 0x00FF00, 0x0000FF, 0); #else return SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, 24, 0x0000FF, 0x00FF00, 0xFF0000, 0); #endif } static inline SDL_Surface* createSurface32(Uint32 width, Uint32 height) { #if SDL_BYTEORDER == SDL_BIG_ENDIAN return SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, 32, 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF); #else return SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, 32, 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000); #endif } static inline char* copyString(const char* c) { if(c == NULL) return NULL; char* result = new char[strlen(c)+1]; strcpy(result, c); return result; } static inline Uint32 getPixel(SDL_Surface *Surface, int x, int y) { Uint8* bits; Uint32 bpp; if(x < 0 || x >= Surface->w) return 0; // Best I could do for errors bpp = Surface->format->BytesPerPixel; bits = ((Uint8*)Surface->pixels) + y*Surface->pitch + x*bpp; switch (bpp) { case 1: return *((Uint8*)Surface->pixels + y * Surface->pitch + x); break; case 2: return *((Uint16*)Surface->pixels + y * Surface->pitch/2 + x); break; case 3: // Endian-correct, but slower Uint8 r, g, b; r = *((bits)+Surface->format->Rshift/8); g = *((bits)+Surface->format->Gshift/8); b = *((bits)+Surface->format->Bshift/8); return SDL_MapRGB(Surface->format, r, g, b); break; case 4: return *((Uint32*)Surface->pixels + y * Surface->pitch/4 + x); break; } return 0; // FIXME: Handle errors better } static inline void setPixel(SDL_Surface* surface, int x, int y, Uint32 color) { int bpp = surface->format->BytesPerPixel; Uint8* bits = ((Uint8 *)surface->pixels) + y*surface->pitch + x*bpp; /* Set the pixel */ switch(bpp) { case 1: *((Uint8 *)(bits)) = (Uint8)color; break; case 2: *((Uint16 *)(bits)) = (Uint16)color; break; case 3: { /* Format/endian independent */ Uint8 r,g,b; r = (color >> surface->format->Rshift) & 0xFF; g = (color >> surface->format->Gshift) & 0xFF; b = (color >> surface->format->Bshift) & 0xFF; *((bits)+surface->format->Rshift/8) = r; *((bits)+surface->format->Gshift/8) = g; *((bits)+surface->format->Bshift/8) = b; } break; case 4: *((Uint32 *)(bits)) = (Uint32)color; break; } } static inline void drawPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color, Uint8 alpha) { if(x > surface->clip_rect.x + surface->clip_rect.w || x < surface->clip_rect.x || y > surface->clip_rect.y + surface->clip_rect.h || y < surface->clip_rect.y) return; switch (surface->format->BytesPerPixel) { case 1: { /* Assuming 8-bpp */ Uint8 *pixel = (Uint8 *)surface->pixels + y*surface->pitch + x; Uint8 dR = surface->format->palette->colors[*pixel].r; Uint8 dG = surface->format->palette->colors[*pixel].g; Uint8 dB = surface->format->palette->colors[*pixel].b; Uint8 sR = surface->format->palette->colors[color].r; Uint8 sG = surface->format->palette->colors[color].g; Uint8 sB = surface->format->palette->colors[color].b; dR = dR + ((sR-dR)*alpha >> 8); dG = dG + ((sG-dG)*alpha >> 8); dB = dB + ((sB-dB)*alpha >> 8); *pixel = SDL_MapRGB(surface->format, dR, dG, dB); } break; case 2: { /* Probably 15-bpp or 16-bpp */ Uint32 Rmask = surface->format->Rmask, Gmask = surface->format->Gmask, Bmask = surface->format->Bmask, Amask = surface->format->Amask; Uint16 *pixel = (Uint16 *)surface->pixels + y*surface->pitch/2 + x; Uint32 dc = *pixel; Uint32 R,G,B,A=0; R = ((dc & Rmask) + (( (color & Rmask) - (dc & Rmask) ) * alpha >> 8)) & Rmask; G = ((dc & Gmask) + (( (color & Gmask) - (dc & Gmask) ) * alpha >> 8)) & Gmask; B = ((dc & Bmask) + (( (color & Bmask) - (dc & Bmask) ) * alpha >> 8)) & Bmask; if( Amask ) A = ((dc & Amask) + (( (color & Amask) - (dc & Amask) ) * alpha >> 8)) & Amask; *pixel= R | G | B | A; } break; case 3: { /* Slow 24-bpp mode, usually not used */ Uint8 *pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3; Uint8 rshift8=surface->format->Rshift/8; Uint8 gshift8=surface->format->Gshift/8; Uint8 bshift8=surface->format->Bshift/8; Uint8 ashift8=surface->format->Ashift/8; Uint8 dR, dG, dB, dA; Uint8 sR, sG, sB, sA; pix = (Uint8 *)surface->pixels + y * surface->pitch + x*3; dR = *((pix)+rshift8); dG = *((pix)+gshift8); dB = *((pix)+bshift8); dA = *((pix)+ashift8); sR = (color>>surface->format->Rshift)&0xff; sG = (color>>surface->format->Gshift)&0xff; sB = (color>>surface->format->Bshift)&0xff; sA = (color>>surface->format->Ashift)&0xff; dR = dR + ((sR-dR)*alpha >> 8); dG = dG + ((sG-dG)*alpha >> 8); dB = dB + ((sB-dB)*alpha >> 8); dA = dA + ((sA-dA)*alpha >> 8); *((pix)+rshift8) = dR; *((pix)+gshift8) = dG; *((pix)+bshift8) = dB; *((pix)+ashift8) = dA; } break; case 4: { /* Probably 32-bpp */ Uint32 Rmask = surface->format->Rmask, Gmask = surface->format->Gmask, Bmask = surface->format->Bmask, Amask = surface->format->Amask; Uint32* pixel = (Uint32*)surface->pixels + y*surface->pitch/4 + x; Uint32 source = *pixel; Uint32 R,G,B,A; R = color & Rmask; G = color & Gmask; B = color & Bmask; A = 0; // keep this as 0 to avoid corruption of non-alpha surfaces // Blend and keep dest alpha if( alpha != SDL_ALPHA_OPAQUE ){ R = ((source & Rmask) + (( R - (source & Rmask) ) * alpha >> 8)) & Rmask; G = ((source & Gmask) + (( G - (source & Gmask) ) * alpha >> 8)) & Gmask; B = ((source & Bmask) + (( B - (source & Bmask) ) * alpha >> 8)) & Bmask; } if(Amask) A = (source & Amask); *pixel = R | G | B | A; } break; } } static inline NFont::Rectf rectUnion(const NFont::Rectf& A, const NFont::Rectf& B) { float x,x2,y,y2; x = MIN(A.x, B.x); y = MIN(A.y, B.y); x2 = MAX(A.x+A.w, B.x+B.w); y2 = MAX(A.y+A.h, B.y+B.h); NFont::Rectf result(x, y, MAX(0, x2 - x), MAX(0, y2 - y)); return result; } // Adapted from SDL_IntersectRect static inline NFont::Rectf rectIntersect(const NFont::Rectf& A, const NFont::Rectf& B) { NFont::Rectf result; float Amin, Amax, Bmin, Bmax; // Horizontal intersection Amin = A.x; Amax = Amin + A.w; Bmin = B.x; Bmax = Bmin + B.w; if(Bmin > Amin) Amin = Bmin; result.x = Amin; if(Bmax < Amax) Amax = Bmax; result.w = Amax - Amin > 0 ? Amax - Amin : 0; // Vertical intersection Amin = A.y; Amax = Amin + A.h; Bmin = B.y; Bmax = Bmin + B.h; if(Bmin > Amin) Amin = Bmin; result.y = Amin; if(Bmax < Amax) Amax = Bmax; result.h = Amax - Amin > 0 ? Amax - Amin : 0; return result; } static inline SDL_Surface* copySurface(SDL_Surface *Surface) { return SDL_ConvertSurface(Surface, Surface->format, Surface->flags); } NFont::Color::Color() : r(0), g(0), b(0), a(255) {} NFont::Color::Color(Uint8 r, Uint8 g, Uint8 b) : r(r), g(g), b(b), a(255) {} NFont::Color::Color(Uint8 r, Uint8 g, Uint8 b, Uint8 a) : r(r), g(g), b(b), a(a) {} NFont::Color::Color(const SDL_Color& color) : r(color.r), g(color.g), b(color.b), a(color.a) {} NFont::Color& NFont::Color::rgb(Uint8 R, Uint8 G, Uint8 B) { r = R; g = G; b = B; return *this; } NFont::Color& NFont::Color::rgba(Uint8 R, Uint8 G, Uint8 B, Uint8 A) { r = R; g = G; b = B; a = A; return *this; } NFont::Color& NFont::Color::color(const SDL_Color& color) { r = color.r; g = color.g; b = color.b; a = color.a; return *this; } SDL_Color NFont::Color::to_SDL_Color() const { SDL_Color c = {r, g, b, a}; return c; } NFont::Rectf::Rectf() : x(0), y(0), w(0), h(0) {} NFont::Rectf::Rectf(float x, float y) : x(x), y(y), w(0), h(0) {} NFont::Rectf::Rectf(float x, float y, float w, float h) : x(x), y(y), w(w), h(h) {} NFont::Rectf::Rectf(const SDL_Rect& rect) : x(rect.x), y(rect.y), w(rect.w), h(rect.h) {} #ifdef NFONT_USE_SDL_GPU NFont::Rectf::Rectf(const GPU_Rect& rect) : x(rect.x), y(rect.y), w(rect.w), h(rect.h) {} #endif SDL_Rect NFont::Rectf::to_SDL_Rect() const { SDL_Rect r = {int(x), int(y), int(w), int(h)}; return r; } #ifdef NFONT_USE_SDL_GPU GPU_Rect NFont::Rectf::to_GPU_Rect() const { return GPU_MakeRect(x, y, w, h); } #endif char* NFont::buffer = NULL; // Shared buffer for efficient drawing // Constructors NFont::NFont() { init(); } NFont::NFont(const NFont& font) { init(); // FIXME: Duplicate font data } #ifdef NFONT_USE_SDL_GPU NFont::NFont(TTF_Font* ttf) { init(); load(ttf, FC_GetDefaultColor(font)); } NFont::NFont(TTF_Font* ttf, const NFont::Color& color) { init(); load(ttf, color); } NFont::NFont(const char* filename_ttf, Uint32 pointSize) { init(); load(filename_ttf, pointSize); } NFont::NFont(const char* filename_ttf, Uint32 pointSize, const NFont::Color& color, int style) { init(); load(filename_ttf, pointSize, color, style); } NFont::NFont(SDL_RWops* file_rwops_ttf, Uint8 own_rwops, Uint32 pointSize, const NFont::Color& color, int style) { init(); load(file_rwops_ttf, own_rwops, pointSize, color, style); } #else NFont::NFont(NFont_Target* renderer, TTF_Font* ttf) { init(); load(renderer, ttf, FC_GetDefaultColor(font)); } NFont::NFont(NFont_Target* renderer, TTF_Font* ttf, const NFont::Color& color) { init(); load(renderer, ttf, color); } NFont::NFont(NFont_Target* renderer, const char* filename_ttf, Uint32 pointSize) { init(); load(renderer, filename_ttf, pointSize); } NFont::NFont(NFont_Target* renderer, const char* filename_ttf, Uint32 pointSize, const NFont::Color& color, int style) { init(); load(renderer, filename_ttf, pointSize, color, style); } NFont::NFont(NFont_Target* renderer, SDL_RWops* file_rwops_ttf, Uint8 own_rwops, Uint32 pointSize, const NFont::Color& color, int style) { init(); load(renderer, file_rwops_ttf, own_rwops, pointSize, color, style); } #endif NFont::~NFont() { FC_FreeFont(font); } NFont& NFont::operator=(const NFont& font) { // FIXME: Duplicate font data return *this; } void NFont::init() { font = FC_CreateFont(); if(buffer == NULL) buffer = new char[NFONT_BUFFER_SIZE]; } void NFont::setLoadingString(const char* str) { FC_SetLoadingString(font, str); } #ifdef NFONT_USE_SDL_GPU bool NFont::load(TTF_Font* ttf) #else bool NFont::load(NFont_Target* renderer, TTF_Font* ttf) #endif { #ifdef NFONT_USE_SDL_GPU return load(ttf, FC_GetDefaultColor(font)); #else return load(renderer, ttf, Color(0,0,0,255)); #endif } #ifdef NFONT_USE_SDL_GPU bool NFont::load(TTF_Font* ttf, const NFont::Color& color) #else bool NFont::load(NFont_Target* renderer, TTF_Font* ttf, const NFont::Color& color) #endif { if(ttf == NULL) return false; #ifndef NFONT_USE_SDL_GPU if(renderer == NULL) return false; #endif FC_ClearFont(font); #ifdef NFONT_USE_SDL_GPU return FC_LoadFontFromTTF(font, ttf, color.to_SDL_Color()); #else return FC_LoadFontFromTTF(font, renderer, ttf, color.to_SDL_Color()); #endif } #ifdef NFONT_USE_SDL_GPU bool NFont::load(const char* filename_ttf, Uint32 pointSize) #else bool NFont::load(NFont_Target* renderer, const char* filename_ttf, Uint32 pointSize) #endif { #ifdef NFONT_USE_SDL_GPU return load(filename_ttf, pointSize, Color(0,0,0,255)); #else return load(renderer, filename_ttf, pointSize, Color(0,0,0,255)); #endif } #ifdef NFONT_USE_SDL_GPU bool NFont::load(const char* filename_ttf, Uint32 pointSize, const NFont::Color& color, int style) #else bool NFont::load(NFont_Target* renderer, const char* filename_ttf, Uint32 pointSize, const NFont::Color& color, int style) #endif { FC_ClearFont(font); #ifdef NFONT_USE_SDL_GPU return FC_LoadFont(font, filename_ttf, pointSize, color.to_SDL_Color(), style); #else return FC_LoadFont(font, renderer, filename_ttf, pointSize, color.to_SDL_Color(), style); #endif } #ifdef NFONT_USE_SDL_GPU bool NFont::load(SDL_RWops* file_rwops_ttf, Uint8 own_rwops, Uint32 pointSize, const NFont::Color& color, int style) #else bool NFont::load(NFont_Target* renderer, SDL_RWops* file_rwops_ttf, Uint8 own_rwops, Uint32 pointSize, const NFont::Color& color, int style) #endif { FC_ClearFont(font); #ifdef NFONT_USE_SDL_GPU return FC_LoadFont_RW(font, file_rwops_ttf, own_rwops, pointSize, color.to_SDL_Color(), style); #else return FC_LoadFont_RW(font, renderer, file_rwops_ttf, own_rwops, pointSize, color.to_SDL_Color(), style); #endif } void NFont::free() { FC_ClearFont(font); } NFont::Rectf NFont::draw(NFont_Target* dest, float x, float y, const char* formatted_text, ...) { if(formatted_text == NULL) return Rectf(x, y, 0, 0); va_list lst; va_start(lst, formatted_text); vsnprintf(buffer, NFONT_BUFFER_SIZE, formatted_text, lst); va_end(lst); return FC_Draw(font, dest, x, y, "%s", buffer); } /*static int getIndexPastWidth(const char* text, int width, const int* charWidth) { int charnum; int len = strlen(text); for (int index = 0; index < len; index++) { char c = text[index]; charnum = (unsigned char)(c) - 33; // spaces and nonprintable characters if (c == ' ' || charnum > 222) { width -= charWidth[0]; } else width -= charWidth[charnum]; if(width <= 0) return index; } return 0; }*/ /*static list explode(const string& str, char delimiter) { list result; size_t oldPos = 0; size_t pos = str.find_first_of(delimiter); while(pos != string::npos) { result.push_back(str.substr(oldPos, pos - oldPos)); oldPos = pos+1; pos = str.find_first_of(delimiter, oldPos); } result.push_back(str.substr(oldPos, string::npos)); return result; }*/ NFont::Rectf NFont::drawBox(NFont_Target* dest, const Rectf& box, const char* formatted_text, ...) { if(formatted_text == NULL) return Rectf(box.x, box.y, 0, 0); va_list lst; va_start(lst, formatted_text); vsnprintf(buffer, NFONT_BUFFER_SIZE, formatted_text, lst); va_end(lst); #ifdef NFONT_USE_SDL_GPU return FC_DrawBox(font, dest, box.to_GPU_Rect(), "%s", buffer); #else return FC_DrawBox(font, dest, box.to_SDL_Rect(), "%s", buffer); #endif } static FC_AlignEnum translate_enum_NFont_to_FC(NFont::AlignEnum align) { switch(align) { case NFont::LEFT: return FC_ALIGN_LEFT; case NFont::CENTER: return FC_ALIGN_CENTER; case NFont::RIGHT: return FC_ALIGN_RIGHT; default: return FC_ALIGN_LEFT; } } NFont::Rectf NFont::drawBox(NFont_Target* dest, const Rectf& box, AlignEnum align, const char* formatted_text, ...) { if(formatted_text == NULL) return Rectf(box.x, box.y, 0, 0); va_list lst; va_start(lst, formatted_text); vsnprintf(buffer, NFONT_BUFFER_SIZE, formatted_text, lst); va_end(lst); #ifdef NFONT_USE_SDL_GPU return FC_DrawBoxAlign(font, dest, box.to_GPU_Rect(), translate_enum_NFont_to_FC(align), "%s", buffer); #else return FC_DrawBoxAlign(font, dest, box.to_SDL_Rect(), translate_enum_NFont_to_FC(align), "%s", buffer); #endif } NFont::Rectf NFont::drawBox(NFont_Target* dest, const Rectf& box, const Scale& scale, const char* formatted_text, ...) { if(formatted_text == NULL) return Rectf(box.x, box.y, 0, 0); va_list lst; va_start(lst, formatted_text); vsnprintf(buffer, NFONT_BUFFER_SIZE, formatted_text, lst); va_end(lst); #ifdef NFONT_USE_SDL_GPU return FC_DrawBoxScale(font, dest, box.to_GPU_Rect(), FC_MakeScale(scale.x, scale.y), "%s", buffer); #else return FC_DrawBoxScale(font, dest, box.to_SDL_Rect(), FC_MakeScale(scale.x, scale.y), "%s", buffer); #endif } NFont::Rectf NFont::drawBox(NFont_Target* dest, const Rectf& box, const Color& color, const char* formatted_text, ...) { if(formatted_text == NULL) return Rectf(box.x, box.y, 0, 0); va_list lst; va_start(lst, formatted_text); vsnprintf(buffer, NFONT_BUFFER_SIZE, formatted_text, lst); va_end(lst); #ifdef NFONT_USE_SDL_GPU return FC_DrawBoxColor(font, dest, box.to_GPU_Rect(), color.to_SDL_Color(), "%s", buffer); #else return FC_DrawBoxColor(font, dest, box.to_SDL_Rect(), color.to_SDL_Color(), "%s", buffer); #endif } NFont::Rectf NFont::drawBox(NFont_Target* dest, const Rectf& box, const Effect& effect, const char* formatted_text, ...) { if(formatted_text == NULL) return Rectf(box.x, box.y, 0, 0); va_list lst; va_start(lst, formatted_text); vsnprintf(buffer, NFONT_BUFFER_SIZE, formatted_text, lst); va_end(lst); #ifdef NFONT_USE_SDL_GPU return FC_DrawBoxEffect(font, dest, box.to_GPU_Rect(), FC_MakeEffect(translate_enum_NFont_to_FC(effect.alignment), FC_MakeScale(effect.scale.x, effect.scale.y), effect.color.to_SDL_Color()), "%s", buffer); #else return FC_DrawBoxEffect(font, dest, box.to_SDL_Rect(), FC_MakeEffect(translate_enum_NFont_to_FC(effect.alignment), FC_MakeScale(effect.scale.x, effect.scale.y), effect.color.to_SDL_Color()), "%s", buffer); #endif } NFont::Rectf NFont::drawColumn(NFont_Target* dest, float x, float y, Uint16 width, const char* formatted_text, ...) { if(formatted_text == NULL) return Rectf(x, y, 0, 0); va_list lst; va_start(lst, formatted_text); vsnprintf(buffer, NFONT_BUFFER_SIZE, formatted_text, lst); va_end(lst); return FC_DrawColumn(font, dest, x, y, width, "%s", buffer); } NFont::Rectf NFont::drawColumn(NFont_Target* dest, float x, float y, Uint16 width, AlignEnum align, const char* formatted_text, ...) { if(formatted_text == NULL) return Rectf(x, y, 0, 0); va_list lst; va_start(lst, formatted_text); vsnprintf(buffer, NFONT_BUFFER_SIZE, formatted_text, lst); va_end(lst); return FC_DrawColumnAlign(font, dest, x, y, width, translate_enum_NFont_to_FC(align), "%s", buffer); } NFont::Rectf NFont::drawColumn(NFont_Target* dest, float x, float y, Uint16 width, const Scale& scale, const char* formatted_text, ...) { if(formatted_text == NULL) return Rectf(x, y, 0, 0); va_list lst; va_start(lst, formatted_text); vsnprintf(buffer, NFONT_BUFFER_SIZE, formatted_text, lst); va_end(lst); return FC_DrawColumnScale(font, dest, x, y, width, FC_MakeScale(scale.x, scale.y), "%s", buffer); } NFont::Rectf NFont::drawColumn(NFont_Target* dest, float x, float y, Uint16 width, const Color& color, const char* formatted_text, ...) { if(formatted_text == NULL) return Rectf(x, y, 0, 0); va_list lst; va_start(lst, formatted_text); vsnprintf(buffer, NFONT_BUFFER_SIZE, formatted_text, lst); va_end(lst); return FC_DrawColumnColor(font, dest, x, y, width, color.to_SDL_Color(), "%s", buffer); } NFont::Rectf NFont::drawColumn(NFont_Target* dest, float x, float y, Uint16 width, const Effect& effect, const char* formatted_text, ...) { if(formatted_text == NULL) return Rectf(x, y, 0, 0); va_list lst; va_start(lst, formatted_text); vsnprintf(buffer, NFONT_BUFFER_SIZE, formatted_text, lst); va_end(lst); #ifdef NFONT_USE_SDL_GPU return FC_DrawColumnEffect(font, dest, x, y, width, FC_MakeEffect(translate_enum_NFont_to_FC(effect.alignment), FC_MakeScale(effect.scale.x, effect.scale.y), effect.color.to_SDL_Color()), "%s", buffer); #else return FC_DrawColumnEffect(font, dest, x, y, width, FC_MakeEffect(translate_enum_NFont_to_FC(effect.alignment), FC_MakeScale(effect.scale.x, effect.scale.y), effect.color.to_SDL_Color()), "%s", buffer); #endif } NFont::Rectf NFont::draw(NFont_Target* dest, float x, float y, const Scale& scale, const char* formatted_text, ...) { if(formatted_text == NULL) return Rectf(x, y, 0, 0); va_list lst; va_start(lst, formatted_text); vsnprintf(buffer, NFONT_BUFFER_SIZE, formatted_text, lst); va_end(lst); return FC_DrawScale(font, dest, x, y, FC_MakeScale(scale.x, scale.y), "%s", buffer); } NFont::Rectf NFont::draw(NFont_Target* dest, float x, float y, AlignEnum align, const char* formatted_text, ...) { if(formatted_text == NULL) return Rectf(x, y, 0, 0); va_list lst; va_start(lst, formatted_text); vsnprintf(buffer, NFONT_BUFFER_SIZE, formatted_text, lst); va_end(lst); return FC_DrawAlign(font, dest, x, y, translate_enum_NFont_to_FC(align), "%s", buffer); } NFont::Rectf NFont::draw(NFont_Target* dest, float x, float y, const Color& color, const char* formatted_text, ...) { if(formatted_text == NULL) return Rectf(x, y, 0, 0); va_list lst; va_start(lst, formatted_text); vsnprintf(buffer, NFONT_BUFFER_SIZE, formatted_text, lst); va_end(lst); return FC_DrawColor(font, dest, x, y, color.to_SDL_Color(), "%s", buffer); } NFont::Rectf NFont::draw(NFont_Target* dest, float x, float y, const Effect& effect, const char* formatted_text, ...) { if(formatted_text == NULL) return Rectf(x, y, 0, 0); va_list lst; va_start(lst, formatted_text); vsnprintf(buffer, NFONT_BUFFER_SIZE, formatted_text, lst); va_end(lst); return FC_DrawEffect(font, dest, x, y, FC_MakeEffect(translate_enum_NFont_to_FC(effect.alignment), FC_MakeScale(effect.scale.x, effect.scale.y), effect.color.to_SDL_Color()), "%s", buffer); } // Getters NFont::FilterEnum NFont::getFilterMode() const { FC_FilterEnum f = FC_GetFilterMode(font); if(f == FC_FILTER_LINEAR) return NFont::LINEAR; return NFont::NEAREST; } Uint16 NFont::getHeight() const { return FC_GetLineHeight(font); } Uint16 NFont::getHeight(const char* formatted_text, ...) const { if(formatted_text == NULL) return 0; va_list lst; va_start(lst, formatted_text); vsnprintf(buffer, NFONT_BUFFER_SIZE, formatted_text, lst); va_end(lst); return FC_GetHeight(font, "%s", buffer); } Uint16 NFont::getWidth(const char* formatted_text, ...) { if (formatted_text == NULL) return 0; va_list lst; va_start(lst, formatted_text); vsnprintf(buffer, NFONT_BUFFER_SIZE, formatted_text, lst); va_end(lst); return FC_GetWidth(font, "%s", buffer); } NFont::Rectf NFont::getCharacterOffset(Uint16 position_index, int column_width, const char* formatted_text, ...) { if(formatted_text == NULL) return Rectf(0,0,0,0); va_list lst; va_start(lst, formatted_text); vsnprintf(buffer, NFONT_BUFFER_SIZE, formatted_text, lst); va_end(lst); return FC_GetCharacterOffset(font, position_index, column_width, "%s", buffer); } // Given an offset (x,y) from the text draw position (the upper-left corner), returns the character position (UTF-8 index) Uint16 NFont::getPositionFromOffset(float x, float y, int column_width, NFont::AlignEnum align, const char* formatted_text, ...) { if(formatted_text == NULL) return 0; va_list lst; va_start(lst, formatted_text); vsnprintf(buffer, NFONT_BUFFER_SIZE, formatted_text, lst); va_end(lst); return FC_GetPositionFromOffset(font, x, y, column_width, translate_enum_NFont_to_FC(align), "%s", buffer); } Uint16 NFont::getColumnHeight(Uint16 width, const char* formatted_text, ...) { if(formatted_text == NULL || width == 0) return 0; va_list lst; va_start(lst, formatted_text); vsnprintf(buffer, NFONT_BUFFER_SIZE, formatted_text, lst); va_end(lst); return FC_GetColumnHeight(font, width, "%s", buffer); } int NFont::getAscent(const char character) { return FC_GetAscent(font, "%c", character); } int NFont::getAscent() const { return FC_GetAscent(font, NULL); } int NFont::getAscent(const char* formatted_text, ...) { if(formatted_text == NULL) return FC_GetAscent(font, NULL); va_list lst; va_start(lst, formatted_text); vsnprintf(buffer, NFONT_BUFFER_SIZE, formatted_text, lst); va_end(lst); return FC_GetAscent(font, "%s", buffer); } int NFont::getDescent(const char character) { return FC_GetDescent(font, "%c", character); } int NFont::getDescent() const { return FC_GetDescent(font, NULL); } int NFont::getDescent(const char* formatted_text, ...) { if(formatted_text == NULL) return FC_GetDescent(font, NULL); va_list lst; va_start(lst, formatted_text); vsnprintf(buffer, NFONT_BUFFER_SIZE, formatted_text, lst); va_end(lst); return FC_GetDescent(font, "%s", buffer); } int NFont::getSpacing() const { return FC_GetSpacing(font); } int NFont::getLineSpacing() const { return FC_GetLineSpacing(font); } Uint16 NFont::getBaseline() const { return FC_GetBaseline(font); } Uint16 NFont::getMaxWidth() const { return FC_GetMaxWidth(font); } NFont::Color NFont::getDefaultColor() const { return FC_GetDefaultColor(font); } int NFont::getNumCacheLevels() const { return FC_GetNumCacheLevels(font); } NFont_Image* NFont::getCacheLevel(int level) const { return FC_GetGlyphCacheLevel(font, level); } // Setters void NFont::setFilterMode(NFont::FilterEnum filter) { if(filter == NFont::LINEAR) FC_SetFilterMode(font, FC_FILTER_LINEAR); else FC_SetFilterMode(font, FC_FILTER_NEAREST); } void NFont::setSpacing(int LetterSpacing) { FC_SetSpacing(font, LetterSpacing); } void NFont::setLineSpacing(int LineSpacing) { FC_SetLineSpacing(font, LineSpacing); } void NFont::setBaseline() { } void NFont::setBaseline(Uint16 Baseline) { } void NFont::setDefaultColor(const Color& color) { FC_SetDefaultColor(font, color.to_SDL_Color()); } void NFont::enableTTFOwnership() { }