/* NFont v4.0.0: A font class for SDL by Jonathan Dearborn Dedicated to the memory of Florian Hufsky License: The short: Use it however you'd like, but keep the copyright and license notice whenever these files or parts of them are distributed in uncompiled form. The long: Copyright (c) 2014 Jonathan Dearborn Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #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); } // 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() { }