diff --git a/src/defs.h b/src/defs.h index 63d491b..b8f71ad 100644 --- a/src/defs.h +++ b/src/defs.h @@ -53,7 +53,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define MAX_FONTS 64 #define NUM_TEXT_BUCKETS 64 -#define TEXT_TTL (1000 * 20) +#define NUM_GLYPH_BUCKETS 128 #define MAX_NAME_LENGTH 32 #define MAX_DESCRIPTION_LENGTH 512 diff --git a/src/entities/structures/pushBlock.h b/src/entities/structures/pushBlock.h index 0e29edb..f841176 100644 --- a/src/entities/structures/pushBlock.h +++ b/src/entities/structures/pushBlock.h @@ -28,4 +28,3 @@ extern void playBattleSound(int snd, int ch, int x, int y); extern int rrnd(int low, int high); extern Entity *self; -extern Game game; diff --git a/src/game/credits.c b/src/game/credits.c index 6fc8873..fdee4f4 100644 --- a/src/game/credits.c +++ b/src/game/credits.c @@ -103,7 +103,7 @@ static void draw(void) blitRectScaled(atlasTexture->texture, 0, app.config.winHeight - h, w, h, &background->rect, 0); - limitTextWidth(CREDIT_LINE_LIMIT); + app.textWidth = CREDIT_LINE_LIMIT; for (c = head.next ; c != NULL ; c = c->next) { @@ -113,7 +113,7 @@ static void draw(void) } } - limitTextWidth(0); + app.textWidth = 0; } static void loadCredits(void) @@ -126,7 +126,7 @@ static void loadCredits(void) text = readFile("data/misc/credits.txt"); - limitTextWidth(CREDIT_LINE_LIMIT); + app.textWidth = CREDIT_LINE_LIMIT; line = strtok_r(text, "\n", &saveptr); @@ -152,7 +152,7 @@ static void loadCredits(void) line = strtok_r(NULL, "\n", &saveptr); } - limitTextWidth(0); + app.textWidth = 0; /* the music that plays over the credits is 1m 55s, so scroll credits roughly inline with that (plus 2 seconds) */ if (isFromEnding) diff --git a/src/game/credits.h b/src/game/credits.h index d70b4d1..e1f3732 100644 --- a/src/game/credits.h +++ b/src/game/credits.h @@ -29,7 +29,6 @@ extern Atlas *getImageFromAtlas(char *filename); extern Texture *getTexture(const char *filename); extern int getWrappedTextHeight(const char *text, int size); extern void initTitle(void); -extern void limitTextWidth(int width); extern void loadMusic(char *filename); extern void playMusic(int loop); extern char *readFile(const char *filename); diff --git a/src/game/ending.c b/src/game/ending.c index 44a1cda..68231e5 100644 --- a/src/game/ending.c +++ b/src/game/ending.c @@ -94,11 +94,11 @@ static void draw(void) if (endingTimer > 0 && endingTextIndex < NUM_ENDING_LINES) { - limitTextWidth(SCREEN_WIDTH / 2); + app.textWidth = (SCREEN_WIDTH / 2); th = getWrappedTextHeight(endingText[endingTextIndex], 24) + 15; drawRect(0, SCREEN_HEIGHT - th - 10, SCREEN_WIDTH, th + 10, 0, 0, 0, 128); drawText(SCREEN_WIDTH / 2, SCREEN_HEIGHT - th, 24, TA_CENTER, colors.white, endingText[endingTextIndex]); - limitTextWidth(0); + app.textWidth = 0; } } diff --git a/src/game/ending.h b/src/game/ending.h index ab2c7a7..4d4b451 100644 --- a/src/game/ending.h +++ b/src/game/ending.h @@ -31,7 +31,6 @@ extern Atlas *getImageFromAtlas(char *filename); extern Texture *getTexture(const char *filename); extern int getWrappedTextHeight(const char *text, int size); extern void initCredits(int playMusic); -extern void limitTextWidth(int width); extern char *readFile(const char *filename); extern void startSectionTransition(void); diff --git a/src/game/options.h b/src/game/options.h index c5129d1..77fc43b 100644 --- a/src/game/options.h +++ b/src/game/options.h @@ -35,11 +35,11 @@ extern void endSectionTransition(void); extern Atlas *getImageFromAtlas(char *filename); extern Texture *getTexture(const char *filename); extern Widget *getWidget(char *name, char *group); +extern void initBackground(void); extern void playSound(int snd, int ch); extern void saveConfig(void); extern void showWidgetGroup(char *group); extern void startSectionTransition(void); -extern void initBackground(void); extern App app; extern Colors colors; diff --git a/src/game/trophies.c b/src/game/trophies.c index 11ee6ab..3054298 100644 --- a/src/game/trophies.c +++ b/src/game/trophies.c @@ -295,8 +295,8 @@ static void nextAlert(void) { playSound(SND_TROPHY, -1); - textSize(alertTrophy->title, 30, &alertRect.w, &h); - textSize(alertTrophy->description, 20, &w, &h); + calcTextDimensions(alertTrophy->title, 30, &alertRect.w, &h); + calcTextDimensions(alertTrophy->description, 20, &w, &h); alertRect.w = MAX(alertRect.w, w); alertRect.w = MAX(400, alertRect.w); diff --git a/src/game/trophies.h b/src/game/trophies.h index 5d3b36a..4da93aa 100644 --- a/src/game/trophies.h +++ b/src/game/trophies.h @@ -27,6 +27,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. extern void blitRect(SDL_Texture *texture, int x, int y, SDL_Rect *srcRect, int center); extern void blitRectRotated(SDL_Texture *texture, int x, int y, SDL_Rect *srcRect, float angle); extern void blitRectScaled(SDL_Texture *texture, int x, int y, int w, int h, SDL_Rect *srcRect, int center); +extern void calcTextDimensions(char *text, int size, int *w, int *h); extern void clearControl(int type); extern void doWidgets(void); extern void drawOutlineRect(int x, int y, int w, int h, int r, int g, int b, int a); @@ -41,7 +42,6 @@ extern long lookup(const char *name); extern float mod(float n, float x); extern void playSound(int snd, int ch); extern char *readFile(const char *filename); -extern void textSize(char *text, int size, int *w, int *h); extern char *timeToDate(long millis); extern App app; diff --git a/src/hub/hub.c b/src/hub/hub.c index d668436..015edae 100644 --- a/src/hub/hub.c +++ b/src/hub/hub.c @@ -506,9 +506,9 @@ static void drawMissionInfo(void) drawText(UI_WIDTH / 2, y + 25, 32, TA_CENTER, colors.white, selectedMission->name); - limitTextWidth(w - 150); + app.textWidth = (w - 150); drawText(x + 15, y + 100, 22, TA_LEFT, colors.white, selectedMission->description); - limitTextWidth(0); + app.textWidth = 0; size = 65; mid = size / 2; diff --git a/src/hub/hub.h b/src/hub/hub.h index 565c988..a431111 100644 --- a/src/hub/hub.h +++ b/src/hub/hub.h @@ -61,7 +61,6 @@ extern void initStatsDisplay(void); extern void initTitle(void); extern void initWorld(void); extern int isControl(int type); -extern void limitTextWidth(int width); extern void loadMusic(char *filename); extern void playMusic(int loop); extern void playSound(int snd, int ch); diff --git a/src/main.c b/src/main.c index 892ebdc..404effd 100644 --- a/src/main.c +++ b/src/main.c @@ -48,6 +48,8 @@ int main(int argc, char *argv[]) frames = 0; + remainder = 0; + nextSecond = SDL_GetTicks() + 1000; while (1) @@ -84,8 +86,6 @@ int main(int argc, char *argv[]) awardTrophies(); - expireTexts(0); - if (dev.takeScreenshots) { saveScreenshot(NULL); diff --git a/src/main.h b/src/main.h index 62cfeda..74d2e69 100644 --- a/src/main.h +++ b/src/main.h @@ -23,22 +23,21 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. extern void awardTrophies(void); extern void cleanup(void); +extern void createScreenshotFolder(void); extern void doTrophyAlerts(void); extern void drawTrophyAlert(void); -extern void expireTexts(int all); extern void handleInput(void); extern void init18N(int argc, char *argv[]); +extern void initCredits(void); +extern void initEnding(void); extern void initGameSystem(void); extern void initLookups(void); extern void initSDL(void); +extern void initTitle(void); extern void initWorldTest(char *worldId); -extern void initEnding(void); -extern void initCredits(void); extern void prepareScene(void); extern void presentScene(void); extern void saveScreenshot(char *name); -extern void initTitle(void); -extern void createScreenshotFolder(void); App app; Camera camera; diff --git a/src/structs.h b/src/structs.h index 189035f..d958778 100644 --- a/src/structs.h +++ b/src/structs.h @@ -35,6 +35,8 @@ typedef struct EntityDef EntityDef; typedef struct Trophy Trophy; typedef struct cJSON cJSON; typedef struct Credit Credit; +typedef struct Font Font; +typedef struct Glyph Glyph; typedef struct Entity Entity; typedef struct EntityExt EntityExt; @@ -67,7 +69,6 @@ typedef struct { struct Texture { char name[MAX_DESCRIPTION_LENGTH]; long hash; - long ttl; SDL_Texture *texture; Texture *next; }; @@ -355,6 +356,7 @@ typedef struct { int restrictTrophyAlert; char *strings[ST_MAX]; Config config; + int textWidth; } App; typedef struct { @@ -517,6 +519,19 @@ struct Credit { Credit *next; }; +struct Glyph { + char character[MAX_NAME_LENGTH]; + SDL_Rect rect; + Glyph *next; +}; + +struct Font { + char name[MAX_NAME_LENGTH]; + SDL_Texture *texture; + Glyph glyphHead[NUM_GLYPH_BUCKETS]; + Font *next; +}; + /* ===== i18n stuff ==== */ struct Bucket { diff --git a/src/system/init.c b/src/system/init.c index b466a9c..0795a9a 100644 --- a/src/system/init.c +++ b/src/system/init.c @@ -284,6 +284,10 @@ static void loadConfig(void) free(text); } + /* don't go higher than 8K or lower than 1280 x 720 */ + app.config.winWidth = MIN(MAX(app.config.winWidth, 1280), 7680); + app.config.winHeight = MIN(MAX(app.config.winHeight, 720), 4320); + free(filename); } @@ -347,15 +351,12 @@ void cleanup(void) destroyLookups(); - destroyFonts(); - destroyTextures(); - expireTexts(1); - destroyGame(); - if (app.joypad != NULL) { + if (app.joypad != NULL) + { SDL_JoystickClose(app.joypad); } diff --git a/src/system/init.h b/src/system/init.h index c9c88da..d32a4ec 100644 --- a/src/system/init.h +++ b/src/system/init.h @@ -29,11 +29,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. extern char *buildFormattedString(const char *format, ...); extern void createSaveFolder(void); -extern void destroyFonts(void); extern void destroyGame(void); extern void destroyLookups(void); extern void destroyTextures(void); -extern void expireTexts(int all); extern int fileExists(const char *filename); extern char *getLookupName(const char *prefix, long num); extern void initAtlas(void); diff --git a/src/system/savepng.h b/src/system/savepng.h index 796fe7d..2aa9342 100644 --- a/src/system/savepng.h +++ b/src/system/savepng.h @@ -17,7 +17,6 @@ extern "C" { /* This helps CPP projects that include this header */ * Returns 0 success or -1 on failure, the error message is then retrievable * via SDL_GetError(). */ -#define SDL_SavePNG(surface, file) \ SDL_SavePNG_RW(surface, SDL_RWFromFile(file, "wb"), 1) /* @@ -30,15 +29,19 @@ extern "C" { /* This helps CPP projects that include this header */ * Returns 0 success or -1 on failure, the error message is then retrievable * via SDL_GetError(). */ -extern int SDL_SavePNG_RW(SDL_Surface *surface, SDL_RWops *rw, int freedst); /* * Return new SDL_Surface with a format suitable for PNG output. */ -extern SDL_Surface *SDL_PNGFormatAlpha(SDL_Surface *src); #ifdef __cplusplus } /* extern "C" */ #endif #endif + +#define SDL_SavePNG(surface, file) \ + +extern SDL_Surface *SDL_PNGFormatAlpha(SDL_Surface *src); +extern int SDL_SavePNG_RW(SDL_Surface *surface, SDL_RWops *rw, int freedst); +#define SDL_SavePNG(surface, file) \ diff --git a/src/system/text.c b/src/system/text.c index 1ad2e39..4cc7bad 100644 --- a/src/system/text.c +++ b/src/system/text.c @@ -20,295 +20,401 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "text.h" -static void loadFont(int size); -static SDL_Texture *getCachedText(unsigned long hash); -static void cacheText(unsigned long hash, SDL_Texture *t); -static void drawTextNormal(int x, int y, int size, int align, SDL_Color c, const char *text); -static void drawTextSplit(int x, int y, int size, int align, SDL_Color c, char *text); -void textSize(const char *text, int size, int *w, int *h); +static void initFont(char *name, char *filename); +static void drawWord(char *word, int *x, int *y, int startX); +static void drawTextLines(int x, int y, int size, int align, SDL_Color color); +static void drawTextLine(int x, int y, int size, int align, SDL_Color color, const char *line); +void calcTextDimensions(const char *text, int size, int *w, int *h); +void useFont(char *name); +static void initChars(Font *f); +static char *nextCharacter(const char *str, int *i); +static Glyph *findGlyph(char *c); -static char drawTextBuffer[MAX_LINE_LENGTH]; -static TTF_Font *font[MAX_FONTS]; -static Texture textures[NUM_TEXT_BUCKETS]; -static int maxWidth = 0; -static int cacheSize = 0; -static int textShadow = 1; -static SDL_Color textShadowColor; +static SDL_Color white = {255, 255, 255, 255}; +static char drawTextBuffer[1024]; +static Font fontHead; +static Font *fontTail; +static Font *activeFont = NULL; +static float scale; void initFonts(void) { - memset(&font, 0, sizeof(TTF_Font*) * MAX_FONTS); - memset(&textures, 0, sizeof(Texture) * NUM_TEXT_BUCKETS); + memset(&fontHead, 0, sizeof(Font)); + fontTail = &fontHead; + + initFont("roboto", getFileLocation("gfx/fonts/Roboto-Medium.ttf")); + + useFont("roboto"); } -void drawText(int x, int y, int size, int align, SDL_Color c, const char *format, ...) +static void initFont(char *name, char *filename) +{ + SDL_Texture *texture; + TTF_Font *font; + Font *f; + SDL_Surface *surface, *text; + SDL_Rect dest; + Glyph *g; + int i; + + f = malloc(sizeof(Font)); + memset(f, 0, sizeof(Font)); + + font = TTF_OpenFont(filename, FONT_SIZE); + + initChars(f); + + surface = SDL_CreateRGBSurface(0, FONT_TEXTURE_SIZE, FONT_TEXTURE_SIZE, 32, 0, 0, 0, 0xff); + + SDL_SetColorKey(surface, SDL_TRUE, SDL_MapRGBA(surface->format, 0, 0, 0, 0)); + + dest.x = dest.y = 0; + + for (i = 0 ; i < NUM_GLYPH_BUCKETS ; i++) + { + for (g = f->glyphHead[i].next ; g != NULL ; g = g->next) + { + text = TTF_RenderUTF8_Blended(font, g->character, white); + + TTF_SizeText(font, g->character, &dest.w, &dest.h); + + if (dest.x + dest.w >= FONT_TEXTURE_SIZE) + { + dest.x = 0; + + dest.y += dest.h + 1; + + if (dest.y + dest.h >= FONT_TEXTURE_SIZE) + { + SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_CRITICAL, "Out of glyph space in %dx%d font atlas texture map.", FONT_TEXTURE_SIZE, FONT_TEXTURE_SIZE); + exit(1); + } + } + + SDL_BlitSurface(text, NULL, surface, &dest); + + g->rect = dest; + + SDL_FreeSurface(text); + + dest.x += dest.w; + } + } + + TTF_CloseFont(font); + + texture = toTexture(surface, 1); + + f->texture = texture; + + strcpy(f->name, name); + + fontTail->next = f; + fontTail = f; +} + +static void initChars(Font *f) +{ + char *characters, *character; + Glyph *g, *glyphTail; + int i, bucket; + + characters = readFile("data/locale/characters.dat"); + + i = 0; + + character = nextCharacter(characters, &i); + + while (character) + { + bucket = hashcode(character) % NUM_GLYPH_BUCKETS; + + glyphTail = &f->glyphHead[bucket]; + + /* horrible bit to look for the tail */ + while (glyphTail->next) + { + glyphTail = glyphTail->next; + } + + g = malloc(sizeof(Glyph)); + memset(g, 0, sizeof(Glyph)); + glyphTail->next = g; + glyphTail = g; + + STRNCPY(g->character, character, MAX_NAME_LENGTH); + + character = nextCharacter(characters, &i); + } + + free(characters); +} + +void drawText(int x, int y, int size, int align, SDL_Color color, const char *format, ...) { va_list args; - - memset(&drawTextBuffer, '\0', sizeof(drawTextBuffer)); - - va_start(args, format); - vsprintf(drawTextBuffer, format, args); - va_end(args); - if (maxWidth == 0) + if (activeFont) { - drawTextNormal(x, y, size, align, c, drawTextBuffer); - } - else - { - drawTextSplit(x, y, size, align, c, drawTextBuffer); + SDL_SetTextureColorMod(activeFont->texture, color.r, color.g, color.b); + SDL_SetTextureAlphaMod(activeFont->texture, color.a); + + memset(&drawTextBuffer, '\0', sizeof(drawTextBuffer)); + + va_start(args, format); + vsprintf(drawTextBuffer, format, args); + va_end(args); + + if (app.textWidth == 0) + { + drawTextLine(x, y, size, align, color, drawTextBuffer); + } + else + { + drawTextLines(x, y, size, align, color); + } } } -static void drawTextNormal(int x, int y, int size, int align, SDL_Color c, const char *text) +static void drawTextLines(int x, int y, int size, int align, SDL_Color color) { - SDL_Surface *surface; - SDL_Texture *t; - int w, h; - long hash; + char line[MAX_LINE_LENGTH], token[MAX_WORD_LENGTH]; + int i, n, w, h, currentWidth, len; - if (size >= MAX_FONTS) - { - SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_CRITICAL, "ERROR: %d exceeds max font size index of %d\n", size, MAX_FONTS); - exit(1); - } + memset(&line, '\0', sizeof(line)); + memset(&token, '\0', sizeof(token)); - if (!font[size]) + len = strlen(drawTextBuffer); + + n = currentWidth = 0; + + for (i = 0 ; i < len ; i++) { - loadFont(size); - } - - hash = hashcode(text) + size; - - t = getCachedText(hash); - - if (!t) - { - surface = TTF_RenderText_Blended(font[size], text, colors.white); - t = SDL_CreateTextureFromSurface(app.renderer, surface); - SDL_FreeSurface(surface); + token[n++] = drawTextBuffer[i]; - cacheText(hash, t); + if (drawTextBuffer[i] == ' ' || i == len - 1) + { + calcTextDimensions(token, size, &w, &h); + + if (currentWidth + w > app.textWidth) + { + drawTextLine(x, y, size, align, color, line); + + currentWidth = 0; + + y += h; + + memset(&line, '\0', sizeof(line)); + } + + strcat(line, token); + + n = 0; + + memset(&token, '\0', sizeof(token)); + + currentWidth += w; + } } + + drawTextLine(x, y, size, align, color, line); +} - SDL_QueryTexture(t, NULL, NULL, &w, &h); - - if (align == TA_CENTER) - { - x -= (w / 2); - } - else if (align == TA_RIGHT) +static void drawTextLine(int x, int y, int size, int align, SDL_Color color, const char *line) +{ + int i, startX, n, w, h; + char word[MAX_WORD_LENGTH]; + + scale = size / (FONT_SIZE * 1.0f); + + startX = x; + + memset(word, 0, MAX_WORD_LENGTH); + + n = 0; + + calcTextDimensions(line, size, &w, &h); + + if (align == TA_RIGHT) { x -= w; } - - if (textShadow) + else if (align == TA_CENTER) { - SDL_SetTextureColorMod(t, textShadowColor.r, textShadowColor.g, textShadowColor.b); - - blit(t, x + 1, y + 1, 0); - blit(t, x + 2, y + 2, 0); + x -= (w / 2); } - SDL_SetTextureColorMod(t, c.r, c.g, c.b); - - blit(t, x, y, 0); -} - -static void drawTextSplit(int x, int y, int size, int align, SDL_Color c, char *text) -{ - char drawTextBuffer[MAX_DESCRIPTION_LENGTH]; - char *token; - int w, h, currentWidth; - - memset(&drawTextBuffer, '\0', sizeof(drawTextBuffer)); - - token = strtok(text, " "); - - currentWidth = 0; - - while (token) + for (i = 0 ; i < strlen(line) ; i++) { - textSize(token, size, &w, &h); + word[n++] = line[i]; - if (currentWidth + w > maxWidth) + if (line[i] == ' ') { - drawTextNormal(x, y, size, align, c, drawTextBuffer); + drawWord(word, &x, &y, startX); - currentWidth = 0; - y += h; - memset(&drawTextBuffer, '\0', sizeof(drawTextBuffer)); + memset(word, 0, MAX_WORD_LENGTH); + + n = 0; } - - strcat(drawTextBuffer, token); - strcat(drawTextBuffer, " "); - - currentWidth += w; - - token = strtok(NULL, " "); } - drawTextNormal(x, y, size, align, c, drawTextBuffer); + drawWord(word, &x, &y, startX); } -int getWrappedTextHeight(const char *text, int size) +static void drawWord(char *word, int *x, int *y, int startX) { - char textBuffer[MAX_DESCRIPTION_LENGTH]; - char *token; - int w, h, currentWidth; - int y; + int i; + char *character; + SDL_Rect dest; + Glyph *g; - STRNCPY(textBuffer, text, MAX_DESCRIPTION_LENGTH); + i = 0; - token = strtok(textBuffer, " "); + character = nextCharacter(word, &i); - y = 0; - currentWidth = 0; - - while (token) + while (character) { - textSize(token, size, &w, &h); + g = findGlyph(character); - if (currentWidth + w > maxWidth) + dest.x = *x; + dest.y = *y; + dest.w = g->rect.w * scale; + dest.h = g->rect.h * scale; + + SDL_RenderCopy(app.renderer, activeFont->texture, &g->rect, &dest); + + *x += g->rect.w * scale; + + character = nextCharacter(word, &i); + } +} + +static Glyph *findGlyph(char *c) +{ + Glyph *g; + int bucket; + + bucket = hashcode(c) % NUM_GLYPH_BUCKETS; + + for (g = activeFont->glyphHead[bucket].next ; g != NULL ; g = g->next) + { + if (strcmp(g->character, c) == 0) { - currentWidth = 0; - y += h; + return g; } + } + + SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_CRITICAL, "Couldn't find glyph for '%s'", c); + exit(1); + + return NULL; +} + +void useFont(char *name) +{ + Font *f; + + for (f = fontHead.next ; f != NULL ; f = f->next) + { + if (strcmp(f->name, name) == 0) + { + activeFont = f; + return; + } + } +} + +void calcTextDimensions(const char *text, int size, int *w, int *h) +{ + float scale; + int i; + char *character; + Glyph *g; + + scale = size / (FONT_SIZE * 1.0f); + + *w = 0; + *h = 0; + + i = 0; + + character = nextCharacter(text, &i); + + while (character) + { + g = findGlyph(character); - currentWidth += w; + *w += g->rect.w * scale; + *h = MAX(g->rect.h * scale, *h); - token = strtok(NULL, " "); + character = nextCharacter(text, &i); + } +} + +int getWrappedTextHeight(char *text, int size) +{ + char word[MAX_WORD_LENGTH]; + int i, y, n, w, h, currentWidth, len; + + STRNCPY(drawTextBuffer, text, MAX_LINE_LENGTH); + + n = 0; + y = 0; + h = 0; + currentWidth = 0; + len = strlen(drawTextBuffer); + memset(word, 0, MAX_WORD_LENGTH); + + for (i = 0 ; i < len ; i++) + { + word[n++] = drawTextBuffer[i]; + + if (drawTextBuffer[i] == ' ' || i == len - 1) + { + calcTextDimensions(word, size, &w, &h); + + if (currentWidth + w > app.textWidth) + { + currentWidth = 0; + y += h; + } + + currentWidth += w; + + memset(word, 0, MAX_WORD_LENGTH); + + n = 0; + } } return y + h; } -void textSize(const char *text, int size, int *w, int *h) +static char *nextCharacter(const char *str, int *i) { - if (!font[size]) - { - loadFont(size); - } + static char character[MAX_NAME_LENGTH]; - TTF_SizeText(font[size], text, w, h); -} - -void limitTextWidth(int width) -{ - maxWidth = width; -} - -void useTextShadow(int enable, int r, int g, int b) -{ - textShadow = 1; - textShadowColor.r = r; - textShadowColor.g = g; - textShadowColor.b = b; -} - -static SDL_Texture *getCachedText(unsigned long hash) -{ - Texture *t; - int i; - - i = hash % NUM_TEXT_BUCKETS; - - t = textures[i].next; - - for (t = textures[i].next ; t != NULL ; t = t->next) - { - if (t->hash == hash) - { - t->ttl = SDL_GetTicks() + TEXT_TTL; - return t->texture; - } - } - - return NULL; -} - -static void cacheText(unsigned long hash, SDL_Texture *texture) -{ - Texture *t, *new; - int i; - - i = hash % NUM_TEXT_BUCKETS; - - t = &textures[i]; - - /* horrible bit to find the tail */ - while (t->next) - { - t = t->next; - } - - new = malloc(sizeof(Texture)); - memset(new, 0, sizeof(Texture)); - - new->hash = hash; - new->texture = texture; - new->ttl = SDL_GetTicks() + TEXT_TTL; - - t->next = new; + unsigned char bit; + int n; - cacheSize++; -} - -void expireTexts(int all) -{ - Texture *t, *prev; - int i, n; - long now; + memset(character, '\0', MAX_NAME_LENGTH); n = 0; - now = SDL_GetTicks(); - - for (i = 0 ; i < NUM_TEXT_BUCKETS ; i++) + + while (1) { - prev = &textures[i]; + bit = (unsigned char)str[*i]; - for (t = textures[i].next ; t != NULL ; t = t->next) + if ((bit >= ' ' && bit <= '~') || bit >= 0xC0 || bit == '\0') { - if (t->ttl <= now || all) + if (n > 0) { - prev->next = t->next; - SDL_DestroyTexture(t->texture); - free(t); - - cacheSize--; - - n++; - - t = prev; + return character[0] != '\0' ? character : NULL; } - - prev = t; - } - } - - if (all && n > 0) - { - SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_DEBUG, "Expired %d texts", n); - } -} - -static void loadFont(int size) -{ - SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, "loadFonts(%d)", size); - - font[size] = TTF_OpenFont(getFileLocation("gfx/fonts/Roboto-Medium.ttf"), size); -} - -void destroyFonts(void) -{ - int i; - - for (i = 0 ; i < MAX_FONTS ; i++) - { - if (font[i]) - { - TTF_CloseFont(font[i]); } + + character[n++] = str[*i]; + + *i = *i + 1; } } diff --git a/src/system/text.h b/src/system/text.h index 663a84d..6777ba4 100644 --- a/src/system/text.h +++ b/src/system/text.h @@ -18,13 +18,21 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ -#include "../common.h" +#include "stdlib.h" +#include "string.h" +#include "SDL2/SDL_image.h" #include "SDL2/SDL_ttf.h" -extern void blit(SDL_Texture *texture, int x, int y, int centered); -extern char *getFileLocation(const char *filename); +#include "../common.h" + +#define FONT_SIZE 32 +#define FONT_TEXTURE_SIZE 512 +#define MAX_WORD_LENGTH 128 + +extern char *getFileLocation(char *filename); extern unsigned long hashcode(const char *str); +extern char *readFile(char *filename); +extern SDL_Texture *toTexture(SDL_Surface *surface, int destroySurface); extern App app; -extern Colors colors; diff --git a/src/system/textures.c b/src/system/textures.c index ae091df..bc5e964 100644 --- a/src/system/textures.c +++ b/src/system/textures.c @@ -88,6 +88,20 @@ Texture *getTexture(const char *filename) return loadTexture(filename); } +SDL_Texture *toTexture(SDL_Surface *surface, int destroySurface) +{ + SDL_Texture *texture; + + texture = SDL_CreateTextureFromSurface(app.renderer, surface); + + if (destroySurface) + { + SDL_FreeSurface(surface); + } + + return texture; +} + void destroyTextures(void) { Texture *t, *next; diff --git a/src/system/transition.c b/src/system/transition.c index 362e61a..b88f0a9 100644 --- a/src/system/transition.c +++ b/src/system/transition.c @@ -31,8 +31,6 @@ void startSectionTransition(void) clearInput(); presentScene(); - - expireTexts(1); } void endSectionTransition(void) diff --git a/src/system/transition.h b/src/system/transition.h index 7396d6e..fd3be65 100644 --- a/src/system/transition.h +++ b/src/system/transition.h @@ -21,6 +21,5 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "../common.h" extern void clearInput(void); -extern void expireTexts(int all); extern void prepareScene(void); extern void presentScene(void); diff --git a/src/system/widgets.c b/src/system/widgets.c index 72980a4..835f489 100644 --- a/src/system/widgets.c +++ b/src/system/widgets.c @@ -188,7 +188,7 @@ void drawWidgets(void) x = w->x + w->w + 25; for (j = 0 ; j < w->numOptions ; j++) { - textSize(w->options[j], 24, &tw, &th); + calcTextDimensions(w->options[j], 24, &tw, &th); tw += 25; diff --git a/src/system/widgets.h b/src/system/widgets.h index 7917820..57b74b8 100644 --- a/src/system/widgets.h +++ b/src/system/widgets.h @@ -23,6 +23,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define MAX_WIDGETS 64 +extern void calcTextDimensions(const char *text, int size, int *w, int *h); extern void clearControl(int type); extern int collision(int x1, int y1, int w1, int h1, int x2, int y2, int w2, int h2); extern void drawOutlineRect(int x, int y, int w, int h, int r, int g, int b, int a); @@ -36,7 +37,6 @@ extern float limit(float i, float a, float b); extern long lookup(const char *name); extern void playSound(int snd, int ch); extern char *readFile(const char *filename); -extern void textSize(const char *text, int size, int *w, int *h); extern App app; extern Colors colors; diff --git a/src/world/hud.c b/src/world/hud.c index f626e7b..ee0b39a 100644 --- a/src/world/hud.c +++ b/src/world/hud.c @@ -95,12 +95,12 @@ void drawHud(void) if (infoMessageTime > 0) { - limitTextWidth(500); + app.textWidth = 500; h = getWrappedTextHeight(infoMessage, 20) + 20; drawRect((app.config.winWidth / 2) - 300, 40, 600, h, 0, 0, 0, 168); drawOutlineRect((app.config.winWidth / 2) - 300, 40, 600, h, 192, 192, 192, 255); drawText(app.config.winWidth / 2, 50, 20, TA_CENTER, colors.white, infoMessage); - limitTextWidth(0); + app.textWidth = 0; } if (dev.debug) diff --git a/src/world/hud.h b/src/world/hud.h index 20d3e55..13745ba 100644 --- a/src/world/hud.h +++ b/src/world/hud.h @@ -20,8 +20,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "../common.h" -const char *getWeaponName(int i); - extern void blitRect(SDL_Texture *texture, int x, int y, SDL_Rect *srcRect, int center); extern void blitRectScaled(SDL_Texture *texture, int x, int y, int w, int h, SDL_Rect *srcRect, int center); extern void drawOutlineRect(int x, int y, int w, int h, int r, int g, int b, int a); @@ -31,8 +29,8 @@ extern SDL_Rect *getCurrentFrame(Sprite *s); extern Atlas *getImageFromAtlas(char *filename); extern int getPercent(float current, float total); extern Texture *getTexture(const char *filename); +const char *getWeaponName(int i); extern int getWrappedTextHeight(const char *text, int size); -extern void limitTextWidth(int width); extern App app; extern Camera camera; diff --git a/src/world/world.c b/src/world/world.c index 789e792..b2cd0c7 100644 --- a/src/world/world.c +++ b/src/world/world.c @@ -809,7 +809,7 @@ void drawQuit(void) drawOutlineRect(r.x, r.y, r.w, r.h, 200, 200, 200, 255); - limitTextWidth(r.w - 100); + app.textWidth = (r.w - 100); drawText(UI_WIDTH / 2, r.y + 10, 26, TA_CENTER, colors.white, app.strings[ST_QUIT_HUB]); if (world.missionType == MT_TRAINING) @@ -829,7 +829,7 @@ void drawQuit(void) drawText(UI_WIDTH / 2, r.y + 65, 26, TA_CENTER, colors.white, app.strings[ST_QUIT_LOSE]); } - limitTextWidth(0); + app.textWidth = 0; drawWidgets(); diff --git a/src/world/world.h b/src/world/world.h index e46818a..504894f 100644 --- a/src/world/world.h +++ b/src/world/world.h @@ -100,7 +100,6 @@ extern int isOnScreen(Entity *e); extern int isSolid(int x, int y); extern int isWalkable(int x, int y); extern float limit(float i, float a, float b); -extern void limitTextWidth(int width); extern void loadMusic(char *filename); extern void loadWorld(char *id); extern void pauseSound(int pause); diff --git a/tools/tidyHeaders.sh b/tools/tidyHeaders.sh index f834297..d792edc 100755 --- a/tools/tidyHeaders.sh +++ b/tools/tidyHeaders.sh @@ -84,6 +84,7 @@ function cleanHeader($headerFile) { $header = file($headerFile); $body = file_get_contents($bodyFile); + $isMain = strpos($body, "int main(int argc, char *argv[])"); $lines = []; $defines = []; $functions = []; @@ -94,7 +95,7 @@ function cleanHeader($headerFile) foreach ($header as $line) { - if (preg_match("/extern|define/", $line) && strstr($line, "getTranslatedString") === FALSE) + if ((preg_match("/extern|define/", $line) || preg_match("/;$/", $line))) { preg_match($func_pattern, $line, $matches); @@ -104,7 +105,7 @@ function cleanHeader($headerFile) $extern = $matches[2]; - if (!preg_match_all("/\b[(]?${extern}[\\(;,)\\n]/", $body)) + if (!preg_match_all("/\b${extern}\b/", $body)) { if (!$hasChanges) { @@ -129,14 +130,21 @@ function cleanHeader($headerFile) $externs[] = $extern; - if (!preg_match_all("/\b${extern}([\\.\\-\\);]| =)/", $body)) + if (!$isMain) { - if (!$hasChanges) + if (!preg_match_all("/\b${extern}\b/", $body)) { - echo "$headerFile\n"; - $hasChanges = true; + if (!$hasChanges) + { + echo "$headerFile\n"; + $hasChanges = true; + } + echo "\t- $line"; + } + else if (!in_array($line, $lines)) + { + $structs[] = $line; } - echo "\t- $line"; } else if (!in_array($line, $lines)) { @@ -185,6 +193,10 @@ function cleanHeader($headerFile) } while ($wasBlank); + $defines = array_unique($defines); + $functions = array_unique($functions); + $structs = array_unique($structs); + $header = updateExterns($header, $defines, $functions, $structs); if ($UPDATE_FILES) @@ -206,7 +218,7 @@ function recurseDir($dir) { recurseDir("$dir/$file"); } - else if (strstr($file, ".h") !== FALSE && strstr($file, "main.h") === FALSE && strstr($file, "savepng") === FALSE) + else if (strstr($file, ".h") !== FALSE && $file != 'i18n.h') { cleanHeader("$dir/$file"); }