diff --git a/source/code/Libs/NFont.cpp b/source/code/Libs/NFont.cpp index efbf3fe..b5023fe 100644 --- a/source/code/Libs/NFont.cpp +++ b/source/code/Libs/NFont.cpp @@ -1,1069 +1,1029 @@ -/* -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)) - -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[1024]; -} - - - - - - -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); - vsprintf(buffer, 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); - vsprintf(buffer, 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); - vsprintf(buffer, 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); - vsprintf(buffer, 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); - vsprintf(buffer, 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); - vsprintf(buffer, 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); - vsprintf(buffer, 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); - vsprintf(buffer, 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); - vsprintf(buffer, 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); - vsprintf(buffer, 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); - vsprintf(buffer, 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); - vsprintf(buffer, 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); - vsprintf(buffer, 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); - vsprintf(buffer, 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); - vsprintf(buffer, 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); - vsprintf(buffer, 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); - vsprintf(buffer, 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); - vsprintf(buffer, formatted_text, lst); - va_end(lst); - - return FC_GetCharacterOffset(font, position_index, column_width, "%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); - vsprintf(buffer, 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); - vsprintf(buffer, 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); - vsprintf(buffer, 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() -{ - -} - - - - +/* +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)) + +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[1024]; + } +} + + + + + + +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); + vsprintf(buffer, 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); + vsprintf(buffer, 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); + vsprintf(buffer, 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); + vsprintf(buffer, 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); + vsprintf(buffer, 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); + vsprintf(buffer, 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); + vsprintf(buffer, 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); + vsprintf(buffer, 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); + vsprintf(buffer, 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); + vsprintf(buffer, 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); + vsprintf(buffer, 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); + vsprintf(buffer, 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); + vsprintf(buffer, 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); + vsprintf(buffer, 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); + vsprintf(buffer, 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); + vsprintf(buffer, 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); + vsprintf(buffer, 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); + vsprintf(buffer, formatted_text, lst); + va_end(lst); + + return FC_GetCharacterOffset(font, position_index, column_width, "%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); + vsprintf(buffer, 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); + vsprintf(buffer, 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); + vsprintf(buffer, 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() { + +} + + + + diff --git a/source/code/joypad.cpp b/source/code/joypad.cpp index d50d661..0219f6d 100644 --- a/source/code/joypad.cpp +++ b/source/code/joypad.cpp @@ -99,7 +99,7 @@ Joypad::Joypad() { but2REL=true; int joynum = 0; /*while ((SDL_JoystickOpened(joynum))&&(joynum=Joypad_number) { working = false; diff --git a/source/code/main.cpp b/source/code/main.cpp index 4bc4a6e..311713b 100644 --- a/source/code/main.cpp +++ b/source/code/main.cpp @@ -199,7 +199,7 @@ static int InitImages(sago::SagoSpriteHolder& holder) { menuMarked = holder.GetSprite("menu_marked"); menuUnmarked = holder.GetSprite("menu_unmarked"); backBoard = holder.GetSprite("back_board"); - + SDL_Color nf_button_color, nf_standard_blue_color, nf_standard_small_color; memset(&nf_button_color,0,sizeof(SDL_Color)); nf_button_color.b = 255; @@ -251,11 +251,11 @@ static string itoa2(int num) { } /*Draws a image from on a given Surface. Takes source image, destination surface and coordinates*/ -void DrawIMG(sago::SagoSprite &sprite, SDL_Renderer* target, int x, int y) { +void DrawIMG(sago::SagoSprite& sprite, SDL_Renderer* target, int x, int y) { sprite.Draw(target, SDL_GetTicks() ,x,y); } -void DrawIMG_Bounded(sago::SagoSprite &sprite, SDL_Renderer* target, int x, int y, int minx, int miny, int maxx, int maxy) { +void DrawIMG_Bounded(sago::SagoSprite& sprite, SDL_Renderer* target, int x, int y, int minx, int miny, int maxx, int maxy) { SDL_Rect bounds; bounds.x = minx; bounds.y = miny; @@ -569,15 +569,15 @@ public: topx = tx; topy = ty; } - + void DrawImgBoard(sago::SagoSprite& img, int x, int y) const { DrawIMG(img, screen, x+topx, y+topy); } - + void DrawImgBoardBounded(sago::SagoSprite& img, int x, int y) const { DrawIMG_Bounded(img, screen, x+topx, y+topy, topx, topy, topx + backBoard.GetWidth(), topy + backBoard.GetHeight()); } - + void PrintTextCenteredBoard(int x, int y, const char* text) { nf_button_font.draw(screen, x+topx+60, y+topy+10, NFont::CENTER, "%s", text); } @@ -783,7 +783,7 @@ public: //Draws everything void DoPaintJob() { DrawIMG(boardBackBack,screen,this->GetTopX()-60,this->GetTopY()-68); - + nf_scoreboard_font.draw(screen, this->GetTopX()+310,this->GetTopY()-68+148,_("Score:") ); nf_scoreboard_font.draw(screen, this->GetTopX()+310,this->GetTopY()-68+197,_("Time:") ); nf_scoreboard_font.draw(screen, this->GetTopX()+310,this->GetTopY()-68+246,_("Chain:") ); @@ -955,6 +955,7 @@ static string getKeyName(SDL_Keycode key) { bool OpenDialogbox(int x, int y, std::string& name) { bool done = false; //We are done! bool accept = false; //New name is accepted! (not Cancelled) + SDL_TextInput textInputScope; ReadKeyboard rk = ReadKeyboard(name.c_str()); string strHolder; DrawIMG(backgroundImage,screen,0,0); @@ -977,6 +978,12 @@ bool OpenDialogbox(int x, int y, std::string& name) { accept = false; } + if (event.type == SDL_TEXTINPUT) { + if ((rk.ReadKey(event))&&(SoundEnabled)&&(!NoSound)) { + Mix_PlayChannel(1,typingChunk,0); + } + } + if ( event.type == SDL_KEYDOWN ) { if ( (event.key.keysym.sym == SDLK_RETURN)||(event.key.keysym.sym == SDLK_KP_ENTER) ) { done = true; @@ -986,12 +993,7 @@ bool OpenDialogbox(int x, int y, std::string& name) { done = true; accept = false; } - else if (!(event.key.keysym.sym == SDLK_BACKSPACE)) { - if ((rk.ReadKey(event))&&(SoundEnabled)&&(!NoSound)) { - Mix_PlayChannel(1,typingChunk,0); - } - } - else if (event.key.keysym.sym == SDLK_BACKSPACE) { + else { if ((rk.ReadKey(event))&&(SoundEnabled)&&(!NoSound)) { Mix_PlayChannel(1,typingChunk,0); } @@ -1318,7 +1320,7 @@ static void DrawBalls() { int x = theTextManeger.textArray[i].getX()-12; int y = theTextManeger.textArray[i].getY()-12; DrawIMG(iChainFrame,screen,x,y); - + nf_standard_small_font.draw(screen, x+12,y+7, NFont::CENTER, "%s",theTextManeger.textArray[i].getText()); } } //for @@ -2137,14 +2139,14 @@ int main(int argc, char* argv[]) { if ((bFullscreen)&&(!singlePuzzle)) { createWindowParams |= SDL_WINDOW_FULLSCREEN_DESKTOP; } - - SDL_Window *sdlWindow = SDL_CreateWindow("Block Attack - Rise of the BlocksMy Game Window", - SDL_WINDOWPOS_UNDEFINED, - SDL_WINDOWPOS_UNDEFINED, - xsize, ysize, - createWindowParams ); + + SDL_Window* sdlWindow = SDL_CreateWindow("Block Attack - Rise of the BlocksMy Game Window", + SDL_WINDOWPOS_UNDEFINED, + SDL_WINDOWPOS_UNDEFINED, + xsize, ysize, + createWindowParams ); dieOnNullptr(sdlWindow, "Unable to create window"); - SDL_Renderer *renderer = SDL_CreateRenderer(sdlWindow, -1, 0); + SDL_Renderer* renderer = SDL_CreateRenderer(sdlWindow, -1, 0); dieOnNullptr(renderer, "Unable to create render"); screen = renderer; //Init the file system abstraction layer @@ -2154,7 +2156,7 @@ int main(int argc, char* argv[]) { sago::SagoDataHolder d(renderer); sago::SagoSpriteHolder spriteholder(d); loadTheme(spriteholder, Config::getInstance()->getString("themename")); - + //Now sets the icon: //SDL_Surface* icon = IMG_Load2("gfx/icon.png"); //SDL_WM_SetIcon(icon,nullptr); @@ -2288,7 +2290,7 @@ int runGame(int gametype, int level) { bool mustsetupgame = true; - + while (done == 0) { if (mustsetupgame) { @@ -2745,7 +2747,7 @@ int runGame(int gametype, int level) { //twoPlayers = false; } } - + if (theGame.isGameOver() && registerTTHighscorePlayer1) { registerTTHighscorePlayer1 = false; theTopScoresTimeTrial.addScore(theGame.name, theGame.GetScore()); diff --git a/source/code/sago/SagoSprite.cpp b/source/code/sago/SagoSprite.cpp index 45b05dd..d1da53e 100644 --- a/source/code/sago/SagoSprite.cpp +++ b/source/code/sago/SagoSprite.cpp @@ -48,12 +48,12 @@ SagoSprite::SagoSprite(const SagoDataHolder& texHolder, const std::string& textu } SagoSprite::SagoSprite(const SagoSprite& base) : data(new SagoSpriteData(*base.data)) { - + } SagoSprite& SagoSprite::operator=(const SagoSprite& base) { *data = *base.data; - return *this; + return *this; } SagoSprite::~SagoSprite() { @@ -62,7 +62,7 @@ SagoSprite::~SagoSprite() { void SagoSprite::Draw(SDL_Renderer* target, Sint32 frameTime, int x, int y) const { if (!data->tex) { - std::cerr << "Texture is null!" << std::endl; + std::cerr << "Texture is null!" << std::endl; } SDL_Rect rect = data->imgCord; rect.x+=rect.w*((frameTime/data->aniFrameTime)%data->aniFrames); diff --git a/source/code/scopeHelpers.hpp b/source/code/scopeHelpers.hpp index 2861469..999f9f5 100644 --- a/source/code/scopeHelpers.hpp +++ b/source/code/scopeHelpers.hpp @@ -40,5 +40,16 @@ public: } }; +class SDL_TextInput { +public: + SDL_TextInput() { + SDL_StartTextInput(); + } + + ~SDL_TextInput() { + SDL_StopTextInput(); + } +}; + #endif /* SCOPEHELPERS_HPP */