commit 078900fe
Started to shift to SDL2 but it requires some major changes that should be done in the base first
Changed files
diff --git a/source/code/CppSdlImageHolder.cpp b/source/code/CppSdlImageHolder.cpp
index ad1c3be..2144281 100644
--- a/source/code/CppSdlImageHolder.cpp
+++ b/source/code/CppSdlImageHolder.cpp
@@ -92,18 +92,6 @@ void CppSdlImageHolder::PaintTo(SDL_Surface* target, int x, int y) {
SDL_BlitSurface(data,&area, target,&dest);
}
-void CppSdlImageHolder::OptimizeForBlit(bool allowAlpha) {
- static SDL_Surface* tmp;
- Initialized();
- if (allowAlpha) {
- tmp = SDL_DisplayFormatAlpha(data);
- }
- else {
- tmp = SDL_DisplayFormat(data);
- }
- SDL_FreeSurface(data);
- data = tmp;
-}
void CppSdlImageHolder::Initialized() {
if (data == nullptr) {
diff --git a/source/code/CppSdlImageHolder.hpp b/source/code/CppSdlImageHolder.hpp
index d6c5384..ae55449 100644
--- a/source/code/CppSdlImageHolder.hpp
+++ b/source/code/CppSdlImageHolder.hpp
@@ -77,7 +77,6 @@ public:
* @param y vertical placement on destination surface
*/
void PaintTo(SDL_Surface *target, int x, int y);
- void OptimizeForBlit(bool allowAlpha = true);
/**
* Tests if there are data in the object
* @return true if where are data in the object
diff --git a/source/code/Libs/NFont.cpp b/source/code/Libs/NFont.cpp
index 2ea2ac4..efbf3fe 100644
--- a/source/code/Libs/NFont.cpp
+++ b/source/code/Libs/NFont.cpp
@@ -1,1050 +1,1069 @@
-/*
-NFont v2.0.0: A bitmap font class for SDL
-by Jonathan Dearborn 2-4-10
-(class adapted from 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) 2010 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"
-
-char* NFont::buffer = NULL;
-NFont::AnimData NFont::data;
-
-#define MIN(a,b) (a < b? a : b)
-#define MAX(a,b) (a > b? a : b)
-
-// Static setters
-void NFont::setAnimData(void* data) {
- NFont::data.userVar = data;
-}
-
-void NFont::setBuffer(unsigned int size) {
- delete[] buffer;
- if (size > 0) {
- buffer = new char[size];
- }
- else {
- buffer = new char[1024];
- }
-}
-
-
-// Static functions
-char* NFont::copyString(const char* c) {
- if (c == NULL) {
- return NULL;
- }
-
- int count = 0;
- for (; c[count] != '\0'; count++);
-
- char* result = new char[count+1];
-
- for (int i = 0; i < count; i++) {
- result[i] = c[i];
- }
-
- result[count] = '\0';
- return result;
-}
-
-Uint32 NFont::getPixel(SDL_Surface* Surface, int x, int y) { // No Alpha?
- 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; // Best I could do for errors
-}
-
-SDL_Rect NFont::rectUnion(const SDL_Rect& A, const SDL_Rect& B) {
- Sint16 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);
- SDL_Rect result = {static_cast<Sint16>(x), static_cast<Sint16>(y), static_cast<Uint16>(x2 - x), static_cast<Uint16>(y2 - y)};
- return result;
-}
-
-SDL_Surface* NFont::copySurface(SDL_Surface* Surface) {
- return SDL_ConvertSurface(Surface, Surface->format, Surface->flags);
-}
-
-SDL_Surface* NFont::verticalGradient(SDL_Surface* targetSurface, Uint32 top, Uint32 bottom, int heightAdjust) {
- SDL_Surface* surface = targetSurface;
- if (surface == NULL) {
- return NULL;
- }
-
- Uint8 tr, tg, tb;
-
- SDL_GetRGB(top, surface->format, &tr, &tg, &tb);
-
- Uint8 br, bg, bb;
-
- SDL_GetRGB(bottom, surface->format, &br, &bg, &bb);
-
- bool useCK = (surface->flags & SDL_SRCALPHA) != SDL_SRCALPHA; // colorkey if no alpha
- Uint32 colorkey = surface->format->colorkey;
-
- Uint8 r, g, b, a;
- float ratio;
- Uint32 color;
- int temp;
-
- for (int x = 0, y = 0; y < surface->h; x++) {
- if (x >= surface->w) {
- x = 0;
- y++;
-
- if (y >= surface->h) {
- break;
- }
- }
-
- ratio = (y - 2)/float(surface->h - heightAdjust); // the neg 3s are for full color at top and bottom
-
- if (!useCK) {
- color = getPixel(surface, x, y);
- SDL_GetRGBA(color, surface->format, &r, &g, &b, &a); // just getting alpha
- }
- else {
- a = SDL_ALPHA_OPAQUE;
- }
-
- // Get and clamp the new values
- temp = int(tr*(1-ratio) + br*ratio);
- r = temp < 0? 0 : temp > 255? 255 : temp;
-
- temp = int(tg*(1-ratio) + bg*ratio);
- g = temp < 0? 0 : temp > 255? 255 : temp;
-
- temp = int(tb*(1-ratio) + bb*ratio);
- b = temp < 0? 0 : temp > 255? 255 : temp;
-
-
- color = SDL_MapRGBA(surface->format, r, g, b, a);
-
-
- if (useCK) {
- if (getPixel(surface, x, y) == colorkey) {
- continue;
- }
- if (color == colorkey) {
- color == 0? color++ : color--;
- }
- }
-
- // make sure it isn't pink
- if (color == SDL_MapRGBA(surface->format, 0xFF, 0, 0xFF, a)) {
- color--;
- }
- if (getPixel(surface, x, y) == SDL_MapRGBA(surface->format, 0xFF, 0, 0xFF, SDL_ALPHA_OPAQUE)) {
- continue;
- }
-
- 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 */
- 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;
- }
-
- }
- return surface;
-}
-
-
-// Constructors
-NFont::NFont() {
- init();
-}
-
-NFont::NFont(SDL_Surface* src) {
- init();
- load(src);
-}
-
-NFont::NFont(SDL_Surface* dest, SDL_Surface* src) {
- init();
- load(src);
- setDest(dest);
-}
-
-#ifdef NFONT_USE_TTF
-NFont::NFont(TTF_Font* ttf, SDL_Color fg) {
- init();
- load(ttf, fg);
-}
-NFont::NFont(TTF_Font* ttf, SDL_Color fg, SDL_Color bg) {
- init();
- load(ttf, fg, bg);
-}
-NFont::NFont(const char* filename_ttf, Uint32 pointSize, SDL_Color fg, int style) {
- init();
- load(filename_ttf, pointSize, fg, style);
-}
-NFont::NFont(const char* filename_ttf, Uint32 pointSize, SDL_Color fg, SDL_Color bg, int style) {
- init();
- load(filename_ttf, pointSize, fg, bg, style);
-}
-
-NFont::NFont(SDL_Surface* dest, TTF_Font* ttf, SDL_Color fg) {
- init();
- load(ttf, fg);
- setDest(dest);
-}
-NFont::NFont(SDL_Surface* dest, TTF_Font* ttf, SDL_Color fg, SDL_Color bg) {
- init();
- load(ttf, fg, bg);
- setDest(dest);
-}
-NFont::NFont(SDL_Surface* dest, const char* filename_ttf, Uint32 pointSize, SDL_Color fg, int style) {
- init();
- load(filename_ttf, pointSize, fg, style);
- setDest(dest);
-}
-NFont::NFont(SDL_Surface* dest, const char* filename_ttf, Uint32 pointSize, SDL_Color fg, SDL_Color bg, int style) {
- init();
- load(filename_ttf, pointSize, fg, bg, style);
- setDest(dest);
-}
-#endif
-
-void NFont::init() {
- src = NULL;
- dest = NULL;
-
- maxPos = 0;
-
- height = 0; // ascent+descent
-
- maxWidth = 0;
- baseline = 0;
- ascent = 0;
- descent = 0;
-
- lineSpacing = 0;
- letterSpacing = 0;
-
- if (buffer == NULL) {
- buffer = new char[1024];
- }
-}
-
-NFont::~NFont() {
-}
-
-
-// Loading
-bool NFont::load(SDL_Surface* FontSurface) {
- src = FontSurface;
- if (src == NULL) {
- printf("\n ERROR: NFont given a NULL surface\n");
- return false;
- }
-
- int x = 1, i = 0;
-
- // memset would be faster
- for (int j = 0; j < 256; j++) {
- charWidth[j] = 0;
- charPos[j] = 0;
- }
-
- SDL_LockSurface(src);
-
- Uint32 pixel = SDL_MapRGB(src->format, 255, 0, 255); // pink pixel
-
- maxWidth = 0;
-
- // Get the character positions and widths
- while (x < src->w) {
- if (getPixel(src, x, 0) != pixel) {
- charPos[i] = x;
- charWidth[i] = x;
- while (x < src->w && getPixel(src, x, 0) != pixel) {
- x++;
- }
- charWidth[i] = x - charWidth[i];
- if (charWidth[i] > maxWidth) {
- maxWidth = charWidth[i];
- }
- i++;
- }
-
- x++;
- }
-
- maxPos = x - 1;
-
-
- pixel = getPixel(src, 0, src->h - 1);
- int j;
- setBaseline();
-
- // Get the max ascent
- j = 1;
- while (j < baseline && j < src->h) {
- x = 0;
- while (x < src->w) {
- if (getPixel(src, x, j) != pixel) {
- ascent = baseline - j;
- j = src->h;
- break;
- }
- x++;
- }
- j++;
- }
-
- // Get the max descent
- j = src->h - 1;
- while (j > 0 && j > baseline) {
- x = 0;
- while (x < src->w) {
- if (getPixel(src, x, j) != pixel) {
- descent = j - baseline+1;
- j = 0;
- break;
- }
- x++;
- }
- j--;
- }
-
-
- height = ascent + descent;
-
-
- if ((src->flags & SDL_SRCALPHA) != SDL_SRCALPHA) {
- pixel = getPixel(src, 0, src->h - 1);
- SDL_UnlockSurface(src);
- SDL_SetColorKey(src, SDL_SRCCOLORKEY, pixel);
- }
- else {
- SDL_UnlockSurface(src);
- }
-
- return true;
-}
-
-bool NFont::load(SDL_Surface* destSurface, SDL_Surface* FontSurface) {
- setDest(destSurface);
- return load(FontSurface);
-}
-
-#ifdef NFONT_USE_TTF
-bool NFont::load(TTF_Font* ttf, SDL_Color fg, SDL_Color bg) {
- if (ttf == NULL) {
- return false;
- }
- SDL_Surface* surfs[127 - 33];
- int width = 0;
- int height = 0;
-
- char buff[2];
- buff[1] = '\0';
- for (int i = 0; i < 127 - 33; i++) {
- buff[0] = i + 33;
- surfs[i] = TTF_RenderText_Shaded(ttf, buff, fg, bg);
- width += surfs[i]->w;
- height = (height < surfs[i]->h)? surfs[i]->h : height;
- }
-
-#if SDL_BYTEORDER == SDL_BIG_ENDIAN
- SDL_Surface* result = SDL_CreateRGBSurface(SDL_SWSURFACE,width + 127 - 33 + 1,height,24, 0xFF0000, 0x00FF00, 0x0000FF, 0);
-#else
- SDL_Surface* result = SDL_CreateRGBSurface(SDL_SWSURFACE,width + 127 - 33 + 1,height,24, 0x0000FF, 0x00FF00, 0xFF0000, 0);
-#endif
- Uint32 pink = SDL_MapRGB(result->format, 255, 0, 255);
- Uint32 bgcolor = SDL_MapRGB(result->format, bg.r, bg.g, bg.b);
-
- SDL_Rect pixel = {1, 0, 1, 1};
- SDL_Rect line = {1, 0, 1, static_cast<Uint16>(result->h)};
-
- int x = 1;
- SDL_Rect dest = {static_cast<Sint16>(x), 0, 0, 0};
- for (int i = 0; i < 127 - 33; i++) {
- pixel.x = line.x = x-1;
- SDL_FillRect(result, &line, bgcolor);
- SDL_FillRect(result, &pixel, pink);
-
- SDL_BlitSurface(surfs[i], NULL, result, &dest);
-
- x += surfs[i]->w + 1;
- dest.x = x;
-
- SDL_FreeSurface(surfs[i]);
- }
- pixel.x = line.x = x-1;
- SDL_FillRect(result, &line, bgcolor);
- SDL_FillRect(result, &pixel, pink);
-
- return load(result);
-}
-
-
-bool NFont::load(TTF_Font* ttf, SDL_Color fg) {
- if (ttf == NULL) {
- return false;
- }
- SDL_Surface* surfs[127 - 33];
- int width = 0;
- int height = 0;
-
- char buff[2];
- buff[1] = '\0';
- for (int i = 0; i < 127 - 33; i++) {
- buff[0] = i + 33;
- surfs[i] = TTF_RenderText_Blended(ttf, buff, fg);
- width += surfs[i]->w;
- height = (height < surfs[i]->h)? surfs[i]->h : height;
- }
-
-#if SDL_BYTEORDER == SDL_BIG_ENDIAN
- SDL_Surface* result = SDL_CreateRGBSurface(SDL_SWSURFACE,width + 127 - 33 + 1,height,32, 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF);
-#else
- SDL_Surface* result = SDL_CreateRGBSurface(SDL_SWSURFACE,width + 127 - 33 + 1,height,32, 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000);
-#endif
- Uint32 pink = SDL_MapRGBA(result->format, 255, 0, 255, SDL_ALPHA_OPAQUE);
-
- SDL_SetAlpha(result, 0, SDL_ALPHA_OPAQUE);
-
- SDL_Rect pixel = {1, 0, 1, 1};
-
- int x = 1;
- SDL_Rect dest = {static_cast<Sint16>(x), 0, 0, 0};
- for (int i = 0; i < 127 - 33; i++) {
- pixel.x = x-1;
- SDL_FillRect(result, &pixel, pink);
-
- SDL_SetAlpha(surfs[i], 0, SDL_ALPHA_OPAQUE);
- SDL_BlitSurface(surfs[i], NULL, result, &dest);
-
- x += surfs[i]->w + 1;
- dest.x = x;
-
- SDL_FreeSurface(surfs[i]);
- }
- pixel.x = x-1;
- SDL_FillRect(result, &pixel, pink);
-
- SDL_SetAlpha(result, SDL_SRCALPHA, SDL_ALPHA_OPAQUE);
-
- return load(result);
-}
-
-
-bool NFont::load(const char* filename_ttf, Uint32 pointSize, SDL_Color fg, int style) {
- if (!TTF_WasInit() && TTF_Init() < 0) {
- printf("Unable to initialize SDL_ttf: %s \n", TTF_GetError());
- return false;
- }
-
- TTF_Font* ttf = TTF_OpenFont(filename_ttf, pointSize);
-
- if (ttf == NULL) {
- printf("Unable to load TrueType font: %s \n", TTF_GetError());
- return false;
- }
- TTF_SetFontStyle(ttf, style);
- bool result = load(ttf, fg);
- TTF_CloseFont(ttf);
- return result;
-}
-
-bool NFont::load(const char* filename_ttf, Uint32 pointSize, SDL_Color fg, SDL_Color bg, int style) {
- if (!TTF_WasInit() && TTF_Init() < 0) {
- printf("Unable to initialize SDL_ttf: %s \n", TTF_GetError());
- return false;
- }
-
- TTF_Font* ttf = TTF_OpenFont(filename_ttf, pointSize);
-
- if (ttf == NULL) {
- printf("Unable to load TrueType font: %s \n", TTF_GetError());
- return false;
- }
- TTF_SetFontStyle(ttf, style);
- bool result = load(ttf, fg, bg);
- TTF_CloseFont(ttf);
- return result;
-}
-
-#endif
-
-
-
-void NFont::freeSurface() {
- SDL_FreeSurface(src);
-}
-
-
-
-// Drawing
-SDL_Rect NFont::drawToSurface(int x, int y, const char* text) const {
- const char* c = text;
- unsigned char num;
- SDL_Rect srcRect, dstRect, copyS, copyD;
- data.dirtyRect = makeRect(x, y, 0, 0);
-
- if (c == NULL || src == NULL || dest == NULL) {
- return data.dirtyRect;
- }
-
- srcRect.y = baseline - ascent;
- srcRect.h = dstRect.h = height;
- dstRect.x = x;
- dstRect.y = y;
-
- int newlineX = x;
-
- for (; *c != '\0'; c++) {
- if (*c == '\n') {
- dstRect.x = newlineX;
- dstRect.y += height + lineSpacing;
- continue;
- }
-
- if (*c == ' ') {
- dstRect.x += charWidth[0] + letterSpacing;
- continue;
- }
- unsigned char ctest = (unsigned char)(*c);
- // Skip bad characters
- if (ctest < 33 || (ctest > 126 && ctest < 161)) {
- continue;
- }
- if (dstRect.x >= dest->w) {
- continue;
- }
- if (dstRect.y >= dest->h) {
- continue;
- }
-
- num = ctest - 33; // Get array index
- if (num > 126) { // shift the extended characters down to the correct index
- num -= 34;
- }
- srcRect.x = charPos[num];
- srcRect.w = dstRect.w = charWidth[num];
- copyS = srcRect;
- copyD = dstRect;
- SDL_BlitSurface(src, &srcRect, dest, &dstRect);
- if (data.dirtyRect.w == 0 || data.dirtyRect.h == 0) {
- data.dirtyRect = dstRect;
- }
- else {
- data.dirtyRect = rectUnion(data.dirtyRect, dstRect);
- }
- srcRect = copyS;
- dstRect = copyD;
-
- dstRect.x += dstRect.w + letterSpacing;
- }
-
- return data.dirtyRect;
-}
-
-SDL_Rect NFont::drawToSurfacePos(int x, int y, NFont::AnimFn posFn) const {
- data.font = this;
- data.dest = dest;
- data.src = src;
- data.text = buffer; // Buffer for efficient drawing
- data.height = height;
- data.charPos = charPos;
- data.charWidth = charWidth;
- data.maxX = maxPos;
- data.dirtyRect = makeRect(x,y,0,0);
-
- data.index = -1;
- data.letterNum = 0;
- data.wordNum = 1;
- data.lineNum = 1;
- data.startX = x; // used as reset value for line feed
- data.startY = y;
-
- int preFnX = x;
- int preFnY = y;
-
- const char* c = buffer;
- unsigned char num;
- SDL_Rect srcRect, dstRect, copyS, copyD;
-
- if (c == NULL || src == NULL || dest == NULL) {
- return makeRect(x,y,0,0);
- }
-
- srcRect.y = baseline - ascent;
- srcRect.h = dstRect.h = height;
- dstRect.x = x;
- dstRect.y = y;
-
- for (; *c != '\0'; c++) {
- data.index++;
- data.letterNum++;
-
- if (*c == '\n') {
- data.letterNum = 1;
- data.wordNum = 1;
- data.lineNum++;
-
- x = data.startX; // carriage return
- y += height + lineSpacing;
- continue;
- }
- if (*c == ' ') {
- data.letterNum = 1;
- data.wordNum++;
-
- x += charWidth[0] + letterSpacing;
- continue;
- }
- unsigned char ctest = (unsigned char)(*c);
- // Skip bad characters
- if (ctest < 33 || (ctest > 126 && ctest < 161)) {
- continue;
- }
- //if(x >= dest->w) // This shouldn't be used with position control
- // continue;
- num = ctest - 33;
- if (num > 126) { // shift the extended characters down to the array index
- num -= 34;
- }
- srcRect.x = charPos[num];
- srcRect.w = dstRect.w = charWidth[num];
-
- preFnX = x; // Save real position
- preFnY = y;
-
- // Use function pointer to get final x, y values
- posFn(x, y, data);
-
- dstRect.x = x;
- dstRect.y = y;
-
- copyS = srcRect;
- copyD = dstRect;
- SDL_BlitSurface(src, &srcRect, dest, &dstRect);
- if (data.dirtyRect.w == 0 || data.dirtyRect.h == 0) {
- data.dirtyRect = dstRect;
- }
- else {
- data.dirtyRect = rectUnion(data.dirtyRect, dstRect);
- }
- srcRect = copyS;
- dstRect = copyD;
-
- x = preFnX; // Restore real position
- y = preFnY;
-
- x += dstRect.w + letterSpacing;
- }
-
- return data.dirtyRect;
-}
-
-SDL_Rect NFont::draw(int x, int y, const char* formatted_text, ...) const {
- if (formatted_text == NULL) {
- return makeRect(x, y, 0, 0);
- }
-
- va_list lst;
- va_start(lst, formatted_text);
- vsprintf(buffer, formatted_text, lst);
- va_end(lst);
-
- return drawToSurface(x, y, buffer);
-}
-
-SDL_Rect NFont::drawCenter(int x, int y, const char* formatted_text, ...) const {
- if (formatted_text == NULL) {
- return makeRect(x, y, 0, 0);
- }
-
- va_list lst;
- va_start(lst, formatted_text);
- vsprintf(buffer, formatted_text, lst);
- va_end(lst);
-
- char* str = copyString(buffer);
- char* del = str;
-
- // Go through str, when you find a \n, replace it with \0 and print it
- // then move down, back, and continue.
- for (char* c = str; *c != '\0';) {
- if (*c == '\n') {
- *c = '\0';
- drawToSurface(x - getWidth("%s", str)/2, y, str);
- *c = '\n';
- c++;
- str = c;
- y += height;
- }
- else {
- c++;
- }
- }
- char s[strlen(str)+1];
- strcpy(s, str);
- delete[] del;
-
- return drawToSurface(x - getWidth("%s", s)/2, y, s);
-}
-
-SDL_Rect NFont::drawRight(int x, int y, const char* formatted_text, ...) const {
- if (formatted_text == NULL) {
- return makeRect(x, y, 0, 0);
- }
-
- va_list lst;
- va_start(lst, formatted_text);
- vsprintf(buffer, formatted_text, lst);
- va_end(lst);
-
- char* str = copyString(buffer);
- char* del = str;
-
- for (char* c = str; *c != '\0';) {
- if (*c == '\n') {
- *c = '\0';
- drawToSurface(x - getWidth("%s", str), y, str);
- *c = '\n';
- c++;
- str = c;
- y += height;
- }
- else {
- c++;
- }
- }
- char s[strlen(str)+1];
- strcpy(s, str);
- delete[] del;
-
- return drawToSurface(x - getWidth("%s", s), y, s);
-}
-
-SDL_Rect NFont::drawPos(int x, int y, NFont::AnimFn posFn, const char* text, ...) const {
- va_list lst;
- va_start(lst, text);
- vsprintf(buffer, text, lst);
- va_end(lst);
-
- return drawToSurfacePos(x, y, posFn);
-}
-
-SDL_Rect NFont::drawAll(int x, int y, NFont::AnimFn allFn, const char* text, ...) const {
- va_list lst;
- va_start(lst, text);
- vsprintf(buffer, text, lst);
- va_end(lst);
-
- allFn(x, y, data);
- return data.dirtyRect;
-}
-
-
-
-
-// Getters
-SDL_Surface* NFont::getDest() const {
- return dest;
-}
-
-SDL_Surface* NFont::getSurface() const {
- return src;
-}
-
-int NFont::getHeight(const char* formatted_text, ...) const {
- if (formatted_text == NULL) {
- return height;
- }
-
- va_list lst;
- va_start(lst, formatted_text);
- vsprintf(buffer, formatted_text, lst);
- va_end(lst);
-
- int numLines = 1;
- const char* c;
-
- for (c = buffer; *c != '\0'; c++) {
- if (*c == '\n') {
- numLines++;
- }
- }
-
- // Actual height of letter region + line spacing
- return height*numLines + lineSpacing*(numLines - 1); //height*numLines;
-}
-
-int NFont::getWidth(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);
-
- const char* c;
- int charnum = 0;
- int width = 0;
- int bigWidth = 0; // Allows for multi-line strings
-
- for (c = buffer; *c != '\0'; c++) {
- charnum = (unsigned char)(*c) - 33;
-
- // skip spaces and nonprintable characters
- if (*c == '\n') {
- bigWidth = bigWidth >= width? bigWidth : width;
- width = 0;
- }
- else if (*c == ' ' || charnum > 222) {
- width += charWidth[0];
- continue;
- }
-
- width += charWidth[charnum];
- }
- bigWidth = bigWidth >= width? bigWidth : width;
-
- return bigWidth;
-}
-
-int NFont::getAscent(const char character) const {
- unsigned char test = (unsigned char)character;
- if (test < 33 || test > 222 || (test > 126 && test < 161)) {
- return 0;
- }
- unsigned char num = (unsigned char)character - 33;
- // Get the max ascent
- int x = charPos[num];
- int i, j = 1, result = 0;
- Uint32 pixel = getPixel(src, 0, src->h - 1); // bg pixel
- while (j < baseline && j < src->h) {
- i = charPos[num];
- while (i < x + charWidth[num]) {
- if (getPixel(src, i, j) != pixel) {
- result = baseline - j;
- j = src->h;
- break;
- }
- i++;
- }
- j++;
- }
- return result;
-}
-
-int NFont::getAscent(const char* formatted_text, ...) const {
- if (formatted_text == NULL) {
- return ascent;
- }
-
- va_list lst;
- va_start(lst, formatted_text);
- vsprintf(buffer, formatted_text, lst);
- va_end(lst);
-
- int max = 0;
- const char* c = buffer;
-
- for (; *c != '\0'; c++) {
- int asc = getAscent(*c);
- if (asc > max) {
- max = asc;
- }
- }
- return max;
-}
-
-int NFont::getDescent(const char character) const {
- unsigned char test = (unsigned char)character;
- if (test < 33 || test > 222 || (test > 126 && test < 161)) {
- return 0;
- }
- unsigned char num = (unsigned char)character - 33;
- // Get the max descent
- int x = charPos[num];
- int i, j = src->h - 1, result = 0;
- Uint32 pixel = getPixel(src, 0, src->h - 1); // bg pixel
- while (j > 0 && j > baseline) {
- i = charPos[num];
- while (i < x + charWidth[num]) {
- if (getPixel(src, i, j) != pixel) {
- result = j - baseline;
- j = 0;
- break;
- }
- i++;
- }
- j--;
- }
- return result;
-}
-
-int NFont::getDescent(const char* formatted_text, ...) const {
- if (formatted_text == NULL) {
- return descent;
- }
-
- va_list lst;
- va_start(lst, formatted_text);
- vsprintf(buffer, formatted_text, lst);
- va_end(lst);
-
- int max = 0;
- const char* c = buffer;
-
- for (; *c != '\0'; c++) {
- int des = getDescent(*c);
- if (des > max) {
- max = des;
- }
- }
- return max;
-}
-
-int NFont::getSpacing() const {
- return letterSpacing;
-}
-
-int NFont::getLineSpacing() const {
- return lineSpacing;
-}
-
-int NFont::getBaseline() const {
- return baseline;
-}
-
-int NFont::getMaxWidth() const {
- return maxWidth;
-}
-
-
-
-
-
-// Setters
-void NFont::setSpacing(int LetterSpacing) {
- letterSpacing = LetterSpacing;
-}
-
-void NFont::setLineSpacing(int LineSpacing) {
- lineSpacing = LineSpacing;
-}
-
-void NFont::setDest(SDL_Surface* Dest) {
- dest = Dest;
-}
-
-int NFont::setBaseline(int Baseline) {
- if (Baseline >= 0) {
- baseline = Baseline;
- }
- else {
- // Get the baseline by checking a, b, and c and averaging their lowest y-value.
- // Is there a better way?
- Uint32 pixel = getPixel(src, 0, src->h - 1);
- int heightSum = 0;
- int x, i, j;
- for (unsigned char avgChar = 64; avgChar < 67; avgChar++) {
- x = charPos[avgChar];
-
- j = src->h - 1;
- while (j > 0) {
- i = x;
- while (i - x < charWidth[64]) {
- if (getPixel(src, i, j) != pixel) {
- heightSum += j;
- j = 0;
- break;
- }
- i++;
- }
- j--;
- }
- }
- baseline = int(heightSum/3.0f + 0.5f); // Round up and cast
- }
- return baseline;
-}
-
-
-
-
-
-
-
+/*
+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 <cmath>
+#include <cstdio>
+#ifndef M_PI
+ #define M_PI 3.14159265358979323846
+#endif
+
+#include <string>
+#include <cstring>
+#include <list>
+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<string> explode(const string& str, char delimiter)
+{
+ list<string> 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/Libs/NFont.h b/source/code/Libs/NFont.h
index 0d6d581..9351dd8 100644
--- a/source/code/Libs/NFont.h
+++ b/source/code/Libs/NFont.h
@@ -1,224 +1,305 @@
-
-// Define this here or in your project settings if you want to use the SDL_ttf features.
-#define NFONT_USE_TTF
-
-/*
-NFont v2.0.0: A bitmap font class for SDL
-by Jonathan Dearborn 2-4-10
-(class originally adapted from Florian Hufsky)
-
-Requires:
- SDL ("SDL.h") [www.libsdl.org]
-
-Optionally Requires:
- SDL_ttf ("SDL_ttf.h") [www.libsdl.org]
-
-Notes:
- NFont is a bitmap font class with text-block alignment, full
- support for the newline character ('\n'), animation, and extended ASCII
- support. It accepts SDL_Surfaces so that any image format you can load
- can be used as an NFont.
-
- NFont has the ability to animate the font in two ways: It's position or
- it's everything. By using drawPos(), you can use a function you create
- to handle the final positions of the drawn characters. With drawAll(),
- you can handle everything that the font does (please use my
- drawToSurface() function as a reference).
-
- Internally, NFont uses a pointer (SDL_Surface*) to handle the destination
- surface. You have to set the destination before the font can be used. Be
- aware that you will need to use setDest() if you replace the memory that
- it points to (like when using screen = SDL_SetVideoMode()).
-
- NFont can use standard SFont bitmaps or extended bitmaps. The standard bitmaps
- have the following characters (ASCII 33-126) separated by pink (255, 0, 255) pixels in the topmost
- row:
- ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~
-
- And the extended bitmaps have these (ASCII 161-255):
- ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~ � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � � �
-
- NFont can also load SDL_ttf fonts. Define NFONT_USE_TTF before including
- NFont.h to use the flexibility of NFont with TrueType fonts.
-
- If you come up with something cool using NFont, I'd love to hear about it.
- Any comments can be sent to GrimFang4 [at] gmail [dot] com
-
-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) 2010 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.
-
-*/
-
-#ifndef _NFONT_H__
-#define _NFONT_H__
-
-#include "SDL.h"
-#include "stdarg.h"
-
-#ifdef NFONT_USE_TTF
-#include "SDL_ttf.h"
-#endif
-
-class NFont
-{
-public:
-
- // Nested struct
- struct AnimData
- {
- const NFont* font;
-
- SDL_Surface* dest;
- SDL_Surface* src;
- char* text; // Buffer for efficient drawing
- int height;
- const int* charPos;
- const int* charWidth;
- int maxX;
-
- int index;
- int letterNum;
- int wordNum;
- int lineNum;
- int startX;
- int startY;
- void* userVar;
-
- SDL_Rect dirtyRect;
- };
-
- // Function pointer
- typedef void (*AnimFn)(int&, int&, AnimData&);
-
-protected:
-
-
- SDL_Surface* src; // bitmap source of characters
- SDL_Surface* dest; // Destination to blit to
-
- int height;
-
- int maxWidth;
- int baseline;
- int ascent;
- int descent;
-
- int lineSpacing;
- int letterSpacing;
-
- int charPos[256];
- int charWidth[256];
- int maxPos;
-
- void init();
-
- SDL_Rect drawToSurface(int x, int y, const char* text) const;
- SDL_Rect drawToSurfacePos(int x, int y, NFont::AnimFn posFn) const;
-
- // Static variables
- static char* buffer; // Buffer for efficient drawing
- static AnimData data; // Data is wrapped in a struct so it can all be passed to
- // the function pointers for animation
-
-public:
-
- // Static functions
- static char* copyString(const char* c);
- static Uint32 getPixel(SDL_Surface *Surface, int x, int y);
- static inline SDL_Rect makeRect(Sint16 x, Sint16 y, Uint16 w, Uint16 h)
- {
- SDL_Rect r = {x, y, w, h};
- return r;
- }
- static SDL_Rect rectUnion(const SDL_Rect& A, const SDL_Rect& B);
- static SDL_Surface* copySurface(SDL_Surface *Surface);
- static SDL_Surface* verticalGradient(SDL_Surface* targetSurface, Uint32 topColor, Uint32 bottomColor, int heightAdjust = 0);
-
- // Static accessors
- static void setAnimData(void* data);
- static void setBuffer(unsigned int size);
-
- // Constructors
- NFont();
- NFont(SDL_Surface* src);
- NFont(SDL_Surface* dest, SDL_Surface* src);
-#ifdef NFONT_USE_TTF
- NFont(TTF_Font* ttf, SDL_Color fg); // Alpha bg
- NFont(TTF_Font* ttf, SDL_Color fg, SDL_Color bg);
- NFont(const char* filename_ttf, Uint32 pointSize, SDL_Color fg, int style = TTF_STYLE_NORMAL); // Alpha bg
- NFont(const char* filename_ttf, Uint32 pointSize, SDL_Color fg, SDL_Color bg, int style = TTF_STYLE_NORMAL);
- NFont(SDL_Surface* dest, TTF_Font* ttf, SDL_Color fg); // Alpha bg
- NFont(SDL_Surface* dest, TTF_Font* ttf, SDL_Color fg, SDL_Color bg);
- NFont(SDL_Surface* dest, const char* filename_ttf, Uint32 pointSize, SDL_Color fg, int style = TTF_STYLE_NORMAL); // Alpha bg
- NFont(SDL_Surface* dest, const char* filename_ttf, Uint32 pointSize, SDL_Color fg, SDL_Color bg, int style = TTF_STYLE_NORMAL);
-#endif
-
- ~NFont();
-
- // Loading
- bool load(SDL_Surface* FontSurface);
- bool load(SDL_Surface* destSurface, SDL_Surface* FontSurface);
-#ifdef NFONT_USE_TTF
- bool load(TTF_Font* ttf, SDL_Color fg); // Alpha bg
- bool load(TTF_Font* ttf, SDL_Color fg, SDL_Color bg);
- bool load(const char* filename_ttf, Uint32 pointSize, SDL_Color fg, int style = TTF_STYLE_NORMAL); // Alpha bg
- bool load(const char* filename_ttf, Uint32 pointSize, SDL_Color fg, SDL_Color bg, int style = TTF_STYLE_NORMAL);
-#endif
-
- void freeSurface();
-
- // Drawing
- SDL_Rect draw(int x, int y, const char* formatted_text, ...) const __attribute__ ((format (printf, 4, 5)));
- SDL_Rect drawCenter(int x, int y, const char* formatted_text, ...) const __attribute__ ((format (printf, 4, 5)));
- SDL_Rect drawRight(int x, int y, const char* formatted_text, ...) const __attribute__ ((format (printf, 4, 5)));
- SDL_Rect drawPos(int x, int y, NFont::AnimFn posFn, const char* text, ...) const __attribute__ ((format (printf, 5, 6)));
- SDL_Rect drawAll(int x, int y, NFont::AnimFn allFn, const char* text, ...) const __attribute__ ((format (printf, 5, 6)));
-
- // Getters
- SDL_Surface* getDest() const;
- SDL_Surface* getSurface() const;
- int getHeight(const char* formatted_text = NULL, ...) const __attribute__ ((format (printf, 2, 3)));
- int getWidth(const char* formatted_text, ...) const __attribute__ ((format (printf, 2, 3)));
- int getSpacing() const;
- int getLineSpacing() const;
- int getBaseline() const;
- int getAscent(const char character) const;
- int getAscent(const char* formatted_text = NULL, ...) const __attribute__ ((format (printf, 2, 3)));
- int getDescent(const char character) const;
- int getDescent(const char* formatted_text = NULL, ...) const __attribute__ ((format (printf, 2, 3)));
- int getMaxWidth() const;
-
- // Setters
- void setDest(SDL_Surface* Dest);
- void setSpacing(int LetterSpacing);
- void setLineSpacing(int LineSpacing);
- int setBaseline(int Baseline = -1);
-
-};
-
-
-
-#endif // _NFONT_H__
+/*
+NFont v4.0.0: A font class for SDL and SDL_Renderer
+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.
+*/
+
+#ifndef _NFONT_H__
+#define _NFONT_H__
+
+#include "SDL.h"
+
+#if defined(FC_USE_SDL_GPU) && !defined(NFONT_USE_SDL_GPU)
+#define NFONT_USE_SDL_GPU
+#endif
+
+#ifdef NFONT_USE_SDL_GPU
+ #include "SDL_gpu.h"
+#endif
+
+#include "stdarg.h"
+
+// Let's pretend this exists...
+#ifndef TTF_STYLE_OUTLINE
+ #define TTF_STYLE_OUTLINE 16
+#endif
+
+struct FC_Font;
+
+typedef struct _TTF_Font TTF_Font;
+
+#if defined(NFONT_DLL) || defined(NFONT_DLL_EXPORT)
+ #ifdef NFONT_DLL_EXPORT
+ #define NFONT_EXPORT __declspec(dllexport)
+ #else
+ #define NFONT_EXPORT __declspec(dllimport)
+ #endif
+#else
+ #define NFONT_EXPORT
+#endif
+
+class NFONT_EXPORT NFont
+{
+ public:
+
+ class NFONT_EXPORT Color
+ {
+ public:
+
+ Uint8 r, g, b, a;
+
+ Color();
+ Color(Uint8 r, Uint8 g, Uint8 b);
+ Color(Uint8 r, Uint8 g, Uint8 b, Uint8 a);
+ Color(const SDL_Color& color);
+
+ Color& rgb(Uint8 R, Uint8 G, Uint8 B);
+ Color& rgba(Uint8 R, Uint8 G, Uint8 B, Uint8 A);
+ Color& color(const SDL_Color& color);
+
+ SDL_Color to_SDL_Color() const;
+ };
+
+ class NFONT_EXPORT Rectf
+ {
+ public:
+ float x, y;
+ float w, h;
+
+ Rectf();
+ Rectf(float x, float y);
+ Rectf(float x, float y, float w, float h);
+ Rectf(const SDL_Rect& rect);
+
+ SDL_Rect to_SDL_Rect() const;
+
+ #ifdef NFONT_USE_SDL_GPU
+ Rectf(const GPU_Rect& rect);
+ GPU_Rect to_GPU_Rect() const;
+ #endif
+ };
+
+
+ enum AlignEnum {LEFT, CENTER, RIGHT};
+ enum FilterEnum {NEAREST, LINEAR};
+
+ class NFONT_EXPORT Scale
+ {
+ public:
+
+ float x;
+ float y;
+
+ enum ScaleTypeEnum {NEAREST};
+ ScaleTypeEnum type;
+
+ Scale()
+ : x(1.0f), y(1.0f), type(NEAREST)
+ {}
+ Scale(float xy)
+ : x(xy), y(xy), type(NEAREST)
+ {}
+ Scale(float xy, ScaleTypeEnum type)
+ : x(xy), y(xy), type(type)
+ {}
+ Scale(float x, float y)
+ : x(x), y(y), type(NEAREST)
+ {}
+ Scale(float x, float y, ScaleTypeEnum type)
+ : x(x), y(y), type(type)
+ {}
+ };
+
+ class NFONT_EXPORT Effect
+ {
+ public:
+ AlignEnum alignment;
+ Scale scale;
+ bool use_color;
+ Color color;
+
+ Effect()
+ : alignment(LEFT), use_color(false), color(255, 255, 255, 255)
+ {}
+
+ Effect(const Scale& scale)
+ : alignment(LEFT), scale(scale), use_color(false), color(255, 255, 255, 255)
+ {}
+ Effect(AlignEnum alignment)
+ : alignment(alignment), use_color(false), color(255, 255, 255, 255)
+ {}
+ Effect(const Color& color)
+ : alignment(LEFT), use_color(true), color(color)
+ {}
+
+ Effect(AlignEnum alignment, const Scale& scale)
+ : alignment(alignment), scale(scale), use_color(false), color(255, 255, 255, 255)
+ {}
+ Effect(AlignEnum alignment, const Color& color)
+ : alignment(alignment), use_color(true), color(color)
+ {}
+ Effect(const Scale& scale, const Color& color)
+ : alignment(LEFT), scale(scale), use_color(true), color(color)
+ {}
+ Effect(AlignEnum alignment, const Scale& scale, const Color& color)
+ : alignment(alignment), scale(scale), use_color(true), color(color)
+ {}
+ };
+
+
+ // Constructors
+ NFont();
+ NFont(const NFont& font);
+ #ifdef NFONT_USE_SDL_GPU
+ NFont(SDL_Surface* src);
+ NFont(TTF_Font* ttf);
+ NFont(TTF_Font* ttf, const NFont::Color& color);
+ NFont(const char* filename_ttf, Uint32 pointSize);
+ NFont(const char* filename_ttf, Uint32 pointSize, const NFont::Color& color, int style = 0);
+ NFont(SDL_RWops* file_rwops_ttf, Uint8 own_rwops, Uint32 pointSize, const NFont::Color& color, int style = 0);
+ #else
+ NFont(SDL_Renderer* renderer, SDL_Surface* src);
+ NFont(SDL_Renderer* renderer, TTF_Font* ttf);
+ NFont(SDL_Renderer* renderer, TTF_Font* ttf, const NFont::Color& color);
+ NFont(SDL_Renderer* renderer, const char* filename_ttf, Uint32 pointSize);
+ NFont(SDL_Renderer* renderer, const char* filename_ttf, Uint32 pointSize, const NFont::Color& color, int style = 0);
+ NFont(SDL_Renderer* renderer, SDL_RWops* file_rwops_ttf, Uint8 own_rwops, Uint32 pointSize, const NFont::Color& color, int style = 0);
+ #endif
+
+ ~NFont();
+
+ NFont& operator=(const NFont& font);
+
+ // Loading
+ void setLoadingString(const char* str);
+
+ #ifdef NFONT_USE_SDL_GPU
+ bool load(SDL_Surface* FontSurface);
+ bool load(TTF_Font* ttf);
+ bool load(TTF_Font* ttf, const NFont::Color& color);
+ bool load(const char* filename_ttf, Uint32 pointSize);
+ bool load(const char* filename_ttf, Uint32 pointSize, const NFont::Color& color, int style = 0);
+ bool load(SDL_RWops* file_rwops_ttf, Uint8 own_rwops, Uint32 pointSize, const NFont::Color& color, int style = 0);
+ #else
+ bool load(SDL_Renderer* renderer, SDL_Surface* FontSurface);
+ bool load(SDL_Renderer* renderer, TTF_Font* ttf);
+ bool load(SDL_Renderer* renderer, TTF_Font* ttf, const NFont::Color& color);
+ bool load(SDL_Renderer* renderer, const char* filename_ttf, Uint32 pointSize);
+ bool load(SDL_Renderer* renderer, const char* filename_ttf, Uint32 pointSize, const NFont::Color& color, int style = 0);
+ bool load(SDL_Renderer* renderer, SDL_RWops* file_rwops_ttf, Uint8 own_rwops, Uint32 pointSize, const NFont::Color& color, int style = 0);
+ #endif
+
+ void free();
+
+ // Drawing
+ #ifdef NFONT_USE_SDL_GPU
+ Rectf draw(GPU_Target* dest, float x, float y, const char* formatted_text, ...);
+ Rectf draw(GPU_Target* dest, float x, float y, AlignEnum align, const char* formatted_text, ...);
+ Rectf draw(GPU_Target* dest, float x, float y, const Scale& scale, const char* formatted_text, ...);
+ Rectf draw(GPU_Target* dest, float x, float y, const Color& color, const char* formatted_text, ...);
+ Rectf draw(GPU_Target* dest, float x, float y, const Effect& effect, const char* formatted_text, ...);
+
+ Rectf drawBox(GPU_Target* dest, const Rectf& box, const char* formatted_text, ...);
+ Rectf drawBox(GPU_Target* dest, const Rectf& box, AlignEnum align, const char* formatted_text, ...);
+ Rectf drawBox(GPU_Target* dest, const Rectf& box, const Scale& scale, const char* formatted_text, ...);
+ Rectf drawBox(GPU_Target* dest, const Rectf& box, const Color& color, const char* formatted_text, ...);
+ Rectf drawBox(GPU_Target* dest, const Rectf& box, const Effect& effect, const char* formatted_text, ...);
+
+ Rectf drawColumn(GPU_Target* dest, float x, float y, Uint16 width, const char* formatted_text, ...);
+ Rectf drawColumn(GPU_Target* dest, float x, float y, Uint16 width, AlignEnum align, const char* formatted_text, ...);
+ Rectf drawColumn(GPU_Target* dest, float x, float y, Uint16 width, const Scale& scale, const char* formatted_text, ...);
+ Rectf drawColumn(GPU_Target* dest, float x, float y, Uint16 width, const Color& color, const char* formatted_text, ...);
+ Rectf drawColumn(GPU_Target* dest, float x, float y, Uint16 width, const Effect& effect, const char* formatted_text, ...);
+ #else
+ Rectf draw(SDL_Renderer* dest, float x, float y, const char* formatted_text, ...);
+ Rectf draw(SDL_Renderer* dest, float x, float y, AlignEnum align, const char* formatted_text, ...);
+ Rectf draw(SDL_Renderer* dest, float x, float y, const Scale& scale, const char* formatted_text, ...);
+ Rectf draw(SDL_Renderer* dest, float x, float y, const Color& color, const char* formatted_text, ...);
+ Rectf draw(SDL_Renderer* dest, float x, float y, const Effect& effect, const char* formatted_text, ...);
+
+ Rectf drawBox(SDL_Renderer* dest, const Rectf& box, const char* formatted_text, ...);
+ Rectf drawBox(SDL_Renderer* dest, const Rectf& box, AlignEnum align, const char* formatted_text, ...);
+ Rectf drawBox(SDL_Renderer* dest, const Rectf& box, const Scale& scale, const char* formatted_text, ...);
+ Rectf drawBox(SDL_Renderer* dest, const Rectf& box, const Color& color, const char* formatted_text, ...);
+ Rectf drawBox(SDL_Renderer* dest, const Rectf& box, const Effect& effect, const char* formatted_text, ...);
+
+ Rectf drawColumn(SDL_Renderer* dest, float x, float y, Uint16 width, const char* formatted_text, ...);
+ Rectf drawColumn(SDL_Renderer* dest, float x, float y, Uint16 width, AlignEnum align, const char* formatted_text, ...);
+ Rectf drawColumn(SDL_Renderer* dest, float x, float y, Uint16 width, const Scale& scale, const char* formatted_text, ...);
+ Rectf drawColumn(SDL_Renderer* dest, float x, float y, Uint16 width, const Color& color, const char* formatted_text, ...);
+ Rectf drawColumn(SDL_Renderer* dest, float x, float y, Uint16 width, const Effect& effect, const char* formatted_text, ...);
+ #endif
+
+ // Getters
+ #ifdef NFONT_USE_SDL_GPU
+ GPU_Image* getImage() const;
+ #else
+ SDL_Texture* getImage() const;
+ #endif
+ SDL_Surface* getSurface() const;
+ FilterEnum getFilterMode() const;
+ Uint16 getHeight() const;
+ Uint16 getHeight(const char* formatted_text, ...) const;
+ Uint16 getWidth(const char* formatted_text, ...);
+ Rectf getCharacterOffset(Uint16 position_index, int column_width, const char* formatted_text, ...);
+ Uint16 getColumnHeight(Uint16 width, const char* formatted_text, ...);
+ int getSpacing() const;
+ int getLineSpacing() const;
+ Uint16 getBaseline() const;
+ int getAscent() const;
+ int getAscent(const char character);
+ int getAscent(const char* formatted_text, ...);
+ int getDescent() const;
+ int getDescent(const char character);
+ int getDescent(const char* formatted_text, ...);
+ Uint16 getMaxWidth() const;
+ Color getDefaultColor() const;
+
+ // Setters
+ void setFilterMode(FilterEnum filter);
+ void setSpacing(int LetterSpacing);
+ void setLineSpacing(int LineSpacing);
+ void setBaseline();
+ void setBaseline(Uint16 Baseline);
+ void setDefaultColor(const Color& color);
+
+ void enableTTFOwnership();
+
+ private:
+
+ static char* buffer;
+ FC_Font* font;
+
+ void init(); // Common constructor
+
+};
+
+
+
+#endif // _NFONT_H__
diff --git a/source/code/Libs/SDL_FontCache.c b/source/code/Libs/SDL_FontCache.c
new file mode 100644
index 0000000..4533d7a
--- /dev/null
+++ b/source/code/Libs/SDL_FontCache.c
@@ -0,0 +1,2544 @@
+/*
+SDL_FontCache v0.0.1: A font cache for SDL and SDL_ttf
+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) 2015 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 "SDL_FontCache.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+// Visual C does not support static inline
+#ifndef static_inline
+ #ifdef _MSC_VER
+ #define static_inline static
+ #else
+ #define static_inline static inline
+ #endif
+#endif
+
+#if SDL_VERSION_ATLEAST(2,0,0)
+ #define FC_GET_ALPHA(sdl_color) ((sdl_color).a)
+#else
+ #define FC_GET_ALPHA(sdl_color) ((sdl_color).unused)
+#endif
+
+// Need SDL_RenderIsClipEnabled() for proper clipping support
+#if SDL_VERSION_ATLEAST(2,0,4)
+ #define ENABLE_SDL_CLIPPING
+#endif
+
+#define FC_MIN(a,b) ((a) < (b)? (a) : (b))
+#define FC_MAX(a,b) ((a) > (b)? (a) : (b))
+
+
+#define FC_EXTRACT_VARARGS(buffer, start_args) \
+{ \
+ va_list lst; \
+ va_start(lst, start_args); \
+ vsprintf(buffer, start_args, lst); \
+ va_end(lst); \
+}
+
+// Extra pixels of padding around each glyph to avoid linear filtering artifacts
+#define FC_CACHE_PADDING 1
+
+
+
+static Uint8 has_clip(FC_Target* dest)
+{
+ #ifdef FC_USE_SDL_GPU
+ return dest->use_clip_rect;
+ #elif defined(ENABLE_SDL_CLIPPING)
+ return SDL_RenderIsClipEnabled(dest);
+ #else
+ return 0;
+ #endif
+}
+
+static FC_Rect get_clip(FC_Target* dest)
+{
+ #ifdef FC_USE_SDL_GPU
+ return dest->clip_rect;
+ #elif defined(ENABLE_SDL_CLIPPING)
+ SDL_Rect r;
+ SDL_RenderGetClipRect(dest, &r);
+ return r;
+ #else
+ SDL_Rect r = {0, 0, 0, 0};
+ return r;
+ #endif
+}
+
+static void set_clip(FC_Target* dest, FC_Rect* rect)
+{
+ #ifdef FC_USE_SDL_GPU
+ if(rect != NULL)
+ GPU_SetClipRect(dest, *rect);
+ else
+ GPU_UnsetClip(dest);
+ #elif defined(ENABLE_SDL_CLIPPING)
+ SDL_RenderSetClipRect(dest, rect);
+ #endif
+}
+
+static void set_color(FC_Image* src, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
+{
+ #ifdef FC_USE_SDL_GPU
+ GPU_SetRGBA(src, r, g, b, a);
+ #else
+ SDL_SetTextureColorMod(src, r, g, b);
+ SDL_SetTextureAlphaMod(src, a);
+ #endif
+}
+
+
+
+static char* new_concat(const char* a, const char* b)
+{
+ // Create new buffer
+ unsigned int size = strlen(a) + strlen(b);
+ char* new_string = (char*)malloc(size+1);
+
+ // Concatenate strings in the new buffer
+ strcpy(new_string, a);
+ strcat(new_string, b);
+
+ return new_string;
+}
+
+static char* replace_concat(char** a, const char* b)
+{
+ char* new_string = new_concat(*a, b);
+ free(*a);
+ *a = new_string;
+ return *a;
+}
+
+
+
+
+
+// Shared buffer for variadic text
+static char* fc_buffer = NULL;
+
+static Uint8 fc_has_render_target_support = 0;
+
+const char* FC_GetStringASCII(void)
+{
+ static char* buffer = NULL;
+ if(buffer == NULL)
+ {
+ int i;
+ char c;
+ buffer = (char*)malloc(512);
+ memset(buffer, 0, 512);
+ i = 0;
+ c = 32;
+ while(1)
+ {
+ buffer[i] = c;
+ if(c == 126)
+ break;
+ ++i;
+ ++c;
+ }
+ }
+ return buffer;
+}
+
+const char* FC_GetStringLatin1(void)
+{
+ static char* buffer = NULL;
+ if(buffer == NULL)
+ {
+ int i;
+ unsigned char c;
+ buffer = (char*)malloc(512);
+ memset(buffer, 0, 512);
+ i = 0;
+ c = 0xA0;
+ while(1)
+ {
+ buffer[i] = 0xC2;
+ buffer[i+1] = c;
+ if(c == 0xBF)
+ break;
+ i += 2;
+ ++c;
+ }
+ i += 2;
+ c = 0x80;
+ while(1)
+ {
+ buffer[i] = 0xC3;
+ buffer[i+1] = c;
+ if(c == 0xBF)
+ break;
+ i += 2;
+ ++c;
+ }
+ }
+ return buffer;
+}
+
+const char* FC_GetStringASCII_Latin1(void)
+{
+ static char* buffer = NULL;
+ if(buffer == NULL)
+ buffer = new_concat(FC_GetStringASCII(), FC_GetStringLatin1());
+
+ return buffer;
+}
+
+FC_Rect FC_MakeRect(float x, float y, float w, float h)
+{
+ FC_Rect r = {x, y, w, h};
+ return r;
+}
+
+FC_Scale FC_MakeScale(float x, float y)
+{
+ FC_Scale s = {x, y};
+
+ return s;
+}
+
+SDL_Color FC_MakeColor(Uint8 r, Uint8 g, Uint8 b, Uint8 a)
+{
+ SDL_Color c = {r, g, b, a};
+
+ return c;
+}
+
+FC_Effect FC_MakeEffect(FC_AlignEnum alignment, FC_Scale scale, SDL_Color color)
+{
+ FC_Effect e;
+
+ e.alignment = alignment;
+ e.scale = scale;
+ e.color = color;
+
+ return e;
+}
+
+FC_GlyphData FC_MakeGlyphData(int cache_level, Sint16 x, Sint16 y, Uint16 w, Uint16 h)
+{
+ FC_GlyphData gd;
+
+ gd.rect.x = x;
+ gd.rect.y = y;
+ gd.rect.w = w;
+ gd.rect.h = h;
+ gd.cache_level = cache_level;
+
+ return gd;
+}
+
+// Enough to hold all of the ascii characters and some.
+#define FC_DEFAULT_NUM_BUCKETS 300
+
+typedef struct FC_MapNode
+{
+ Uint32 key;
+ FC_GlyphData value;
+ struct FC_MapNode* next;
+
+} FC_MapNode;
+
+typedef struct FC_Map
+{
+ int num_buckets;
+ FC_MapNode** buckets;
+} FC_Map;
+
+
+
+static FC_Map* FC_MapCreate(int num_buckets)
+{
+ int i;
+ FC_Map* map = (FC_Map*)malloc(sizeof(FC_Map));
+
+ map->num_buckets = num_buckets;
+ map->buckets = (FC_MapNode**)malloc(num_buckets * sizeof(FC_MapNode*));
+
+ for(i = 0; i < num_buckets; ++i)
+ {
+ map->buckets[i] = NULL;
+ }
+
+ return map;
+}
+
+/*static void FC_MapClear(FC_Map* map)
+{
+ int i;
+ if(map == NULL)
+ return;
+
+ // Go through each bucket
+ for(i = 0; i < map->num_buckets; ++i)
+ {
+ // Delete the nodes in order
+ FC_MapNode* node = map->buckets[i];
+ while(node != NULL)
+ {
+ FC_MapNode* last = node;
+ node = node->next;
+ free(last);
+ }
+ // Set the bucket to empty
+ map->buckets[i] = NULL;
+ }
+}*/
+
+static void FC_MapFree(FC_Map* map)
+{
+ int i;
+ if(map == NULL)
+ return;
+
+ // Go through each bucket
+ for(i = 0; i < map->num_buckets; ++i)
+ {
+ // Delete the nodes in order
+ FC_MapNode* node = map->buckets[i];
+ while(node != NULL)
+ {
+ FC_MapNode* last = node;
+ node = node->next;
+ free(last);
+ }
+ }
+
+ free(map->buckets);
+ free(map);
+}
+
+// Note: Does not handle duplicates in any special way.
+static FC_GlyphData* FC_MapInsert(FC_Map* map, Uint32 codepoint, FC_GlyphData glyph)
+{
+ Uint32 index;
+ FC_MapNode* node;
+ if(map == NULL)
+ return NULL;
+
+ // Get index for bucket
+ index = codepoint % map->num_buckets;
+
+ // If this bucket is empty, create a node and return its value
+ if(map->buckets[index] == NULL)
+ {
+ node = map->buckets[index] = (FC_MapNode*)malloc(sizeof(FC_MapNode));
+ node->key = codepoint;
+ node->value = glyph;
+ node->next = NULL;
+ return &node->value;
+ }
+
+ for(node = map->buckets[index]; node != NULL; node = node->next)
+ {
+ // Find empty node and add a new one on.
+ if(node->next == NULL)
+ {
+ node->next = (FC_MapNode*)malloc(sizeof(FC_MapNode));
+ node = node->next;
+
+ node->key = codepoint;
+ node->value = glyph;
+ node->next = NULL;
+ return &node->value;
+ }
+ }
+
+ return NULL;
+}
+
+static FC_GlyphData* FC_MapFind(FC_Map* map, Uint32 codepoint)
+{
+ Uint32 index;
+ FC_MapNode* node;
+ if(map == NULL)
+ return NULL;
+
+ // Get index for bucket
+ index = codepoint % map->num_buckets;
+
+ // Go through list until we find a match
+ for(node = map->buckets[index]; node != NULL; node = node->next)
+ {
+ if(node->key == codepoint)
+ return &node->value;
+ }
+
+ return NULL;
+}
+
+
+
+struct FC_Font
+{
+ #ifndef FC_USE_SDL_GPU
+ SDL_Renderer* renderer;
+ #endif
+
+ TTF_Font* ttf_source; // TTF_Font source of characters
+ Uint8 owns_ttf_source; // Can we delete the TTF_Font ourselves?
+
+ FC_FilterEnum filter;
+
+ SDL_Color default_color;
+ Uint16 height;
+
+ Uint16 maxWidth;
+ Uint16 baseline;
+ int ascent;
+ int descent;
+
+ int lineSpacing;
+ int letterSpacing;
+
+ // Uses 32-bit (4-byte) Unicode codepoints to refer to each glyph
+ // Codepoints are little endian (reversed from UTF-8) so that something like 0x00000005 is ASCII 5 and the map can be indexed by ASCII values
+ FC_Map* glyphs;
+
+ FC_GlyphData last_glyph; // Texture packing cursor
+ int glyph_cache_size;
+ int glyph_cache_count;
+ FC_Image** glyph_cache;
+
+ char* loading_string;
+
+};
+
+// Private
+static FC_GlyphData* FC_PackGlyphData(FC_Font* font, Uint32 codepoint, Uint16 width, Uint16 maxWidth, Uint16 maxHeight);
+
+
+static FC_Rect FC_RenderLeft(FC_Font* font, FC_Target* dest, float x, float y, FC_Scale scale, const char* text);
+static FC_Rect FC_RenderCenter(FC_Font* font, FC_Target* dest, float x, float y, FC_Scale scale, const char* text);
+static FC_Rect FC_RenderRight(FC_Font* font, FC_Target* dest, float x, float y, FC_Scale scale, const char* text);
+
+
+static_inline SDL_Surface* FC_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
+}
+
+
+char* U8_alloc(unsigned int size)
+{
+ char* result;
+ if(size == 0)
+ return NULL;
+
+ result = (char*)malloc(size);
+ result[0] = '\0';
+
+ return result;
+}
+
+void U8_free(char* string)
+{
+ free(string);
+}
+
+char* U8_strdup(const char* string)
+{
+ char* result;
+ if(string == NULL)
+ return NULL;
+
+ result = (char*)malloc(strlen(string)+1);
+ strcpy(result, string);
+
+ return result;
+}
+
+int U8_strlen(const char* string)
+{
+ int length = 0;
+ if(string == NULL)
+ return 0;
+
+ while(*string != '\0')
+ {
+ string = U8_next(string);
+ ++length;
+ }
+
+ return length;
+}
+
+int U8_charsize(const char* character)
+{
+ if(character == NULL)
+ return 0;
+
+ if((unsigned char)*character <= 0x7F)
+ return 1;
+ else if((unsigned char)*character < 0xE0)
+ return 2;
+ else if((unsigned char)*character < 0xF0)
+ return 3;
+ else
+ return 4;
+ return 1;
+}
+
+int U8_charcpy(char* buffer, const char* source, int buffer_size)
+{
+ int charsize;
+ if(buffer == NULL || source == NULL || buffer_size < 1)
+ return 0;
+
+ charsize = U8_charsize(source);
+ if(charsize > buffer_size)
+ return 0;
+
+ memcpy(buffer, source, charsize);
+ return charsize;
+}
+
+const char* U8_next(const char* string)
+{
+ return string + U8_charsize(string);
+}
+
+int U8_strinsert(char* string, int position, const char* source, int max_bytes)
+{
+ int pos_bytes;
+ int len = strlen(string);
+ int add_len = strlen(source);
+ int ulen = U8_strlen(string);
+
+ if(position == -1)
+ position = ulen;
+
+ if(string == NULL || source == NULL || position < 0 || position > ulen || len + add_len + 1 > max_bytes)
+ return 0;
+
+ // Move string pointer to the proper position
+ pos_bytes = 0;
+ while(*string != '\0' && pos_bytes < position)
+ {
+ string = (char*)U8_next(string);
+ ++pos_bytes;
+ }
+
+ // Move the rest of the string out of the way
+ memmove(string + add_len, string, len - pos_bytes + 1);
+
+ // Copy in the new characters
+ memcpy(string, source, add_len);
+
+ return 1;
+}
+
+void U8_strdel(char* string, int position)
+{
+ if(string == NULL || position < 0)
+ return;
+
+ while(*string != '\0')
+ {
+ if(position == 0)
+ {
+ int chars_to_erase = U8_charsize(string);
+ int remaining_bytes = strlen(string) + 1;
+ memmove(string, string + chars_to_erase, remaining_bytes);
+ break;
+ }
+
+ string = (char*)U8_next(string);
+ --position;
+ }
+}
+
+
+
+
+
+static_inline FC_Rect FC_RectUnion(FC_Rect A, FC_Rect B)
+{
+ float x,x2,y,y2;
+ x = FC_MIN(A.x, B.x);
+ y = FC_MIN(A.y, B.y);
+ x2 = FC_MAX(A.x+A.w, B.x+B.w);
+ y2 = FC_MAX(A.y+A.h, B.y+B.h);
+ {
+ FC_Rect result = {x, y, FC_MAX(0, x2 - x), FC_MAX(0, y2 - y)};
+ return result;
+ }
+}
+
+// Adapted from SDL_IntersectRect
+static_inline FC_Rect FC_RectIntersect(FC_Rect A, FC_Rect B)
+{
+ FC_Rect 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;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+FC_Rect FC_DefaultRenderCallback(FC_Image* src, FC_Rect* srcrect, FC_Target* dest, float x, float y, float xscale, float yscale)
+{
+ float w = srcrect->w * xscale;
+ float h = srcrect->h * yscale;
+ FC_Rect result;
+
+ // FIXME: Why does the scaled offset look so wrong?
+ #ifdef FC_USE_SDL_GPU
+ {
+ GPU_Rect r = *srcrect;
+ GPU_BlitScale(src, &r, dest, x + xscale*r.w/2.0f, y + r.h/2.0f, xscale, yscale);
+ }
+ #else
+ {
+ SDL_RendererFlip flip = SDL_FLIP_NONE;
+ if(xscale < 0)
+ {
+ xscale = -xscale;
+ flip = flip | SDL_FLIP_HORIZONTAL;
+ }
+ if(yscale < 0)
+ {
+ yscale = -yscale;
+ flip = flip | SDL_FLIP_VERTICAL;
+ }
+
+ SDL_Rect r = *srcrect;
+ SDL_Rect dr = {(int)x, (int)y, (int)(xscale*r.w), (int)(yscale*r.h)};
+ SDL_RenderCopyEx(dest, src, &r, &dr, 0, NULL, flip);
+ }
+ #endif
+
+ result.x = x;
+ result.y = y;
+ result.w = w;
+ result.h = h;
+ return result;
+}
+
+static FC_Rect (*fc_render_callback)(FC_Image* src, FC_Rect* srcrect, FC_Target* dest, float x, float y, float xscale, float yscale) = &FC_DefaultRenderCallback;
+
+void FC_SetRenderCallback(FC_Rect (*callback)(FC_Image* src, FC_Rect* srcrect, FC_Target* dest, float x, float y, float xscale, float yscale))
+{
+ if(callback == NULL)
+ fc_render_callback = &FC_DefaultRenderCallback;
+ else
+ fc_render_callback = callback;
+}
+
+void FC_GetUTF8FromCodepoint(char* result, Uint32 codepoint)
+{
+ char a, b, c, d;
+
+ if(result == NULL)
+ return;
+
+ a = (codepoint >> 24) & 0xFF;
+ b = (codepoint >> 16) & 0xFF;
+ c = (codepoint >> 8) & 0xFF;
+ d = codepoint & 0xFF;
+
+ if(a == 0)
+ {
+ if(b == 0)
+ {
+ if(c == 0)
+ {
+ result[0] = d;
+ result[1] = '\0';
+ }
+ else
+ {
+ result[0] = c;
+ result[1] = d;
+ result[2] = '\0';
+ }
+ }
+ else
+ {
+ result[0] = b;
+ result[1] = c;
+ result[2] = d;
+ result[3] = '\0';
+ }
+ }
+ else
+ {
+ result[0] = a;
+ result[1] = b;
+ result[2] = c;
+ result[3] = d;
+ result[4] = '\0';
+ }
+}
+
+Uint32 FC_GetCodepointFromUTF8(const char** c, Uint8 advance_pointer)
+{
+ Uint32 result = 0;
+ const char* str;
+ if(c == NULL || *c == NULL)
+ return 0;
+
+ str = *c;
+ if((unsigned char)*str <= 0x7F)
+ result = *str;
+ else if((unsigned char)*str < 0xE0)
+ {
+ result |= (unsigned char)(*str) << 8;
+ result |= (unsigned char)(*(str+1));
+ if(advance_pointer)
+ *c += 1;
+ }
+ else if((unsigned char)*str < 0xF0)
+ {
+ result |= (unsigned char)(*str) << 16;
+ result |= (unsigned char)(*(str+1)) << 8;
+ result |= (unsigned char)(*(str+2));
+ if(advance_pointer)
+ *c += 2;
+ }
+ else
+ {
+ result |= (unsigned char)(*str) << 24;
+ result |= (unsigned char)(*(str+1)) << 16;
+ result |= (unsigned char)(*(str+2)) << 8;
+ result |= (unsigned char)(*(str+3));
+ if(advance_pointer)
+ *c += 3;
+ }
+ return result;
+}
+
+
+void FC_SetLoadingString(FC_Font* font, const char* string)
+{
+ if(font == NULL)
+ return;
+
+ free(font->loading_string);
+ font->loading_string = U8_strdup(string);
+}
+
+
+void FC_SetBufferSize(unsigned int size)
+{
+ free(fc_buffer);
+ if(size > 0)
+ fc_buffer = (char*)malloc(size);
+ else
+ fc_buffer = (char*)malloc(1024);
+}
+
+
+
+
+
+// Constructors
+
+static void FC_Init(FC_Font* font)
+{
+ if(font == NULL)
+ return;
+
+ #ifndef FC_USE_SDL_GPU
+ font->renderer = NULL;
+ #endif
+
+ font->ttf_source = NULL;
+ font->owns_ttf_source = 0;
+
+ font->filter = FC_FILTER_NEAREST;
+
+ font->default_color.r = 0;
+ font->default_color.g = 0;
+ font->default_color.b = 0;
+ FC_GET_ALPHA(font->default_color) = 255;
+
+ font->height = 0; // ascent+descent
+
+ font->maxWidth = 0;
+ font->baseline = 0;
+ font->ascent = 0;
+ font->descent = 0;
+
+ font->lineSpacing = 0;
+ font->letterSpacing = 0;
+
+ // Give a little offset for when filtering/mipmaps are used. Depending on mipmap level, this will still not be enough.
+ font->last_glyph.rect.x = FC_CACHE_PADDING;
+ font->last_glyph.rect.y = FC_CACHE_PADDING;
+ font->last_glyph.rect.w = 0;
+ font->last_glyph.rect.h = 0;
+ font->last_glyph.cache_level = 0;
+
+ if(font->glyphs != NULL)
+ FC_MapFree(font->glyphs);
+
+ font->glyphs = FC_MapCreate(FC_DEFAULT_NUM_BUCKETS);
+
+ font->glyph_cache_size = 3;
+ font->glyph_cache_count = 0;
+
+
+ font->glyph_cache = (FC_Image**)malloc(font->glyph_cache_size * sizeof(FC_Image*));
+
+ if(font->loading_string == NULL)
+ font->loading_string = U8_strdup(FC_GetStringASCII());
+
+ if(fc_buffer == NULL)
+ fc_buffer = (char*)malloc(1024);
+}
+
+static Uint8 FC_GrowGlyphCache(FC_Font* font)
+{
+ if(font == NULL)
+ return 0;
+ #ifdef FC_USE_SDL_GPU
+ GPU_Image* new_level = GPU_CreateImage(font->height * 12, font->height * 12, GPU_FORMAT_RGBA);
+ #else
+ SDL_Texture* new_level = SDL_CreateTexture(font->renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, font->height * 12, font->height * 12);
+ #endif
+ if(new_level == NULL || !FC_SetGlyphCacheLevel(font, font->glyph_cache_count, new_level))
+ {
+ FC_Log("Error: SDL_FontCache ran out of packing space and could not add another cache level.\n");
+ #ifdef FC_USE_SDL_GPU
+ GPU_FreeImage(new_level);
+ #else
+ SDL_DestroyTexture(new_level);
+ #endif
+ return 0;
+ }
+ return 1;
+}
+
+static Uint8 FC_UploadGlyphCache(FC_Font* font, int cache_level, SDL_Surface* data_surface)
+{
+ if(font == NULL || data_surface == NULL)
+ return 0;
+ #ifdef FC_USE_SDL_GPU
+ GPU_Image* new_level = GPU_CopyImageFromSurface(data_surface);
+ if(FC_GetFilterMode(font) == FC_FILTER_LINEAR)
+ GPU_SetImageFilter(new_level, GPU_FILTER_LINEAR);
+ else
+ GPU_SetImageFilter(new_level, GPU_FILTER_NEAREST);
+ #else
+ SDL_Texture* new_level;
+ if(!fc_has_render_target_support)
+ new_level = SDL_CreateTextureFromSurface(font->renderer, data_surface);
+ else
+ {
+ // Must upload with render target enabled so we can put more glyphs on later
+ SDL_Renderer* renderer = font->renderer;
+
+ // Set filter mode for new texture
+ const char* old_filter_mode = SDL_GetHint(SDL_HINT_RENDER_SCALE_QUALITY);
+ if(FC_GetFilterMode(font) == FC_FILTER_LINEAR)
+ SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "1");
+ else
+ SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0");
+
+ new_level = SDL_CreateTexture(renderer, data_surface->format->format, SDL_TEXTUREACCESS_TARGET, data_surface->w, data_surface->h);
+ SDL_SetTextureBlendMode(new_level, SDL_BLENDMODE_BLEND);
+
+ // Reset filter mode for the temp texture
+ SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "0");
+
+ {
+ Uint8 r, g, b, a;
+ SDL_Texture* temp = SDL_CreateTextureFromSurface(renderer, data_surface);
+ SDL_SetTextureBlendMode(temp, SDL_BLENDMODE_NONE);
+ SDL_SetRenderTarget(renderer, new_level);
+
+ SDL_GetRenderDrawColor(renderer, &r, &g, &b, &a);
+ SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0);
+ SDL_RenderClear(renderer);
+ SDL_SetRenderDrawColor(renderer, r, g, b, a);
+
+ SDL_RenderCopy(renderer, temp, NULL, NULL);
+ SDL_SetRenderTarget(renderer, NULL);
+
+ SDL_DestroyTexture(temp);
+ }
+
+ // Reset to the old filter value
+ SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, old_filter_mode);
+
+ }
+ #endif
+ if(new_level == NULL || !FC_SetGlyphCacheLevel(font, cache_level, new_level))
+ {
+ FC_Log("Error: SDL_FontCache ran out of packing space and could not add another cache level.\n");
+ #ifdef FC_USE_SDL_GPU
+ GPU_FreeImage(new_level);
+ #else
+ SDL_DestroyTexture(new_level);
+ #endif
+ return 0;
+ }
+ return 1;
+}
+
+static FC_GlyphData* FC_PackGlyphData(FC_Font* font, Uint32 codepoint, Uint16 width, Uint16 maxWidth, Uint16 maxHeight)
+{
+ FC_Map* glyphs = font->glyphs;
+ FC_GlyphData* last_glyph = &font->last_glyph;
+ Uint16 height = font->height + FC_CACHE_PADDING;
+
+ if(last_glyph->rect.x + last_glyph->rect.w + width >= maxWidth - FC_CACHE_PADDING)
+ {
+ if(last_glyph->rect.y + height + height >= maxHeight - FC_CACHE_PADDING)
+ {
+ // Get ready to pack on the next cache level when it is ready
+ last_glyph->cache_level = font->glyph_cache_count;
+ last_glyph->rect.x = FC_CACHE_PADDING;
+ last_glyph->rect.y = FC_CACHE_PADDING;
+ last_glyph->rect.w = 0;
+ return NULL;
+ }
+ else
+ {
+ // Go to next row
+ last_glyph->rect.x = FC_CACHE_PADDING;
+ last_glyph->rect.y += height;
+ last_glyph->rect.w = 0;
+ }
+ }
+
+ // Move to next space
+ last_glyph->rect.x += last_glyph->rect.w + 1 + FC_CACHE_PADDING;
+ last_glyph->rect.w = width;
+
+ return FC_MapInsert(glyphs, codepoint, FC_MakeGlyphData(last_glyph->cache_level, last_glyph->rect.x, last_glyph->rect.y, last_glyph->rect.w, last_glyph->rect.h));
+}
+
+
+FC_Image* FC_GetGlyphCacheLevel(FC_Font* font, int cache_level)
+{
+ if(font == NULL || cache_level < 0 || cache_level > font->glyph_cache_count)
+ return NULL;
+
+ return font->glyph_cache[cache_level];
+}
+
+Uint8 FC_SetGlyphCacheLevel(FC_Font* font, int cache_level, FC_Image* cache_texture)
+{
+ if(font == NULL || cache_level < 0)
+ return 0;
+
+ // Must be sequentially added
+ if(cache_level > font->glyph_cache_count + 1)
+ return 0;
+
+ if(cache_level == font->glyph_cache_count)
+ {
+ font->glyph_cache_count++;
+
+ // Grow cache?
+ if(font->glyph_cache_count > font->glyph_cache_size)
+ {
+ // Copy old cache to new one
+ int i;
+ FC_Image** new_cache;
+ new_cache = (FC_Image**)malloc(font->glyph_cache_count * sizeof(FC_Image*));
+ for(i = 0; i < font->glyph_cache_size; ++i)
+ new_cache[i] = font->glyph_cache[i];
+
+ // Save new cache
+ free(font->glyph_cache);
+ font->glyph_cache_size = font->glyph_cache_count;
+ font->glyph_cache = new_cache;
+ }
+ }
+
+ font->glyph_cache[cache_level] = cache_texture;
+ return 1;
+}
+
+
+FC_Font* FC_CreateFont(void)
+{
+ FC_Font* font;
+
+ font = (FC_Font*)malloc(sizeof(FC_Font));
+ memset(font, 0, sizeof(FC_Font));
+
+ FC_Init(font);
+
+ return font;
+}
+
+
+// Assume this many will be enough...
+#define FC_LOAD_MAX_SURFACES 10
+
+#ifdef FC_USE_SDL_GPU
+Uint8 FC_LoadFontFromTTF(FC_Font* font, TTF_Font* ttf, SDL_Color color)
+#else
+Uint8 FC_LoadFontFromTTF(FC_Font* font, SDL_Renderer* renderer, TTF_Font* ttf, SDL_Color color)
+#endif
+{
+ if(font == NULL || ttf == NULL)
+ return 0;
+ #ifndef FC_USE_SDL_GPU
+ if(renderer == NULL)
+ return 0;
+ #endif
+
+ FC_ClearFont(font);
+
+
+ // Might as well check render target support here
+ #ifdef FC_USE_SDL_GPU
+ fc_has_render_target_support = GPU_IsFeatureEnabled(GPU_FEATURE_RENDER_TARGETS);
+ #else
+ SDL_RendererInfo info;
+ SDL_GetRendererInfo(renderer, &info);
+ fc_has_render_target_support = (info.flags & SDL_RENDERER_TARGETTEXTURE);
+
+ font->renderer = renderer;
+ #endif
+
+ font->ttf_source = ttf;
+
+ //font->line_height = TTF_FontLineSkip(ttf);
+ font->height = TTF_FontHeight(ttf);
+ font->ascent = TTF_FontAscent(ttf);
+ font->descent = -TTF_FontDescent(ttf);
+
+ font->baseline = font->height - font->descent;
+
+ font->default_color = color;
+
+ {
+ SDL_Color white = {255, 255, 255, 255};
+ SDL_Surface* glyph_surf;
+ char buff[5];
+ const char* buff_ptr = buff;
+ const char* source_string;
+ Uint8 packed = 0;
+
+ // Copy glyphs from the surface to the font texture and store the position data
+ // Pack row by row into a square texture
+ // Try figuring out dimensions that make sense for the font size.
+ unsigned int w = font->height*12;
+ unsigned int h = font->height*12;
+ SDL_Surface* surfaces[FC_LOAD_MAX_SURFACES];
+ int num_surfaces = 1;
+ surfaces[0] = FC_CreateSurface32(w, h);
+ font->last_glyph.rect.x = FC_CACHE_PADDING;
+ font->last_glyph.rect.y = FC_CACHE_PADDING;
+ font->last_glyph.rect.w = 0;
+ font->last_glyph.rect.h = font->height;
+
+ memset(buff, 0, 5);
+ source_string = font->loading_string;
+ for(; *source_string != '\0'; source_string = U8_next(source_string))
+ {
+ if(!U8_charcpy(buff, source_string, 5))
+ continue;
+ glyph_surf = TTF_RenderUTF8_Blended(ttf, buff, white);
+ if(glyph_surf == NULL)
+ continue;
+
+ // Try packing. If it fails, create a new surface for the next cache level.
+ packed = (FC_PackGlyphData(font, FC_GetCodepointFromUTF8(&buff_ptr, 0), glyph_surf->w, surfaces[num_surfaces-1]->w, surfaces[num_surfaces-1]->h) != NULL);
+ if(!packed)
+ {
+ int i = num_surfaces-1;
+ if(num_surfaces >= FC_LOAD_MAX_SURFACES)
+ {
+ // Can't do any more!
+ FC_Log("SDL_FontCache error: Could not create enough cache surfaces to fit all of the loading string!\n");
+ SDL_FreeSurface(glyph_surf);
+ break;
+ }
+
+ // Upload the current surface to the glyph cache now so we can keep the cache level packing cursor up to date as we go.
+ FC_UploadGlyphCache(font, i, surfaces[i]);
+ SDL_FreeSurface(surfaces[i]);
+ #ifndef FC_USE_SDL_GPU
+ SDL_SetTextureBlendMode(font->glyph_cache[i], SDL_BLENDMODE_BLEND);
+ #endif
+ // Update the glyph cursor to the new cache level. We need to do this here because the actual cache lags behind our use of the packing above.
+ font->last_glyph.cache_level = num_surfaces;
+
+
+ surfaces[num_surfaces] = FC_CreateSurface32(w, h);
+ num_surfaces++;
+ }
+
+ // Try packing for the new surface, then blit onto it.
+ if(packed || FC_PackGlyphData(font, FC_GetCodepointFromUTF8(&buff_ptr, 0), glyph_surf->w, surfaces[num_surfaces-1]->w, surfaces[num_surfaces-1]->h) != NULL)
+ {
+ SDL_SetSurfaceBlendMode(glyph_surf, SDL_BLENDMODE_NONE);
+ SDL_Rect srcRect = {0, 0, glyph_surf->w, glyph_surf->h};
+ SDL_Rect destrect = font->last_glyph.rect;
+ SDL_BlitSurface(glyph_surf, &srcRect, surfaces[num_surfaces-1], &destrect);
+ }
+
+ SDL_FreeSurface(glyph_surf);
+ }
+
+ {
+ int i = num_surfaces-1;
+ FC_UploadGlyphCache(font, i, surfaces[i]);
+ SDL_FreeSurface(surfaces[i]);
+ #ifndef FC_USE_SDL_GPU
+ SDL_SetTextureBlendMode(font->glyph_cache[i], SDL_BLENDMODE_BLEND);
+ #endif
+ }
+ }
+
+ return 1;
+}
+
+
+#ifdef FC_USE_SDL_GPU
+Uint8 FC_LoadFont(FC_Font* font, const char* filename_ttf, Uint32 pointSize, SDL_Color color, int style)
+#else
+Uint8 FC_LoadFont(FC_Font* font, FC_Target* renderer, const char* filename_ttf, Uint32 pointSize, SDL_Color color, int style)
+#endif
+{
+ SDL_RWops* rwops;
+
+ if(font == NULL)
+ return 0;
+
+ rwops = SDL_RWFromFile(filename_ttf, "rb");
+
+ if(rwops == NULL)
+ {
+ FC_Log("Unable to open file for reading: %s \n", SDL_GetError());
+ return 0;
+ }
+
+ #ifdef FC_USE_SDL_GPU
+ return FC_LoadFont_RW(font, rwops, 1, pointSize, color, style);
+ #else
+ return FC_LoadFont_RW(font, renderer, rwops, 1, pointSize, color, style);
+ #endif
+}
+
+#ifdef FC_USE_SDL_GPU
+Uint8 FC_LoadFont_RW(FC_Font* font, SDL_RWops* file_rwops_ttf, Uint8 own_rwops, Uint32 pointSize, SDL_Color color, int style)
+#else
+Uint8 FC_LoadFont_RW(FC_Font* font, FC_Target* renderer, SDL_RWops* file_rwops_ttf, Uint8 own_rwops, Uint32 pointSize, SDL_Color color, int style)
+#endif
+{
+ Uint8 result;
+ TTF_Font* ttf;
+ Uint8 outline;
+
+ if(font == NULL)
+ return 0;
+
+ if(!TTF_WasInit() && TTF_Init() < 0)
+ {
+ FC_Log("Unable to initialize SDL_ttf: %s \n", TTF_GetError());
+ if(own_rwops)
+ SDL_RWclose(file_rwops_ttf);
+ return 0;
+ }
+
+ ttf = TTF_OpenFontRW(file_rwops_ttf, own_rwops, pointSize);
+
+ if(ttf == NULL)
+ {
+ FC_Log("Unable to load TrueType font: %s \n", TTF_GetError());
+ if(own_rwops)
+ SDL_RWclose(file_rwops_ttf);
+ return 0;
+ }
+
+ outline = (style & TTF_STYLE_OUTLINE);
+ if(outline)
+ {
+ style &= ~TTF_STYLE_OUTLINE;
+ TTF_SetFontOutline(ttf, 1);
+ }
+ TTF_SetFontStyle(ttf, style);
+
+ #ifdef FC_USE_SDL_GPU
+ result = FC_LoadFontFromTTF(font, ttf, color);
+ #else
+ result = FC_LoadFontFromTTF(font, renderer, ttf, color);
+ #endif
+
+ // Can only load new (uncached) glyphs if we can keep the SDL_RWops open.
+ font->owns_ttf_source = own_rwops;
+ if(!own_rwops)
+ {
+ TTF_CloseFont(font->ttf_source);
+ font->ttf_source = NULL;
+ }
+
+ return result;
+}
+
+
+void FC_ClearFont(FC_Font* font)
+{
+ int i;
+ if(font == NULL)
+ return;
+
+ // Release resources
+ if(font->owns_ttf_source)
+ TTF_CloseFont(font->ttf_source);
+
+ font->owns_ttf_source = 0;
+ font->ttf_source = NULL;
+
+ // Delete glyph map
+ FC_MapFree(font->glyphs);
+ font->glyphs = NULL;
+
+ // Delete glyph cache
+ for(i = 0; i < font->glyph_cache_count; ++i)
+ {
+ #ifdef FC_USE_SDL_GPU
+ GPU_FreeImage(font->glyph_cache[i]);
+ #else
+ SDL_DestroyTexture(font->glyph_cache[i]);
+ #endif
+ }
+ free(font->glyph_cache);
+ font->glyph_cache = NULL;
+
+ // Reset font
+ FC_Init(font);
+}
+
+
+void FC_FreeFont(FC_Font* font)
+{
+ int i;
+ if(font == NULL)
+ return;
+
+ // Release resources
+ if(font->owns_ttf_source)
+ TTF_CloseFont(font->ttf_source);
+
+ // Delete glyph map
+ FC_MapFree(font->glyphs);
+
+ // Delete glyph cache
+ for(i = 0; i < font->glyph_cache_count; ++i)
+ {
+ #ifdef FC_USE_SDL_GPU
+ GPU_FreeImage(font->glyph_cache[i]);
+ #else
+ SDL_DestroyTexture(font->glyph_cache[i]);
+ #endif
+ }
+ free(font->glyph_cache);
+
+ free(font->loading_string);
+
+ free(font);
+}
+
+int FC_GetNumCacheLevels(FC_Font* font)
+{
+ return font->glyph_cache_count;
+}
+
+Uint8 FC_AddGlyphToCache(FC_Font* font, SDL_Surface* glyph_surface)
+{
+ if(font == NULL || glyph_surface == NULL)
+ return 0;
+
+ SDL_SetSurfaceBlendMode(glyph_surface, SDL_BLENDMODE_NONE);
+ FC_Image* dest = FC_GetGlyphCacheLevel(font, font->last_glyph.cache_level);
+ if(dest == NULL)
+ return 0;
+
+ #ifdef FC_USE_SDL_GPU
+ {
+ GPU_Target* target = GPU_LoadTarget(dest);
+ if(target == NULL)
+ return 0;
+ GPU_Image* img = GPU_CopyImageFromSurface(glyph_surface);
+ GPU_SetImageFilter(img, GPU_FILTER_NEAREST);
+ GPU_SetBlendMode(img, GPU_BLEND_SET);
+
+ SDL_Rect destrect = font->last_glyph.rect;
+ GPU_Blit(img, NULL, target, destrect.x + destrect.w/2, destrect.y + destrect.h/2);
+
+ GPU_FreeImage(img);
+ GPU_FreeTarget(target);
+ }
+ #else
+ {
+ SDL_Texture* img = SDL_CreateTextureFromSurface(font->renderer, glyph_surface);
+
+ SDL_Rect destrect = font->last_glyph.rect;
+ SDL_SetRenderTarget(font->renderer, dest);
+ SDL_RenderCopy(font->renderer, img, NULL, &destrect);
+ SDL_SetRenderTarget(font->renderer, NULL);
+ SDL_DestroyTexture(img);
+ }
+ #endif
+
+ return 1;
+}
+
+Uint8 FC_GetGlyphData(FC_Font* font, FC_GlyphData* result, Uint32 codepoint)
+{
+ FC_GlyphData* e = FC_MapFind(font->glyphs, codepoint);
+ if(e == NULL || result == NULL)
+ {
+ char buff[5];
+ int w, h;
+ SDL_Color white = {255, 255, 255, 255};
+ SDL_Surface* surf;
+ FC_Image* cache_image;
+
+ if(font->ttf_source == NULL)
+ return 0;
+
+ FC_GetUTF8FromCodepoint(buff, codepoint);
+
+ cache_image = FC_GetGlyphCacheLevel(font, font->last_glyph.cache_level);
+ if(cache_image == NULL)
+ {
+ FC_Log("SDL_FontCache: Failed to load cache image, so cannot add new glyphs!\n");
+ return 0;
+ }
+ #ifdef FC_USE_SDL_GPU
+ w = cache_image->w;
+ h = cache_image->h;
+ #else
+ SDL_QueryTexture(cache_image, NULL, NULL, &w, &h);
+ #endif
+
+ surf = TTF_RenderUTF8_Blended(font->ttf_source, buff, white);
+ if(surf == NULL)
+ {
+ return 0;
+ }
+
+ e = FC_PackGlyphData(font, codepoint, surf->w, w, h);
+ if(e == NULL)
+ {
+ // Grow the cache
+ FC_GrowGlyphCache(font);
+
+ // Try packing again
+ e = FC_PackGlyphData(font, codepoint, surf->w, w, h);
+ if(e == NULL)
+ {
+ SDL_FreeSurface(surf);
+ return 0;
+ }
+ }
+
+ // Render onto the cache texture
+ FC_AddGlyphToCache(font, surf);
+
+ SDL_FreeSurface(surf);
+ }
+
+ if(result != NULL && e != NULL)
+ *result = *e;
+
+ return 1;
+}
+
+
+FC_GlyphData* FC_SetGlyphData(FC_Font* font, Uint32 codepoint, FC_GlyphData glyph_data)
+{
+ return FC_MapInsert(font->glyphs, codepoint, glyph_data);
+}
+
+
+// Drawing
+static FC_Rect FC_RenderLeft(FC_Font* font, FC_Target* dest, float x, float y, FC_Scale scale, const char* text)
+{
+ const char* c = text;
+ FC_Rect srcRect;
+ FC_Rect dstRect;
+ FC_Rect dirtyRect = FC_MakeRect(x, y, 0, 0);
+
+ FC_GlyphData glyph;
+ Uint32 codepoint;
+
+ float destX = x;
+ float destY = y;
+ float destH;
+ float destLineSpacing;
+ float destLetterSpacing;
+
+ if(font == NULL)
+ return dirtyRect;
+
+ destH = font->height * scale.y;
+ destLineSpacing = font->lineSpacing*scale.y;
+ destLetterSpacing = font->letterSpacing*scale.x;
+
+ if(c == NULL || font->glyph_cache_count == 0 || dest == NULL)
+ return dirtyRect;
+
+ int newlineX = x;
+
+ for(; *c != '\0'; c++)
+ {
+ if(*c == '\n')
+ {
+ destX = newlineX;
+ destY += destH + destLineSpacing;
+ continue;
+ }
+
+ codepoint = FC_GetCodepointFromUTF8(&c, 1); // Increments 'c' to skip the extra UTF-8 bytes
+ if(!FC_GetGlyphData(font, &glyph, codepoint))
+ {
+ codepoint = ' ';
+ if(!FC_GetGlyphData(font, &glyph, codepoint))
+ continue; // Skip bad characters
+ }
+
+ if (codepoint == ' ')
+ {
+ destX += glyph.rect.w*scale.x + destLetterSpacing;
+ continue;
+ }
+ /*if(destX >= dest->w)
+ continue;
+ if(destY >= dest->h)
+ continue;*/
+
+ #ifdef FC_USE_SDL_GPU
+ srcRect.x = glyph.rect.x;
+ srcRect.y = glyph.rect.y;
+ srcRect.w = glyph.rect.w;
+ srcRect.h = glyph.rect.h;
+ #else
+ srcRect = glyph.rect;
+ #endif
+ dstRect = fc_render_callback(FC_GetGlyphCacheLevel(font, glyph.cache_level), &srcRect, dest, destX, destY, scale.x, scale.y);
+ if(dirtyRect.w == 0 || dirtyRect.h == 0)
+ dirtyRect = dstRect;
+ else
+ dirtyRect = FC_RectUnion(dirtyRect, dstRect);
+
+ destX += glyph.rect.w*scale.x + destLetterSpacing;
+ }
+
+ return dirtyRect;
+}
+
+static void set_color_for_all_caches(FC_Font* font, SDL_Color color)
+{
+ // TODO: How can I predict which glyph caches are to be used?
+ FC_Image* img;
+ int i;
+ int num_levels = FC_GetNumCacheLevels(font);
+ for(i = 0; i < num_levels; ++i)
+ {
+ img = FC_GetGlyphCacheLevel(font, i);
+ set_color(img, color.r, color.g, color.b, FC_GET_ALPHA(color));
+ }
+}
+
+FC_Rect FC_Draw(FC_Font* font, FC_Target* dest, float x, float y, const char* formatted_text, ...)
+{
+ if(formatted_text == NULL || font == NULL)
+ return FC_MakeRect(x, y, 0, 0);
+
+ FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
+
+ set_color_for_all_caches(font, font->default_color);
+
+ return FC_RenderLeft(font, dest, x, y, FC_MakeScale(1,1), fc_buffer);
+}
+
+
+
+typedef struct FC_StringList
+{
+ char* value;
+ struct FC_StringList* next;
+} FC_StringList;
+
+void FC_StringListFree(FC_StringList* node)
+{
+ // Delete the nodes in order
+ while(node != NULL)
+ {
+ FC_StringList* last = node;
+ node = node->next;
+
+ free(last->value);
+ free(last);
+ }
+}
+
+FC_StringList** FC_StringListPushBack(FC_StringList** node, char* value, Uint8 copy)
+{
+ // Get to the last node
+ while(node != NULL && *node != NULL)
+ {
+ node = &(*node)->next;
+ }
+
+ *node = (FC_StringList*)malloc(sizeof(FC_StringList));
+
+ (*node)->value = (copy? U8_strdup(value) : value);
+ (*node)->next = NULL;
+
+ return node;
+}
+
+static FC_StringList* FC_Explode(const char* text, char delimiter)
+{
+ FC_StringList* head;
+ FC_StringList* new_node;
+ FC_StringList** node;
+ const char* start;
+ const char* end;
+ unsigned int size;
+ if(text == NULL)
+ return NULL;
+
+ head = NULL;
+ node = &head;
+
+ // Doesn't technically support UTF-8, but it's probably fine, right?
+ size = 0;
+ start = end = text;
+ while(1)
+ {
+ if(*end == delimiter || *end == '\0')
+ {
+ *node = (FC_StringList*)malloc(sizeof(FC_StringList));
+ new_node = *node;
+
+ new_node->value = (char*)malloc(size + 1);
+ memcpy(new_node->value, start, size);
+ new_node->value[size] = '\0';
+
+ new_node->next = NULL;
+
+ if(*end == '\0')
+ break;
+
+ node = &((*node)->next);
+ start = end+1;
+ size = 0;
+ }
+ else
+ ++size;
+
+ ++end;
+ }
+
+ return head;
+}
+
+static FC_StringList* FC_ExplodeAndKeep(const char* text, char delimiter)
+{
+ FC_StringList* head;
+ FC_StringList* new_node;
+ FC_StringList** node;
+ const char* start;
+ const char* end;
+ unsigned int size;
+ if(text == NULL)
+ return NULL;
+
+ head = NULL;
+ node = &head;
+
+ // Doesn't technically support UTF-8, but it's probably fine, right?
+ size = 0;
+ start = end = text;
+ while(1)
+ {
+ if(*end == delimiter || *end == '\0')
+ {
+ *node = (FC_StringList*)malloc(sizeof(FC_StringList));
+ new_node = *node;
+
+ new_node->value = (char*)malloc(size + 1);
+ memcpy(new_node->value, start, size);
+ new_node->value[size] = '\0';
+
+ new_node->next = NULL;
+
+ if(*end == '\0')
+ break;
+
+ node = &((*node)->next);
+ start = end;
+ size = 1;
+ }
+ else
+ ++size;
+
+ ++end;
+ }
+
+ return head;
+}
+
+static void FC_RenderAlign(FC_Font* font, FC_Target* dest, float x, float y, int width, FC_Scale scale, FC_AlignEnum align, const char* text)
+{
+ switch(align)
+ {
+ case FC_ALIGN_LEFT:
+ FC_RenderLeft(font, dest, x, y, scale, text);
+ break;
+ case FC_ALIGN_CENTER:
+ FC_RenderCenter(font, dest, x + width/2, y, scale, text);
+ break;
+ case FC_ALIGN_RIGHT:
+ FC_RenderRight(font, dest, x + width, y, scale, text);
+ break;
+ }
+}
+
+static FC_StringList* FC_GetBufferFitToColumn(FC_Font* font, int width, FC_Scale scale, Uint8 keep_newlines)
+{
+ FC_StringList* result = NULL;
+ FC_StringList** current = &result;
+
+ FC_StringList *ls, *iter;
+
+ ls = (keep_newlines? FC_ExplodeAndKeep(fc_buffer, '\n') : FC_Explode(fc_buffer, '\n'));
+ for(iter = ls; iter != NULL; iter = iter->next)
+ {
+ char* line = iter->value;
+
+ // If line is too long, then add words one at a time until we go over.
+ if(width > 0 && FC_GetWidth(font, "%s", line) > width)
+ {
+ FC_StringList *words, *word_iter;
+
+ words = FC_Explode(line, ' ');
+ // Skip the first word for the iterator, so there will always be at least one word per line
+ line = new_concat(words->value, " ");
+ for(word_iter = words->next; word_iter != NULL; word_iter = word_iter->next)
+ {
+ char* line_plus_word = new_concat(line, word_iter->value);
+ char* word_plus_space = new_concat(word_iter->value, " ");
+ if(FC_GetWidth(font, line_plus_word) > width)
+ {
+ current = FC_StringListPushBack(current, line, 0);
+
+ line = word_plus_space;
+ }
+ else
+ {
+ replace_concat(&line, word_plus_space);
+ free(word_plus_space);
+ }
+ free(line_plus_word);
+ }
+ current = FC_StringListPushBack(current, line, 0);
+ FC_StringListFree(words);
+ }
+ else
+ {
+ current = FC_StringListPushBack(current, line, 0);
+ iter->value = NULL;
+ }
+ }
+ FC_StringListFree(ls);
+
+ return result;
+}
+
+static void FC_DrawColumnFromBuffer(FC_Font* font, FC_Target* dest, FC_Rect box, int* total_height, FC_Scale scale, FC_AlignEnum align)
+{
+ int y = box.y;
+ FC_StringList *ls, *iter;
+
+ ls = FC_GetBufferFitToColumn(font, box.w, scale, 0);
+ for(iter = ls; iter != NULL; iter = iter->next)
+ {
+ FC_RenderAlign(font, dest, box.x, y, box.w, scale, align, iter->value);
+ y += FC_GetLineHeight(font);
+ }
+ FC_StringListFree(ls);
+
+ if(total_height != NULL)
+ *total_height = y - box.y;
+}
+
+FC_Rect FC_DrawBox(FC_Font* font, FC_Target* dest, FC_Rect box, const char* formatted_text, ...)
+{
+ Uint8 useClip;
+ if(formatted_text == NULL || font == NULL)
+ return FC_MakeRect(box.x, box.y, 0, 0);
+
+ FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
+
+ useClip = has_clip(dest);
+ FC_Rect oldclip, newclip;
+ if(useClip)
+ {
+ oldclip = get_clip(dest);
+ newclip = FC_RectIntersect(oldclip, box);
+ }
+ else
+ newclip = box;
+ set_clip(dest, &newclip);
+
+ set_color_for_all_caches(font, font->default_color);
+
+ FC_DrawColumnFromBuffer(font, dest, box, NULL, FC_MakeScale(1,1), FC_ALIGN_LEFT);
+
+ if(useClip)
+ set_clip(dest, &oldclip);
+ else
+ set_clip(dest, NULL);
+
+ return box;
+}
+
+FC_Rect FC_DrawBoxAlign(FC_Font* font, FC_Target* dest, FC_Rect box, FC_AlignEnum align, const char* formatted_text, ...)
+{
+ Uint8 useClip;
+ if(formatted_text == NULL || font == NULL)
+ return FC_MakeRect(box.x, box.y, 0, 0);
+
+ FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
+
+ useClip = has_clip(dest);
+ FC_Rect oldclip, newclip;
+ if(useClip)
+ {
+ oldclip = get_clip(dest);
+ newclip = FC_RectIntersect(oldclip, box);
+ }
+ else
+ newclip = box;
+ set_clip(dest, &newclip);
+
+ set_color_for_all_caches(font, font->default_color);
+
+ FC_DrawColumnFromBuffer(font, dest, box, NULL, FC_MakeScale(1,1), align);
+
+ if(useClip)
+ set_clip(dest, &oldclip);
+ else
+ set_clip(dest, NULL);
+
+ return box;
+}
+
+FC_Rect FC_DrawBoxScale(FC_Font* font, FC_Target* dest, FC_Rect box, FC_Scale scale, const char* formatted_text, ...)
+{
+ Uint8 useClip;
+ if(formatted_text == NULL || font == NULL)
+ return FC_MakeRect(box.x, box.y, 0, 0);
+
+ FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
+
+ useClip = has_clip(dest);
+ FC_Rect oldclip, newclip;
+ if(useClip)
+ {
+ oldclip = get_clip(dest);
+ newclip = FC_RectIntersect(oldclip, box);
+ }
+ else
+ newclip = box;
+ set_clip(dest, &newclip);
+
+ set_color_for_all_caches(font, font->default_color);
+
+ FC_DrawColumnFromBuffer(font, dest, box, NULL, scale, FC_ALIGN_LEFT);
+
+ if(useClip)
+ set_clip(dest, &oldclip);
+ else
+ set_clip(dest, NULL);
+
+ return box;
+}
+
+FC_Rect FC_DrawBoxColor(FC_Font* font, FC_Target* dest, FC_Rect box, SDL_Color color, const char* formatted_text, ...)
+{
+ Uint8 useClip;
+ if(formatted_text == NULL || font == NULL)
+ return FC_MakeRect(box.x, box.y, 0, 0);
+
+ FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
+
+ useClip = has_clip(dest);
+ FC_Rect oldclip, newclip;
+ if(useClip)
+ {
+ oldclip = get_clip(dest);
+ newclip = FC_RectIntersect(oldclip, box);
+ }
+ else
+ newclip = box;
+ set_clip(dest, &newclip);
+
+ set_color_for_all_caches(font, color);
+
+ FC_DrawColumnFromBuffer(font, dest, box, NULL, FC_MakeScale(1,1), FC_ALIGN_LEFT);
+
+ if(useClip)
+ set_clip(dest, &oldclip);
+ else
+ set_clip(dest, NULL);
+
+ return box;
+}
+
+FC_Rect FC_DrawBoxEffect(FC_Font* font, FC_Target* dest, FC_Rect box, FC_Effect effect, const char* formatted_text, ...)
+{
+ Uint8 useClip;
+ if(formatted_text == NULL || font == NULL)
+ return FC_MakeRect(box.x, box.y, 0, 0);
+
+ FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
+
+ useClip = has_clip(dest);
+ FC_Rect oldclip, newclip;
+ if(useClip)
+ {
+ oldclip = get_clip(dest);
+ newclip = FC_RectIntersect(oldclip, box);
+ }
+ else
+ newclip = box;
+ set_clip(dest, &newclip);
+
+ set_color_for_all_caches(font, effect.color);
+
+ FC_DrawColumnFromBuffer(font, dest, box, NULL, effect.scale, effect.alignment);
+
+ if(useClip)
+ set_clip(dest, &oldclip);
+ else
+ set_clip(dest, NULL);
+
+ return box;
+}
+
+FC_Rect FC_DrawColumn(FC_Font* font, FC_Target* dest, float x, float y, Uint16 width, const char* formatted_text, ...)
+{
+ FC_Rect box = {x, y, width, 0};
+ int total_height;
+
+ if(formatted_text == NULL || font == NULL)
+ return FC_MakeRect(x, y, 0, 0);
+
+ FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
+
+ set_color_for_all_caches(font, font->default_color);
+
+ FC_DrawColumnFromBuffer(font, dest, box, &total_height, FC_MakeScale(1,1), FC_ALIGN_LEFT);
+
+ return FC_MakeRect(box.x, box.y, width, total_height);
+}
+
+FC_Rect FC_DrawColumnAlign(FC_Font* font, FC_Target* dest, float x, float y, Uint16 width, FC_AlignEnum align, const char* formatted_text, ...)
+{
+ FC_Rect box = {x, y, width, 0};
+ int total_height;
+
+ if(formatted_text == NULL || font == NULL)
+ return FC_MakeRect(x, y, 0, 0);
+
+ FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
+
+ set_color_for_all_caches(font, font->default_color);
+
+ switch(align)
+ {
+ case FC_ALIGN_CENTER:
+ box.x -= width/2;
+ break;
+ case FC_ALIGN_RIGHT:
+ box.x -= width;
+ break;
+ default:
+ break;
+ }
+
+ FC_DrawColumnFromBuffer(font, dest, box, &total_height, FC_MakeScale(1,1), align);
+
+ return FC_MakeRect(box.x, box.y, width, total_height);
+}
+
+FC_Rect FC_DrawColumnScale(FC_Font* font, FC_Target* dest, float x, float y, Uint16 width, FC_Scale scale, const char* formatted_text, ...)
+{
+ FC_Rect box = {x, y, width, 0};
+ int total_height;
+
+ if(formatted_text == NULL || font == NULL)
+ return FC_MakeRect(x, y, 0, 0);
+
+ FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
+
+ set_color_for_all_caches(font, font->default_color);
+
+ FC_DrawColumnFromBuffer(font, dest, box, &total_height, scale, FC_ALIGN_LEFT);
+
+ return FC_MakeRect(box.x, box.y, width, total_height);
+}
+
+FC_Rect FC_DrawColumnColor(FC_Font* font, FC_Target* dest, float x, float y, Uint16 width, SDL_Color color, const char* formatted_text, ...)
+{
+ FC_Rect box = {x, y, width, 0};
+ int total_height;
+
+ if(formatted_text == NULL || font == NULL)
+ return FC_MakeRect(x, y, 0, 0);
+
+ FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
+
+ set_color_for_all_caches(font, color);
+
+ FC_DrawColumnFromBuffer(font, dest, box, &total_height, FC_MakeScale(1,1), FC_ALIGN_LEFT);
+
+ return FC_MakeRect(box.x, box.y, width, total_height);
+}
+
+FC_Rect FC_DrawColumnEffect(FC_Font* font, FC_Target* dest, float x, float y, Uint16 width, FC_Effect effect, const char* formatted_text, ...)
+{
+ FC_Rect box = {x, y, width, 0};
+ int total_height;
+
+ if(formatted_text == NULL || font == NULL)
+ return FC_MakeRect(x, y, 0, 0);
+
+ FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
+
+ set_color_for_all_caches(font, effect.color);
+
+ switch(effect.alignment)
+ {
+ case FC_ALIGN_CENTER:
+ box.x -= width/2;
+ break;
+ case FC_ALIGN_RIGHT:
+ box.x -= width;
+ break;
+ default:
+ break;
+ }
+
+ FC_DrawColumnFromBuffer(font, dest, box, &total_height, effect.scale, effect.alignment);
+
+ return FC_MakeRect(box.x, box.y, width, total_height);
+}
+
+static FC_Rect FC_RenderCenter(FC_Font* font, FC_Target* dest, float x, float y, FC_Scale scale, const char* text)
+{
+ FC_Rect result = {x, y, 0, 0};
+ if(text == NULL || font == NULL)
+ return result;
+
+ char* str = U8_strdup(text);
+ char* del = str;
+ char* c;
+
+ // Go through str, when you find a \n, replace it with \0 and print it
+ // then move down, back, and continue.
+ for(c = str; *c != '\0';)
+ {
+ if(*c == '\n')
+ {
+ *c = '\0';
+ result = FC_RectUnion(FC_RenderLeft(font, dest, x - scale.x*FC_GetWidth(font, "%s", str)/2.0f, y, scale, str), result);
+ *c = '\n';
+ c++;
+ str = c;
+ y += scale.y*font->height;
+ }
+ else
+ c++;
+ }
+
+ result = FC_RectUnion(FC_RenderLeft(font, dest, x - scale.x*FC_GetWidth(font, "%s", str)/2.0f, y, scale, str), result);
+
+ free(del);
+ return result;
+}
+
+static FC_Rect FC_RenderRight(FC_Font* font, FC_Target* dest, float x, float y, FC_Scale scale, const char* text)
+{
+ FC_Rect result = {x, y, 0, 0};
+ if(text == NULL || font == NULL)
+ return result;
+
+ char* str = U8_strdup(text);
+ char* del = str;
+ char* c;
+
+ for(c = str; *c != '\0';)
+ {
+ if(*c == '\n')
+ {
+ *c = '\0';
+ result = FC_RectUnion(FC_RenderLeft(font, dest, x - scale.x*FC_GetWidth(font, "%s", str), y, scale, str), result);
+ *c = '\n';
+ c++;
+ str = c;
+ y += scale.y*font->height;
+ }
+ else
+ c++;
+ }
+
+ result = FC_RectUnion(FC_RenderLeft(font, dest, x - scale.x*FC_GetWidth(font, "%s", str), y, scale, str), result);
+
+ free(del);
+ return result;
+}
+
+
+
+FC_Rect FC_DrawScale(FC_Font* font, FC_Target* dest, float x, float y, FC_Scale scale, const char* formatted_text, ...)
+{
+ if(formatted_text == NULL || font == NULL)
+ return FC_MakeRect(x, y, 0, 0);
+
+ FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
+
+ set_color_for_all_caches(font, font->default_color);
+
+ return FC_RenderLeft(font, dest, x, y, scale, fc_buffer);
+}
+
+FC_Rect FC_DrawAlign(FC_Font* font, FC_Target* dest, float x, float y, FC_AlignEnum align, const char* formatted_text, ...)
+{
+ if(formatted_text == NULL || font == NULL)
+ return FC_MakeRect(x, y, 0, 0);
+
+ FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
+
+ set_color_for_all_caches(font, font->default_color);
+
+ FC_Rect result;
+ switch(align)
+ {
+ case FC_ALIGN_LEFT:
+ result = FC_RenderLeft(font, dest, x, y, FC_MakeScale(1,1), fc_buffer);
+ break;
+ case FC_ALIGN_CENTER:
+ result = FC_RenderCenter(font, dest, x, y, FC_MakeScale(1,1), fc_buffer);
+ break;
+ case FC_ALIGN_RIGHT:
+ result = FC_RenderRight(font, dest, x, y, FC_MakeScale(1,1), fc_buffer);
+ break;
+ default:
+ result = FC_MakeRect(x, y, 0, 0);
+ break;
+ }
+
+ return result;
+}
+
+FC_Rect FC_DrawColor(FC_Font* font, FC_Target* dest, float x, float y, SDL_Color color, const char* formatted_text, ...)
+{
+ if(formatted_text == NULL || font == NULL)
+ return FC_MakeRect(x, y, 0, 0);
+
+ FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
+
+ set_color_for_all_caches(font, color);
+
+ return FC_RenderLeft(font, dest, x, y, FC_MakeScale(1,1), fc_buffer);
+}
+
+
+FC_Rect FC_DrawEffect(FC_Font* font, FC_Target* dest, float x, float y, FC_Effect effect, const char* formatted_text, ...)
+{
+ if(formatted_text == NULL || font == NULL)
+ return FC_MakeRect(x, y, 0, 0);
+
+ FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
+
+ set_color_for_all_caches(font, effect.color);
+
+ FC_Rect result;
+ switch(effect.alignment)
+ {
+ case FC_ALIGN_LEFT:
+ result = FC_RenderLeft(font, dest, x, y, effect.scale, fc_buffer);
+ break;
+ case FC_ALIGN_CENTER:
+ result = FC_RenderCenter(font, dest, x, y, effect.scale, fc_buffer);
+ break;
+ case FC_ALIGN_RIGHT:
+ result = FC_RenderRight(font, dest, x, y, effect.scale, fc_buffer);
+ break;
+ default:
+ result = FC_MakeRect(x, y, 0, 0);
+ break;
+ }
+
+ return result;
+}
+
+
+
+
+// Getters
+
+
+FC_FilterEnum FC_GetFilterMode(FC_Font* font)
+{
+ if(font == NULL)
+ return FC_FILTER_NEAREST;
+
+ return font->filter;
+}
+
+Uint16 FC_GetLineHeight(FC_Font* font)
+{
+ if(font == NULL)
+ return 0;
+
+ return font->height;
+}
+
+Uint16 FC_GetHeight(FC_Font* font, const char* formatted_text, ...)
+{
+ if(formatted_text == NULL || font == NULL)
+ return 0;
+
+ FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
+
+ Uint16 numLines = 1;
+ const char* c;
+
+ for (c = fc_buffer; *c != '\0'; c++)
+ {
+ if(*c == '\n')
+ numLines++;
+ }
+
+ // Actual height of letter region + line spacing
+ return font->height*numLines + font->lineSpacing*(numLines - 1); //height*numLines;
+}
+
+Uint16 FC_GetWidth(FC_Font* font, const char* formatted_text, ...)
+{
+ if(formatted_text == NULL || font == NULL)
+ return 0;
+
+ FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
+
+ const char* c;
+ Uint16 width = 0;
+ Uint16 bigWidth = 0; // Allows for multi-line strings
+
+ for (c = fc_buffer; *c != '\0'; c++)
+ {
+ if(*c == '\n')
+ {
+ bigWidth = bigWidth >= width? bigWidth : width;
+ width = 0;
+ continue;
+ }
+
+ FC_GlyphData glyph;
+ Uint32 codepoint = FC_GetCodepointFromUTF8(&c, 1);
+ if(FC_GetGlyphData(font, &glyph, codepoint) || FC_GetGlyphData(font, &glyph, ' '))
+ width += glyph.rect.w;
+ }
+ bigWidth = bigWidth >= width? bigWidth : width;
+
+ return bigWidth;
+}
+
+// If width == -1, use no width limit
+FC_Rect FC_GetCharacterOffset(FC_Font* font, Uint16 position_index, int column_width, const char* formatted_text, ...)
+{
+ FC_Rect result = {0, 0, 1, FC_GetLineHeight(font)};
+ FC_StringList *ls, *iter;
+ int num_lines = 0;
+ Uint8 done = 0;
+
+ if(formatted_text == NULL || column_width == 0 || position_index == 0 || font == NULL)
+ return result;
+
+ FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
+
+ ls = FC_GetBufferFitToColumn(font, column_width, FC_MakeScale(1,1), 1);
+ for(iter = ls; iter != NULL; iter = iter->next)
+ {
+ char* line;
+ int i = 0;
+
+ ++num_lines;
+ for(line = iter->value; line != NULL && *line != '\0'; line = (char*)U8_next(line))
+ {
+ ++i;
+ --position_index;
+ if(position_index == 0)
+ {
+ // FIXME: Doesn't handle box-wrapped newlines correctly
+ line = (char*)U8_next(line);
+ line[0] = '\0';
+ result.x = FC_GetWidth(font, "%s", iter->value);
+ done = 1;
+ break;
+ }
+ }
+ if(done)
+ break;
+ }
+ FC_StringListFree(ls);
+
+ if(num_lines > 0)
+ {
+ result.y = (num_lines - 1) * FC_GetLineHeight(font);
+ }
+
+ return result;
+}
+
+
+Uint16 FC_GetColumnHeight(FC_Font* font, Uint16 width, const char* formatted_text, ...)
+{
+ int y = 0;
+
+ FC_StringList *ls, *iter;
+
+ if(font == NULL)
+ return 0;
+
+ if(formatted_text == NULL || width == 0)
+ return font->height;
+
+ FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
+
+ ls = FC_GetBufferFitToColumn(font, width, FC_MakeScale(1,1), 0);
+ for(iter = ls; iter != NULL; iter = iter->next)
+ {
+ y += FC_GetLineHeight(font);
+ }
+ FC_StringListFree(ls);
+
+ return y;
+}
+
+static int FC_GetAscentFromCodepoint(FC_Font* font, Uint32 codepoint)
+{
+ FC_GlyphData glyph;
+
+ if(font == NULL)
+ return 0;
+
+ // FIXME: Store ascent so we can return it here
+ FC_GetGlyphData(font, &glyph, codepoint);
+ return glyph.rect.h;
+}
+
+static int FC_GetDescentFromCodepoint(FC_Font* font, Uint32 codepoint)
+{
+ FC_GlyphData glyph;
+
+ if(font == NULL)
+ return 0;
+
+ // FIXME: Store descent so we can return it here
+ FC_GetGlyphData(font, &glyph, codepoint);
+ return glyph.rect.h;
+}
+
+int FC_GetAscent(FC_Font* font, const char* formatted_text, ...)
+{
+ Uint32 codepoint;
+ int max, ascent;
+ const char* c;
+
+ if(font == NULL)
+ return 0;
+
+ if(formatted_text == NULL)
+ return font->ascent;
+
+ FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
+
+ max = 0;
+ c = fc_buffer;
+
+ while(*c != '\0')
+ {
+ codepoint = FC_GetCodepointFromUTF8(&c, 1);
+ if(codepoint != 0)
+ {
+ ascent = FC_GetAscentFromCodepoint(font, codepoint);
+ if(ascent > max)
+ max = ascent;
+ }
+ ++c;
+ }
+ return max;
+}
+
+int FC_GetDescent(FC_Font* font, const char* formatted_text, ...)
+{
+ Uint32 codepoint;
+ int max, descent;
+ const char* c;
+
+ if(font == NULL)
+ return 0;
+
+ if(formatted_text == NULL)
+ return font->descent;
+
+ FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
+
+ max = 0;
+ c = fc_buffer;
+
+ while(*c != '\0')
+ {
+ codepoint = FC_GetCodepointFromUTF8(&c, 1);
+ if(codepoint != 0)
+ {
+ descent = FC_GetDescentFromCodepoint(font, codepoint);
+ if(descent > max)
+ max = descent;
+ }
+ ++c;
+ }
+ return max;
+}
+
+int FC_GetBaseline(FC_Font* font)
+{
+ if(font == NULL)
+ return 0;
+
+ return font->baseline;
+}
+
+int FC_GetSpacing(FC_Font* font)
+{
+ if(font == NULL)
+ return 0;
+
+ return font->letterSpacing;
+}
+
+int FC_GetLineSpacing(FC_Font* font)
+{
+ if(font == NULL)
+ return 0;
+
+ return font->lineSpacing;
+}
+
+Uint16 FC_GetMaxWidth(FC_Font* font)
+{
+ if(font == NULL)
+ return 0;
+
+ return font->maxWidth;
+}
+
+SDL_Color FC_GetDefaultColor(FC_Font* font)
+{
+ if(font == NULL)
+ {
+ SDL_Color c = {0,0,0,255};
+ return c;
+ }
+
+ return font->default_color;
+}
+
+
+Uint8 FC_InRect(float x, float y, FC_Rect input_rect)
+{
+ return (input_rect.x <= x && x <= input_rect.x + input_rect.w && input_rect.y <= y && y <= input_rect.y + input_rect.h);
+}
+
+// TODO: Make it work with alignment
+Uint16 FC_GetPositionFromOffset(FC_Font* font, float x, float y, int column_width, FC_AlignEnum align, const char* formatted_text, ...)
+{
+ FC_StringList *ls, *iter;
+ Uint8 done = 0;
+ int height = FC_GetLineHeight(font);
+ Uint16 position = 0;
+ int current_x = 0;
+ int current_y = 0;
+ FC_GlyphData glyph_data;
+
+ if(formatted_text == NULL || column_width == 0 || font == NULL)
+ return 0;
+
+ FC_EXTRACT_VARARGS(fc_buffer, formatted_text);
+
+ ls = FC_GetBufferFitToColumn(font, column_width, FC_MakeScale(1,1), 1);
+ for(iter = ls; iter != NULL; iter = iter->next)
+ {
+ char* line;
+
+ for(line = iter->value; line != NULL && *line != '\0'; line = (char*)U8_next(line))
+ {
+ if(FC_GetGlyphData(font, &glyph_data, FC_GetCodepointFromUTF8((const char**)&line, 0)))
+ {
+ if(FC_InRect(x, y, FC_MakeRect(current_x, current_y, glyph_data.rect.w, glyph_data.rect.h)))
+ {
+ done = 1;
+ break;
+ }
+
+ current_x += glyph_data.rect.w;
+ }
+ position++;
+ }
+ if(done)
+ break;
+
+ current_x = 0;
+ current_y += height;
+ if(y < current_y)
+ break;
+ }
+ FC_StringListFree(ls);
+
+ return position;
+}
+
+
+
+
+// Setters
+
+
+void FC_SetFilterMode(FC_Font* font, FC_FilterEnum filter)
+{
+ if(font == NULL)
+ return;
+
+ if(font->filter != filter)
+ {
+ font->filter = filter;
+
+ #ifdef FC_USE_SDL_GPU
+ // Update each texture to use this filter mode
+ {
+ int i;
+ GPU_FilterEnum gpu_filter = GPU_FILTER_NEAREST;
+ if(FC_GetFilterMode(font) == FC_FILTER_LINEAR)
+ gpu_filter = GPU_FILTER_LINEAR;
+
+ for(i = 0; i < font->glyph_cache_count; ++i)
+ {
+ GPU_SetImageFilter(font->glyph_cache[i], gpu_filter);
+ }
+ }
+ #endif
+ }
+}
+
+
+void FC_SetSpacing(FC_Font* font, int LetterSpacing)
+{
+ if(font == NULL)
+ return;
+
+ font->letterSpacing = LetterSpacing;
+}
+
+void FC_SetLineSpacing(FC_Font* font, int LineSpacing)
+{
+ if(font == NULL)
+ return;
+
+ font->lineSpacing = LineSpacing;
+}
+
+void FC_SetDefaultColor(FC_Font* font, SDL_Color color)
+{
+ if(font == NULL)
+ return;
+
+ font->default_color = color;
+}
+
+
+
+
+
+
diff --git a/source/code/Libs/SDL_FontCache.h b/source/code/Libs/SDL_FontCache.h
new file mode 100644
index 0000000..cd0d0e5
--- /dev/null
+++ b/source/code/Libs/SDL_FontCache.h
@@ -0,0 +1,298 @@
+/*
+SDL_FontCache v0.0.1: A font cache for SDL and SDL_ttf
+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) 2015 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.
+*/
+
+#ifndef _SDL_FONTCACHE_H__
+#define _SDL_FONTCACHE_H__
+
+#include "SDL.h"
+#include "SDL_ttf.h"
+
+#ifdef FC_USE_SDL_GPU
+ #include "SDL_gpu.h"
+#endif
+
+
+#include <stdarg.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+// Let's pretend this exists...
+#define TTF_STYLE_OUTLINE 16
+
+
+
+// Differences between SDL_Renderer and SDL_gpu
+#ifdef FC_USE_SDL_GPU
+#define FC_Rect GPU_Rect
+#define FC_Target GPU_Target
+#define FC_Image GPU_Image
+#define FC_Log GPU_LogError
+#else
+#define FC_Rect SDL_Rect
+#define FC_Target SDL_Renderer
+#define FC_Image SDL_Texture
+#define FC_Log SDL_Log
+#endif
+
+
+// SDL_FontCache types
+
+typedef enum
+{
+ FC_ALIGN_LEFT,
+ FC_ALIGN_CENTER,
+ FC_ALIGN_RIGHT
+} FC_AlignEnum;
+
+typedef enum
+{
+ FC_FILTER_NEAREST,
+ FC_FILTER_LINEAR
+} FC_FilterEnum;
+
+typedef struct FC_Scale
+{
+ float x;
+ float y;
+
+} FC_Scale;
+
+typedef struct FC_Effect
+{
+ FC_AlignEnum alignment;
+ FC_Scale scale;
+ SDL_Color color;
+
+} FC_Effect;
+
+// Opaque type
+typedef struct FC_Font FC_Font;
+
+
+typedef struct FC_GlyphData
+{
+ SDL_Rect rect;
+ int cache_level;
+
+} FC_GlyphData;
+
+
+
+
+// Object creation
+
+FC_Rect FC_MakeRect(float x, float y, float w, float h);
+
+FC_Scale FC_MakeScale(float x, float y);
+
+SDL_Color FC_MakeColor(Uint8 r, Uint8 g, Uint8 b, Uint8 a);
+
+FC_Effect FC_MakeEffect(FC_AlignEnum alignment, FC_Scale scale, SDL_Color color);
+
+FC_GlyphData FC_MakeGlyphData(int cache_level, Sint16 x, Sint16 y, Uint16 w, Uint16 h);
+
+
+
+// Font object
+
+FC_Font* FC_CreateFont(void);
+
+#ifdef FC_USE_SDL_GPU
+Uint8 FC_LoadFont(FC_Font* font, const char* filename_ttf, Uint32 pointSize, SDL_Color color, int style);
+
+Uint8 FC_LoadFontFromTTF(FC_Font* font, TTF_Font* ttf, SDL_Color color);
+
+Uint8 FC_LoadFont_RW(FC_Font* font, SDL_RWops* file_rwops_ttf, Uint8 own_rwops, Uint32 pointSize, SDL_Color color, int style);
+#else
+Uint8 FC_LoadFont(FC_Font* font, SDL_Renderer* renderer, const char* filename_ttf, Uint32 pointSize, SDL_Color color, int style);
+
+Uint8 FC_LoadFontFromTTF(FC_Font* font, SDL_Renderer* renderer, TTF_Font* ttf, SDL_Color color);
+
+Uint8 FC_LoadFont_RW(FC_Font* font, SDL_Renderer* renderer, SDL_RWops* file_rwops_ttf, Uint8 own_rwops, Uint32 pointSize, SDL_Color color, int style);
+#endif
+
+void FC_ClearFont(FC_Font* font);
+
+void FC_FreeFont(FC_Font* font);
+
+
+
+// Built-in loading strings
+
+const char* FC_GetStringASCII(void);
+
+const char* FC_GetStringLatin1(void);
+
+const char* FC_GetStringASCII_Latin1(void);
+
+
+// UTF-8 to SDL_FontCache codepoint conversion
+
+/*!
+Returns the Uint32 codepoint (not UTF-32) parsed from the given UTF-8 string.
+\param c A pointer to a string of proper UTF-8 character values.
+\param advance_pointer If true, the source pointer will be incremented to skip the extra bytes from multibyte codepoints.
+*/
+Uint32 FC_GetCodepointFromUTF8(const char** c, Uint8 advance_pointer);
+
+/*!
+Parses the given codepoint and stores the UTF-8 bytes in 'result'. The result is NULL terminated.
+\param result A memory buffer for the UTF-8 values. Must be at least 5 bytes long.
+\param codepoint The Uint32 codepoint to parse (not UTF-32).
+*/
+void FC_GetUTF8FromCodepoint(char* result, Uint32 codepoint);
+
+
+// UTF-8 string operations
+
+/*! Allocates a new string of 'size' bytes that is already NULL-terminated. The NULL byte counts toward the size limit, as usual. Returns NULL if size is 0. */
+char* U8_alloc(unsigned int size);
+
+/*! Deallocates the given string. */
+void U8_free(char* string);
+
+/*! Allocates a copy of the given string. */
+char* U8_strdup(const char* string);
+
+/*! Returns the number of UTF-8 characters in the given string. */
+int U8_strlen(const char* string);
+
+/*! Returns the number of bytes in the UTF-8 multibyte character pointed at by 'character'. */
+int U8_charsize(const char* character);
+
+/*! Copies the source multibyte character into the given buffer without overrunning it. Returns 0 on failure. */
+int U8_charcpy(char* buffer, const char* source, int buffer_size);
+
+/*! Returns a pointer to the next UTF-8 character. */
+const char* U8_next(const char* string);
+
+/*! Inserts a UTF-8 string into 'string' at the given position. Use a position of -1 to append. Returns 0 when unable to insert the string. */
+int U8_strinsert(char* string, int position, const char* source, int max_bytes);
+
+/*! Erases the UTF-8 character at the given position, moving the subsequent characters down. */
+void U8_strdel(char* string, int position);
+
+
+// Internal settings
+
+/*! Sets the string from which to load the initial glyphs. Use this if you need upfront loading for any reason (such as lack of render-target support). */
+void FC_SetLoadingString(FC_Font* font, const char* string);
+
+/*! Changes the size of the internal buffer which is used for unpacking variadic text data. This buffer is shared by all FC_Fonts. */
+void FC_SetBufferSize(unsigned int size);
+
+void FC_SetRenderCallback(FC_Rect (*callback)(FC_Image* src, FC_Rect* srcrect, FC_Target* dest, float x, float y, float xscale, float yscale));
+
+FC_Rect FC_DefaultRenderCallback(FC_Image* src, FC_Rect* srcrect, FC_Target* dest, float x, float y, float xscale, float yscale);
+
+
+// Custom caching
+
+/*! Returns the number of cache levels that are active. */
+int FC_GetNumCacheLevels(FC_Font* font);
+
+/*! Returns the cache source texture at the given cache level. */
+FC_Image* FC_GetGlyphCacheLevel(FC_Font* font, int cache_level);
+
+// TODO: Specify ownership of the texture (should be shareable)
+/*! Sets a cache source texture for rendering. New cache levels must be sequential. */
+Uint8 FC_SetGlyphCacheLevel(FC_Font* font, int cache_level, FC_Image* cache_texture);
+
+/*! Stores the glyph data for the given codepoint in 'result'. Returns 0 if the codepoint was not found in the cache. */
+Uint8 FC_GetGlyphData(FC_Font* font, FC_GlyphData* result, Uint32 codepoint);
+
+/*! Sets the glyph data for the given codepoint. Duplicates are not checked. Returns a pointer to the stored data. */
+FC_GlyphData* FC_SetGlyphData(FC_Font* font, Uint32 codepoint, FC_GlyphData glyph_data);
+
+
+// Rendering
+
+FC_Rect FC_Draw(FC_Font* font, FC_Target* dest, float x, float y, const char* formatted_text, ...);
+FC_Rect FC_DrawAlign(FC_Font* font, FC_Target* dest, float x, float y, FC_AlignEnum align, const char* formatted_text, ...);
+FC_Rect FC_DrawScale(FC_Font* font, FC_Target* dest, float x, float y, FC_Scale scale, const char* formatted_text, ...);
+FC_Rect FC_DrawColor(FC_Font* font, FC_Target* dest, float x, float y, SDL_Color color, const char* formatted_text, ...);
+FC_Rect FC_DrawEffect(FC_Font* font, FC_Target* dest, float x, float y, FC_Effect effect, const char* formatted_text, ...);
+
+FC_Rect FC_DrawBox(FC_Font* font, FC_Target* dest, FC_Rect box, const char* formatted_text, ...);
+FC_Rect FC_DrawBoxAlign(FC_Font* font, FC_Target* dest, FC_Rect box, FC_AlignEnum align, const char* formatted_text, ...);
+FC_Rect FC_DrawBoxScale(FC_Font* font, FC_Target* dest, FC_Rect box, FC_Scale scale, const char* formatted_text, ...);
+FC_Rect FC_DrawBoxColor(FC_Font* font, FC_Target* dest, FC_Rect box, SDL_Color color, const char* formatted_text, ...);
+FC_Rect FC_DrawBoxEffect(FC_Font* font, FC_Target* dest, FC_Rect box, FC_Effect effect, const char* formatted_text, ...);
+
+FC_Rect FC_DrawColumn(FC_Font* font, FC_Target* dest, float x, float y, Uint16 width, const char* formatted_text, ...);
+FC_Rect FC_DrawColumnAlign(FC_Font* font, FC_Target* dest, float x, float y, Uint16 width, FC_AlignEnum align, const char* formatted_text, ...);
+FC_Rect FC_DrawColumnScale(FC_Font* font, FC_Target* dest, float x, float y, Uint16 width, FC_Scale scale, const char* formatted_text, ...);
+FC_Rect FC_DrawColumnColor(FC_Font* font, FC_Target* dest, float x, float y, Uint16 width, SDL_Color color, const char* formatted_text, ...);
+FC_Rect FC_DrawColumnEffect(FC_Font* font, FC_Target* dest, float x, float y, Uint16 width, FC_Effect effect, const char* formatted_text, ...);
+
+
+// Getters
+
+FC_FilterEnum FC_GetFilterMode(FC_Font* font);
+Uint16 FC_GetLineHeight(FC_Font* font);
+Uint16 FC_GetHeight(FC_Font* font, const char* formatted_text, ...);
+Uint16 FC_GetWidth(FC_Font* font, const char* formatted_text, ...);
+
+// Returns a 1-pixel wide box in front of the character in the given position (index)
+FC_Rect FC_GetCharacterOffset(FC_Font* font, Uint16 position_index, int column_width, const char* formatted_text, ...);
+Uint16 FC_GetColumnHeight(FC_Font* font, Uint16 width, const char* formatted_text, ...);
+
+int FC_GetAscent(FC_Font* font, const char* formatted_text, ...);
+int FC_GetDescent(FC_Font* font, const char* formatted_text, ...);
+int FC_GetBaseline(FC_Font* font);
+int FC_GetSpacing(FC_Font* font);
+int FC_GetLineSpacing(FC_Font* font);
+Uint16 FC_GetMaxWidth(FC_Font* font);
+SDL_Color FC_GetDefaultColor(FC_Font* font);
+
+Uint8 FC_InRect(float x, float y, FC_Rect input_rect);
+// Given an offset (x,y) from the text draw position (the upper-left corner), returns the character position (UTF-8 index)
+Uint16 FC_GetPositionFromOffset(FC_Font* font, float x, float y, int column_width, FC_AlignEnum align, const char* formatted_text, ...);
+
+// Setters
+
+void FC_SetFilterMode(FC_Font* font, FC_FilterEnum filter);
+void FC_SetSpacing(FC_Font* font, int LetterSpacing);
+void FC_SetLineSpacing(FC_Font* font, int LineSpacing);
+void FC_SetDefaultColor(FC_Font* font, SDL_Color color);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+
+#endif
diff --git a/source/code/Makefile b/source/code/Makefile
index 8a8acf9..b3d2276 100644
--- a/source/code/Makefile
+++ b/source/code/Makefile
@@ -10,13 +10,13 @@ ifdef CROSS
CXX=$(CROSS)g++
endif
-BASE_CFLAGS=-c $(shell $(CROSS)sdl-config --cflags) -std=c++11
+BASE_CFLAGS=-c $(shell $(CROSS)sdl2-config --cflags) -std=c++11
ifndef BUILDDIR
BUILDDIR=build
endif
-BASE_LIBS=$(shell $(CROSS)sdl-config --libs) -lSDL_ttf $(shell $(CROSS)pkg-config SDL_image SDL_mixer --libs)
+BASE_LIBS=$(shell $(CROSS)sdl2-config --libs) -lSDL_ttf $(shell $(CROSS)pkg-config SDL_image SDL_mixer --libs)
#For developement only
ifndef DEBUG
diff --git a/source/code/ReadKeyboard.cpp b/source/code/ReadKeyboard.cpp
index 0b70924..4ee5278 100644
--- a/source/code/ReadKeyboard.cpp
+++ b/source/code/ReadKeyboard.cpp
@@ -45,7 +45,7 @@ ReadKeyboard::ReadKeyboard(const char* oldName) {
}
-void ReadKeyboard::putchar(char thing) {
+void ReadKeyboard::putchar(const std::string& thing) {
if (text_string.length() < maxLength) {
text_string.insert(position, thing);
utf8::advance(position, 1, text_string.end());
@@ -61,7 +61,7 @@ void ReadKeyboard::removeChar() {
}
}
-bool ReadKeyboard::ReadKey(const SDL_keysym& key) {
+bool ReadKeyboard::ReadKey(const SDL_Event& key) {
if (
(key.unicode >= 'a' && key.unicode <= 'z') ||
(key.unicode >= '0' && key.unicode <= '9') ||
@@ -75,7 +75,7 @@ bool ReadKeyboard::ReadKey(const SDL_keysym& key) {
return ReadKey(key.sym);
}
-bool ReadKeyboard::ReadKey(SDLKey keyPressed) {
+bool ReadKeyboard::ReadKey(SDL_Keycode keyPressed) {
if (keyPressed == SDLK_SPACE) {
ReadKeyboard::putchar(' ');
return true;
diff --git a/source/code/ReadKeyboard.h b/source/code/ReadKeyboard.h
index 36946c9..fe7ed03 100644
--- a/source/code/ReadKeyboard.h
+++ b/source/code/ReadKeyboard.h
@@ -34,14 +34,14 @@ private:
int maxLength;
std::string::iterator position;
std::string text_string;
- void putchar(char);
+ void putchar(const std::string& );
void removeChar();
public:
ReadKeyboard(void);
~ReadKeyboard(void);
ReadKeyboard(const char*);
Uint8 CharsBeforeCursor(); //Where should the cursor be placed?
- bool ReadKey(const SDL_keysym&);
- bool ReadKey(SDLKey); //true if key accepted
+ bool ReadKey(const SDL_Event&);
+ bool ReadKey(SDL_Keycode); //true if key accepted
const char* GetString(void);
};
diff --git a/source/code/common.cpp b/source/code/common.cpp
index 3525c37..f67e43e 100644
--- a/source/code/common.cpp
+++ b/source/code/common.cpp
@@ -49,6 +49,13 @@ bool strequals(const char* a, const char* b) {
return strcmp(a,b) == 0;
}
+void dieOnNullptr(bool ptr, const char* msg) {
+ if (!ptr) {
+ cerr << "Fatal error: " << msg << endl;
+ abort();
+ }
+}
+
/**
* str2double parses a string and returns a double with the value of the string.
* if the string is not a double then 0.0 is returned instead of throing an error
diff --git a/source/code/common.h b/source/code/common.h
index 01c5f4f..ca985c8 100644
--- a/source/code/common.h
+++ b/source/code/common.h
@@ -74,6 +74,8 @@ int str2int(const std::string &str2parse) __attribute__((const));
std::string double2str(double num) __attribute__((const));
+void dieOnNullptr(bool, const char* msg);
+
/**
* str2double parses a string and returns a double with the value of the string.
* if the string is not a double then 0.0 is returned instead of throing an error
diff --git a/source/code/global.hpp b/source/code/global.hpp
index 4f9e1c0..6a379d2 100644
--- a/source/code/global.hpp
+++ b/source/code/global.hpp
@@ -39,7 +39,7 @@ extern bool SoundEnabled; //true if sound effects is enabled
extern bool bFullscreen; //true if game is running fullscreen
extern std::string player1name;
extern std::string player2name;
-extern SDL_Surface *screen; //The whole screen;
+extern SDL_Renderer *screen; //The whole screen;
extern std::shared_ptr<CppSdl::CppSdlImageHolder> mouse;
extern SDL_Surface* backgroundImage;
extern bool highPriority;
diff --git a/source/code/main.cpp b/source/code/main.cpp
index 7e11d07..35af220 100644
--- a/source/code/main.cpp
+++ b/source/code/main.cpp
@@ -39,9 +39,6 @@ http://blockattack.sf.net
#define WITH_SDL 1
-//Macros to convert surfaces (ffor faster drawing)
-#define CONVERT(n) tmp = SDL_DisplayFormat(n); SDL_FreeSurface(n); n = tmp
-#define CONVERTA(n) tmp = SDL_DisplayFormatAlpha(n); SDL_FreeSurface(n); n = tmp
#include <iostream>
#include <stdlib.h>
@@ -214,7 +211,7 @@ void loadTheme(const string& themeName) {
}
-long NFont_OpenFont(NFont* target, const char* path,int ptsize, SDL_Color color, int style=TTF_STYLE_NORMAL) {
+long NFont_OpenFont(SDL_Renderer* dest, NFont* target, const char* path,int ptsize, SDL_Color color, int style=TTF_STYLE_NORMAL) {
if (!PHYSFS_exists(path)) {
cerr << "Error: File not in blockattack.data: " << path << endl;
return -1; //file doesn't exist
@@ -257,9 +254,9 @@ long NFont_OpenFont(NFont* target, const char* path,int ptsize, SDL_Color color,
TTF_Font* font;
font=TTF_OpenFontRW(rw, 1, ptsize);
- TTF_SetFontStyle(font,style);
+ TTF_SetFontStyle(font, style);
- target->load(font,color);
+ target->load(dest, font, color);
TTF_CloseFont(font); //Once loaded we don't care anymore!
@@ -305,7 +302,7 @@ Mix_Music* Mix_LoadMUS2(string path) {
return nullptr;
}
- Mix_Music* ret = Mix_LoadMUS_RW(rw);
+ Mix_Music* ret = Mix_LoadMUS_RW(rw, SDL_TRUE);
return ret;
}
@@ -456,71 +453,6 @@ static int InitImages() {
exit(1);
}
-
- //Prepare for fast blittering!
- CONVERT(background);
- CONVERT(backgroundImage);
- CONVERT(bOptions);
- CONVERTA(bConfigure);
- CONVERTA(bSelectPuzzle);
- CONVERTA(bSkip);
- CONVERTA(bRetry);
- CONVERTA(bNext);
- CONVERT(bHighScore);
- CONVERTA(boardBackBack);
- CONVERT(backBoard);
- CONVERT(blackLine);
- CONVERTA(changeButtonsBack);
- CONVERTA(cursor[0]);
- CONVERTA(cursor[1]);
- CONVERTA(counter[0]);
- CONVERTA(counter[1]);
- CONVERTA(counter[2]);
- CONVERT(bOn);
- CONVERT(bOff);
- CONVERT(b1024);
- CONVERTA(dialogBox);
-// CONVERTA(fileDialogBox);
- CONVERTA(iLevelCheck);
- CONVERT(iLevelCheckBox);
- CONVERT(iLevelCheckBoxMarked);
- CONVERTA(iCheckBoxArea);
- for (int i = 0; i<4; i++) {
- CONVERTA(explosion[i]);
- }
- for (int i = 0; i<7; i++) {
- CONVERTA(bricks[i]);
- CONVERTA(balls[i]);
- }
- CONVERTA(crossover);
- CONVERTA(garbageTL);
- CONVERTA(garbageT);
- CONVERTA(garbageTR);
- CONVERTA(garbageR);
- CONVERTA(garbageBR);
- CONVERTA(garbageB);
- CONVERTA(garbageBL);
- CONVERTA(garbageL);
- CONVERTA(garbageFill);
- CONVERTA(garbageML);
- CONVERTA(garbageMR);
- CONVERTA(garbageM);
- CONVERTA(garbageGML);
- CONVERTA(garbageGMR);
- CONVERTA(garbageGM);
- CONVERTA(smiley[0]);
- CONVERTA(smiley[1]);
- CONVERTA(smiley[2]);
- CONVERTA(smiley[3]);
- CONVERTA(iWinner);
- CONVERTA(iDraw);
- CONVERTA(iLoser);
- CONVERTA(iChainBack);
- CONVERTA(iGameOver);
- mouse->OptimizeForBlit(true);
- bNewGame->OptimizeForBlit(true);
- CONVERTA(stageBobble);
- CONVERTA(transCover);
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;
@@ -532,14 +464,11 @@ static int InitImages() {
nf_standard_small_color.b = 0;
nf_standard_small_color.g = 0;
nf_standard_small_color.r = 200;
- NFont_OpenFont(&nf_button_font,"fonts/FreeSerif.ttf",24,nf_button_color);
- nf_button_font.setDest(screen);
- NFont_OpenFont(&nf_standard_blue_font,"fonts/FreeSerif.ttf",30,nf_standard_blue_color);
- nf_standard_blue_font.setDest(screen);
- NFont_OpenFont(&nf_standard_small_font,"fonts/FreeSerif.ttf",16,nf_standard_small_color);
- nf_standard_small_font.setDest(screen);
- NFont_OpenFont(&nf_scoreboard_font,"fonts/PenguinAttack.ttf",20,nf_button_color);
- nf_scoreboard_font.setDest(boardBackBack);
+ NFont_OpenFont(screen, &nf_button_font,"fonts/FreeSerif.ttf",24,nf_button_color);
+ NFont_OpenFont(screen, &nf_standard_blue_font,"fonts/FreeSerif.ttf",30,nf_standard_blue_color);
+ NFont_OpenFont(screen, &nf_standard_small_font,"fonts/FreeSerif.ttf",16,nf_standard_small_color);
+ SDL_RendererHolder backbackRenderer();
+ NFont_OpenFont(screen, &nf_scoreboard_font,"fonts/PenguinAttack.ttf",20,nf_button_color); //should draw to boardBackBack
nf_scoreboard_font.draw(370,148,_("Score:") );
nf_scoreboard_font.draw(370,197,_("Time:") );
nf_scoreboard_font.draw(370,246,_("Chain:") );
@@ -2685,7 +2614,7 @@ int main(int argc, char* argv[]) {
NoSound = true; //Tries to stop all sound from playing/loading
}
- SDL_WM_SetCaption("Block Attack - Rise of the Blocks", nullptr); //Sets title line
+ //SDL_WM_SetCaption("Block Attack - Rise of the Blocks", nullptr); //Sets title line
if (verboseLevel) {
//Copyright notice:
@@ -2805,18 +2734,21 @@ int main(int argc, char* argv[]) {
}
+ // "Block Attack - Rise of the Blocks"
//Open video
+ int createWindowParams = 0;
if ((bFullscreen)&&(!singlePuzzle)) {
- screen=SDL_SetVideoMode(xsize,ysize,32,SDL_SWSURFACE|SDL_FULLSCREEN|SDL_ANYFORMAT);
- }
- else {
- screen=SDL_SetVideoMode(xsize,ysize,32,SDL_SWSURFACE|SDL_ANYFORMAT);
- }
-
- if ( screen == nullptr ) {
- cerr << "Unable to set " << xsize << "x" << ysize << " video: " << SDL_GetError() << endl;
- exit(1);
+ 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 );
+ dieOnNullptr(sdlWindow, "Unable to create window");
+ SDL_Renderer *renderer = SDL_CreateRenderer(sdlWindow, -1, 0);
+ dieOnNullptr(renderer, "Unable to create render");
//Init the file system abstraction layer
PHYSFS_init(argv[0]);
diff --git a/source/code/mainVars.hpp b/source/code/mainVars.hpp
index f0ad0c9..13d8066 100644
--- a/source/code/mainVars.hpp
+++ b/source/code/mainVars.hpp
@@ -54,7 +54,7 @@ static SDL_Surface *iChainBack;
static SDL_Surface *bHighScore; //The High Score botton
static SDL_Surface *blackLine; //The seperator in stage clear
static SDL_Surface *stageBobble; //The bobble instage clear
-SDL_Surface *screen; //The whole screen;
+SDL_Renderer *screen; //The whole screen;
static SDL_Surface *iGameOver; //The gameOver image
static SDL_Surface *iWinner; //the "winner" image
static SDL_Surface *iDraw; //the "draw" image
@@ -239,12 +239,12 @@ bool joyplay2=false; //Player two uses the joypad
//Stores the controls
struct control
{
- SDLKey up;
- SDLKey down;
- SDLKey left;
- SDLKey right;
- SDLKey change;
- SDLKey push;
+ SDL_Keycode up;
+ SDL_Keycode down;
+ SDL_Keycode left;
+ SDL_Keycode right;
+ SDL_Keycode change;
+ SDL_Keycode push;
};
control keySettings[3]; //array to hold the controls (default and two custom)
diff --git a/source/code/scopeHelpers.hpp b/source/code/scopeHelpers.hpp
index e96e5ea..2861469 100644
--- a/source/code/scopeHelpers.hpp
+++ b/source/code/scopeHelpers.hpp
@@ -24,20 +24,19 @@ http://www.blockattack.net
#ifndef SCOPEHELPERS_HPP
#define SCOPEHELPERS_HPP
-class SDLUnicodeScope {
-private:
- int oldStatus;
+#include "common.h"
+
+
+class SDL_RendererHolder {
+ SDL_Renderer* ptr;
public:
- SDLUnicodeScope() {
- oldStatus = SDL_EnableUNICODE(SDL_ENABLE);
- }
-
- void Release() {
- SDL_EnableUNICODE(oldStatus);
+ SDL_RendererHolder(SDL_Renderer* input) {
+ dieOnNullptr(input, "Failed to get render");
+ ptr = input;
}
- ~SDLUnicodeScope() {
- Release();
+ ~SDL_RendererHolder() {
+ SDL_DestroyRenderer(ptr);
}
};