Maelstrom: Preallocate the fonts up front, and free them when we're all done.

From 78c2fec5916b1260d1ecfb2f93a97c079ea8def4 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Fri, 21 Oct 2011 23:44:08 -0400
Subject: [PATCH] Preallocate the fonts up front, and free them when we're all
 done.

---
 Maelstrom_Globals.h     |  8 ++++++
 controls.cpp            | 19 ++++----------
 init.cpp                | 30 +++++++++++++++-------
 maclib/Mac_FontServ.cpp | 35 +-------------------------
 maclib/Mac_FontServ.h   |  6 -----
 main.cpp                | 55 +++++++++--------------------------------
 netlogic/about.cpp      |  8 +-----
 netlogic/game.cpp       | 23 +++--------------
 scores.cpp              | 14 ++---------
 9 files changed, 53 insertions(+), 145 deletions(-)

diff --git a/Maelstrom_Globals.h b/Maelstrom_Globals.h
index a4694bce..ee90ee24 100644
--- a/Maelstrom_Globals.h
+++ b/Maelstrom_Globals.h
@@ -17,6 +17,14 @@
 
 // The Font Server :)
 extern FontServ *fontserv;
+enum {
+	CHICAGO_12,
+	GENEVA_9,
+	NEWYORK_14,
+	NEWYORK_18,
+	NUM_FONTS
+};
+extern MFont *fonts[NUM_FONTS];
 
 // The Sound Server *grin*
 extern Sound *sound;
diff --git a/controls.cpp b/controls.cpp
index 73ad84a9..9e31f34f 100644
--- a/controls.cpp
+++ b/controls.cpp
@@ -164,7 +164,6 @@ static struct {
 
 static int X=0;
 static int Y=0;
-static MFont *chicago;
 static SDL_Texture *keynames[NUM_CTLS];
 static int currentbox, valid;
 
@@ -196,7 +195,7 @@ static void BoxKeyPress(const SDL_Keysym &key, int *doneflag)
 			/* Blit the new message */
 			strcpy(keyname, "That key is in use!");
 			keynames[currentbox] = fontserv->TextImage(keyname,
-					chicago, STYLE_NORM, 0x00, 0x00, 0x00);
+					fonts[CHICAGO_12], STYLE_NORM, 0x00, 0x00, 0x00);
 			screen->QueueBlit(
 				X+96+(BOX_WIDTH-screen->GetImageWidth(keynames[currentbox]))/2, 
 				Y+75+SP+checkboxes[currentbox].yoffset,
@@ -214,7 +213,7 @@ static void BoxKeyPress(const SDL_Keysym &key, int *doneflag)
 	*checkboxes[currentbox].control = sym;
 	KeyName(*checkboxes[currentbox].control, keyname);
 	keynames[currentbox] = fontserv->TextImage(keyname,
-					chicago, STYLE_NORM, 0x00, 0x00, 0x00);
+					fonts[CHICAGO_12], STYLE_NORM, 0x00, 0x00, 0x00);
 	screen->QueueBlit(X+96+(BOX_WIDTH-screen->GetImageWidth(keynames[currentbox]))/2, 
 				Y+75+SP+checkboxes[currentbox].yoffset,
 						keynames[currentbox], NOCLIP);
@@ -230,6 +229,7 @@ void ConfigureControls(void)
 		"ESC aborts the game.";
 	SDL_Texture *text1, *text2;
 #endif
+	MFont *chicago;
 	Uint32 black;
 	int i;
 	char keyname[128];
@@ -242,13 +242,9 @@ void ConfigureControls(void)
 
 	/* Set up all the components of the dialog box */
 	black = screen->MapRGB(0x00, 0x00, 0x00);
-	if ( (chicago = fontserv->NewFont("Chicago", 12)) == NULL ) {
-		error("Can't use Chicago font!\n");
-		return;
-	}
+	chicago = fonts[CHICAGO_12];
 	if ( (splash = Load_Title(screen, 100)) == NULL ) {
 		error("Can't load configuration splash!\n");
-		fontserv->FreeFont(chicago);
 		return;
 	}
 	X=(SCREEN_WIDTH-CTL_DIALOG_WIDTH)/2;
@@ -310,7 +306,6 @@ void ConfigureControls(void)
 	for ( i=0; i<NUM_CTLS; ++i ) {
 		fontserv->FreeText(keynames[i]);
 	}
-	fontserv->FreeFont(chicago);
 	delete dialog;
 	if ( valid ) {
 		memcpy(&controls, &newcontrols, sizeof(controls));
@@ -500,10 +495,7 @@ void ShowDawn(void)
 	X=160;
 	Y=73;
 #endif
-	if ( (chicago = fontserv->NewFont("Chicago", 12)) == NULL ) {
-		error("Can't use Chicago font!\n");
-		return;
-	}
+	chicago = fonts[CHICAGO_12];
 	if ( (splash = GetCIcon(screen, 103)) == NULL ) {
 		error("Can't load alien dawn splash!\n");
 		return;
@@ -534,7 +526,6 @@ void ShowDawn(void)
 	screen->FreeImage(splash);
 	for ( i=0; i<6; ++i )
 		fontserv->FreeText(text[i]);
-	fontserv->FreeFont(chicago);
 	delete dialog;
 	return;
 }
diff --git a/init.cpp b/init.cpp
index a55b5d72..fdfdc58f 100644
--- a/init.cpp
+++ b/init.cpp
@@ -13,6 +13,7 @@
 // Global variables set in this file...
 Sound    *sound = NULL;
 FontServ *fontserv = NULL;
+MFont    *fonts[NUM_FONTS];
 FrameBuf *screen = NULL;
 
 Sint32	gLastHigh;
@@ -76,7 +77,6 @@ void DoSplash(void)
 
 void DoIntroScreen(void)
 {
-	MFont  *geneva;
 	SDL_Texture *intro, *text;
 	Uint16  Yoff, Xoff;
 	Uint32  clr, ltClr, ltrClr;
@@ -112,19 +112,13 @@ void DoIntroScreen(void)
 
 /* -- Draw the loading message */
 
-	geneva = fontserv->NewFont("Geneva", 9);
-	if ( geneva == NULL ) {
-		error("Warning: %s\n", fontserv->Error());
-		return;
-	}
-	text = fontserv->TextImage("Loading...", geneva, STYLE_BOLD,
+	text = fontserv->TextImage("Loading...", fonts[GENEVA_9], STYLE_BOLD,
 						0xFF, 0xFF, 0x00);
 	if ( text ) {
 		screen->QueueBlit(SCREEN_WIDTH/2-screen->GetImageWidth(text)/2,
 				Yoff+20-screen->GetImageHeight(text)/2, text, NOCLIP);
 		fontserv->FreeText(text);
 	}
-	fontserv->FreeFont(geneva);
 
 	screen->Update();
 }	// -- DoIntroScreen
@@ -696,8 +690,15 @@ static void BuildVelocityTable(void)
 */
 extern "C" void CleanUp(void)
 {
+	int i;
+
 	HaltLogic();
 	if ( fontserv ) {
+		for ( i = 0; i < NUM_FONTS; ++i ) {
+			if ( fonts[i] ) {
+				fontserv->FreeFont(fonts[i]);
+			}
+		}
 		delete fontserv;
 		fontserv = NULL;
 	}
@@ -770,12 +771,23 @@ int DoInitializations(Uint32 video_flags)
 	atexit(CleanUp);		// Need to reset this under X11 DGA
 	SDL_FreeSurface(icon);
 
-	/* Load the Font Server */
+	/* Load the Font Server and fonts */
 	fontserv = new FontServ(screen, "Maelstrom Fonts");
 	if ( fontserv->Error() ) {
 		error("Fatal: %s\n", fontserv->Error());
 		return(-1);
 	}
+	memset(fonts, 0, sizeof(fonts));
+	fonts[CHICAGO_12] = fontserv->NewFont("Chicago", 12);
+	fonts[GENEVA_9] = fontserv->NewFont("Geneva", 9);
+	fonts[NEWYORK_14] = fontserv->NewFont("New York", 14);
+	fonts[NEWYORK_18] = fontserv->NewFont("New York", 18);
+	for ( i = 0; i < NUM_FONTS; ++i ) {
+		if ( !fonts[i] ) {
+			error("Fatal: Couldn't load fonts");
+			return(-1);
+		}
+	}
 
 	/* Load the Sound Server and initialize sound */
 	sound = new Sound("Maelstrom Sounds", gSoundLevel);
diff --git a/maclib/Mac_FontServ.cpp b/maclib/Mac_FontServ.cpp
index ea3c9c66..71977e85 100644
--- a/maclib/Mac_FontServ.cpp
+++ b/maclib/Mac_FontServ.cpp
@@ -85,7 +85,6 @@ FontServ:: FontServ(FrameBuf *_screen, const char *fontfile)
 {
 	screen = _screen;
 	fontres = new Mac_Resource(fontfile);
-	fonts = NULL;
 	strings = hash_create(screen, hash_hash_string, hash_keymatch_string, hash_nuke_string_texture);
  
 	if ( fontres->Error() ) {
@@ -101,11 +100,6 @@ FontServ:: FontServ(FrameBuf *_screen, const char *fontfile)
 
 FontServ:: ~FontServ()
 {
-	while (fonts) {
-		MFont *next = fonts->next;
-		delete fonts;
-		fonts = next;
-	}
 	hash_destroy(strings);
 
 	delete fontres;
@@ -124,20 +118,6 @@ FontServ:: NewFont(const char *fontname, int ptsize)
 	int i, swapfont;
 	MFont *prev, *font;
 
-	/* First see if we can find the font in our cache */
-	prev = NULL;
-	for (font = fonts; font; prev = font, font = font->next) {
-		if (strcmp(fontname, font->name) == 0 && ptsize == font->ptsize) {
-			/* Move this font to the front so it's found faster */
-			if (prev) {
-				prev->next = font->next;
-				font->next = fonts;
-				fonts = font;
-			}
-			return font;
-		}
-	}
-	
 	/* Get the font family */
 	fond = fontres->Resource("FOND", fontname);
 	if ( fond == NULL ) {
@@ -235,18 +215,13 @@ FontServ:: NewFont(const char *fontname, int ptsize)
 		byteswap((Uint16 *)font->owTable, nchars);
 	}
 
-	/* Save this font in the cache */
-	font->next = fonts;
-	fonts = font;
-
 	return(font);
 }
 
 void
 FontServ:: FreeFont(MFont *font)
 {
-	/* We'll likely be asked for this again soon, leave it alone */
-	return;
+	delete font;
 }
 
 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
@@ -453,11 +428,3 @@ FontServ:: FreeText(SDL_Texture *text)
 	/* We'll likely be asked for this again soon, leave it alone */
 	return;
 }
-
-void
-FontServ:: FlushCache(void)
-{
-	/* We'll flush any strings in the cache and leave the fonts around */
-	hash_destroy(strings);
-	strings = hash_create(screen, hash_hash_string, hash_keymatch_string, hash_nuke_string_texture);
-}
diff --git a/maclib/Mac_FontServ.h b/maclib/Mac_FontServ.h
index a4142f83..3a1ebce7 100644
--- a/maclib/Mac_FontServ.h
+++ b/maclib/Mac_FontServ.h
@@ -74,11 +74,8 @@ struct FontHdr {
 };
 
 typedef struct MFont {
-	/* Data useful for caching */
 	const char *name;
 	int ptsize;
-	struct MFont *next;
-
 	struct FontHdr *header;		/* The NFNT header! */
 
 	/* Variable-length tables */
@@ -125,8 +122,6 @@ class FontServ {
 	}
 	void FreeText(SDL_Texture *text);
 
-	void FlushCache();
-
 	/* Returns NULL if everything is okay, or an error message if not */
 	char *Error(void) {
 		return(errstr);
@@ -135,7 +130,6 @@ class FontServ {
 private:
 	FrameBuf *screen;
 	Mac_Resource *fontres;
-	MFont *fonts;
 	HashTable *strings;
 
 	/* Useful for getting error feedback */
diff --git a/main.cpp b/main.cpp
index c5b2cf9c..18b144ca 100644
--- a/main.cpp
+++ b/main.cpp
@@ -448,21 +448,14 @@ int DrawText(int x, int y, const char *text, MFont *font, Uint8 style,
 /* -- Draw the current sound volume */
 static void DrawSoundLevel(void)
 {
-	MFont *geneva;
 	char text[12];
 	int xOff, yOff;
 
-	if ( (geneva = fontserv->NewFont("Geneva", 9)) == NULL ) {
-		error("Can't use Geneva font! -- Exiting.\n");
-		exit(255);
-	}
-
 	xOff = (SCREEN_WIDTH - 512) / 2;
 	yOff = (SCREEN_HEIGHT - 384) / 2;
 	sprintf(text, "%d", gSoundLevel);
-	DrawText(xOff+309-7, yOff+240-6, text, geneva, STYLE_BOLD,
+	DrawText(xOff+309-7, yOff+240-6, text, fonts[GENEVA_9], STYLE_BOLD,
 						30000>>8, 30000>>8, 0xFF);
-	fontserv->FreeFont(geneva);
 }	/* -- DrawSoundLevel */
 
 
@@ -522,11 +515,8 @@ void DrawMainScreen(void)
 
 	/* -- Draw the high scores */
 
-	/* -- First the headings  -- fontserv() isn't elegant, but hey.. */
-	if ( (bigfont = fontserv->NewFont("New York", 18)) == NULL ) {
-		error("Can't use New York (18) font! -- Exiting.\n");
-		exit(255);
-	}
+	/* -- First the headings */
+	bigfont = fonts[NEWYORK_18];
 	DrawText(xOff+5, botDiv+22, "Name", bigfont, STYLE_ULINE,
 						0xFF, 0xFF, 0x00);
 	sRt = xOff+185;
@@ -540,10 +530,7 @@ void DrawMainScreen(void)
 
 	/* -- Now the scores */
 	LoadScores();
-	if ( (font = fontserv->NewFont("New York", 14)) == NULL ) {
-		error("Can't use New York (14) font! -- Exiting.\n");
-		exit(255);
-	}
+	font = fonts[NEWYORK_14];
 
 	for (index = 0; index < 10; index++) {
 		Uint8 R, G, B;
@@ -568,7 +555,6 @@ void DrawMainScreen(void)
 		DrawText(wRt-sw, botDiv+42+(index*18), buffer, 
 						font, STYLE_BOLD, R, G, B);
 	}
-	fontserv->FreeFont(font);
 
 	DrawText(xOff+5, botDiv+46+(10*18)+3, "Last Score: ", 
 					bigfont, STYLE_NORM, 0xFF, 0xFF, 0xFF);
@@ -576,7 +562,6 @@ void DrawMainScreen(void)
 	sw = fontserv->TextWidth("Last Score: ", bigfont, STYLE_NORM);
 	DrawText(xOff+5+sw, botDiv+46+(index*18)+3, buffer, 
 					bigfont, STYLE_NORM, 0xFF, 0xFF, 0xFF);
-	fontserv->FreeFont(bigfont);
 
 	/* -- Draw the Instructions */
 	offset = 34;
@@ -607,10 +592,7 @@ void DrawMainScreen(void)
 	pt.v += offset;
 	DrawKey(&pt, "0", " ", DecrementSound);
 
-	if ( (font = fontserv->NewFont("Geneva", 9)) == NULL ) {
-		error("Can't use Geneva font! -- Exiting.\n");
-		exit(255);
-	}
+	font = fonts[GENEVA_9];
 	DrawText(pt.h+screen->GetImageWidth(gKeyIcon)+3, pt.v+19, "-",
 				font, STYLE_NORM, 0xFF, 0xFF, 0x00);
 
@@ -628,7 +610,6 @@ void DrawMainScreen(void)
 
 	DrawText(xOff+20, yOff+151, VERSION_STRING,
 				font, STYLE_NORM, 0xFF, 0xFF, 0xFF);
-	fontserv->FreeFont(font);
 
 	DrawSoundLevel();
 
@@ -644,20 +625,14 @@ void DrawMainScreen(void)
 
 static void DrawKey(MPoint *pt, const char *key, const char *text, void (*callback)(void))
 {
-	MFont *geneva;
-
-	if ( (geneva = fontserv->NewFont("Geneva", 9)) == NULL ) {
-		error("Can't use Geneva font! -- Exiting.\n");
-		exit(255);
-	}
+	MFont *font = fonts[GENEVA_9];
 
 	screen->QueueBlit(pt->h, pt->v, gKeyIcon);
 
-	DrawText(pt->h+14, pt->v+20, key, geneva, STYLE_BOLD, 0xFF, 0xFF, 0xFF);
-	DrawText(pt->h+13, pt->v+19, key, geneva, STYLE_BOLD, 0x00, 0x00, 0x00);
+	DrawText(pt->h+14, pt->v+20, key, font, STYLE_BOLD, 0xFF, 0xFF, 0xFF);
+	DrawText(pt->h+13, pt->v+19, key, font, STYLE_BOLD, 0x00, 0x00, 0x00);
 	DrawText(pt->h+screen->GetImageWidth(gKeyIcon)+3, pt->v+19, text,
-					geneva, STYLE_BOLD, 0xFF, 0xFF, 0x00);
-	fontserv->FreeFont(geneva);
+					font, STYLE_BOLD, 0xFF, 0xFF, 0x00);
 
 	buttons.Add_Button(pt->h, pt->v, screen->GetImageWidth(gKeyIcon), screen->GetImageHeight(gKeyIcon), callback);
 }	/* -- DrawKey */
@@ -665,22 +640,14 @@ static void DrawKey(MPoint *pt, const char *key, const char *text, void (*callba
 
 void Message(const char *message)
 {
-	MFont *font;
 	int xOff;
 
 	if (!message) {
 		return;
 	}
 
-	if ( (font = fontserv->NewFont("New York", 14)) == NULL ) {
-		error("Can't use New York(14) font! -- Exiting.\n");
-		exit(255);
-	}
-
 	/* This was taken from the DrawMainScreen function */
 	xOff = (SCREEN_WIDTH - 512) / 2;
-	DrawText(xOff, 25, message, font, STYLE_BOLD, 0xCC,0xCC,0xCC);
-
-	fontserv->FreeFont(font);
+	DrawText(xOff, 25, message, fonts[NEWYORK_14], STYLE_BOLD,
+						0xCC, 0xCC, 0xCC);
 }
-
diff --git a/netlogic/about.cpp b/netlogic/about.cpp
index d48c53ae..aa321f0f 100644
--- a/netlogic/about.cpp
+++ b/netlogic/about.cpp
@@ -175,12 +175,7 @@ void DoAbout(void)
 				/* Put in the right credits / mask the old... */
 				clr = screen->MapRGB(0x00, 0x00, 0x00);
 				screen->FillRect(xOff+166,yOff+282,338,62,clr);
-				font = fontserv->NewFont("New York", 18);
-				if ( font == NULL ) {
-					error(
-				"Can't use New York(18) font! -- Exiting.\n");
-					exit(255);
-				}
+				font = fonts[NEWYORK_18];
 				text1 = fontserv->TextImage("Port to Linux:   ",
 					font, STYLE_NORM, 0xFF, 0xFF, 0x55);
 				text2 = fontserv->TextImage("Sam Lantinga",
@@ -191,7 +186,6 @@ void DoAbout(void)
 								text2, NOCLIP);
 				fontserv->FreeText(text1);
 				fontserv->FreeText(text2);
-				fontserv->FreeFont(font);
 			}
 			screen->Update();
 			screen->Fade();
diff --git a/netlogic/game.cpp b/netlogic/game.cpp
index 5177473d..ff34fe87 100644
--- a/netlogic/game.cpp
+++ b/netlogic/game.cpp
@@ -116,7 +116,7 @@ Object *gEnemySprite;
 int	gWhenEnemy;
 
 // Local global variables;
-static MFont *geneva=NULL;
+static MFont *geneva;
 static Uint32 ourGrey, ourWhite;
 static int text_height;
 
@@ -278,10 +278,7 @@ void NewGame(void)
 	}
 
 	/* Load the font and colors we use everywhere */
-	if ( (geneva = fontserv->NewFont("Geneva", 9)) == NULL ) {
-		error("Can't use Geneva font! -- Exiting.\n");
-		exit(255);
-	}
+	geneva = fonts[GENEVA_9];
 	text_height = fontserv->TextHeight(geneva);
 	ourGrey = screen->MapRGB(30000>>8, 30000>>8, 0xFF);
 	ourWhite = screen->MapRGB(0xFF, 0xFF, 0xFF);
@@ -327,7 +324,6 @@ void NewGame(void)
 
 	DoGameOver();
 	screen->ShowCursor();
-	fontserv->FreeFont(geneva);
 }	/* -- NewGame */
 
 
@@ -405,9 +401,6 @@ static void NextWave(void)
 	int	NewRoids;
 	short	temp;
 
-	/* Flush the font text cache */
-	fontserv->FlushCache();
-	
 	gEnemySprite = NULL;
 
 	/* -- Initialize some variables */
@@ -580,10 +573,7 @@ static void DoGameOver(void)
 
 	/* Show the player ranking */
 	if ( gNumPlayers > 1 ) {
-		if ( (newyork = fontserv->NewFont("New York", 18)) == NULL ) {
-                        error("Can't use New York font! -- Exiting.\n");
-                        exit(255);
-                }
+		newyork = fonts[NEWYORK_18];
 		newyork_height = fontserv->TextHeight(newyork);
 		for ( i=0; i<gNumPlayers; ++i ) {
 			char buffer[BUFSIZ], num1[12], num2[12];
@@ -595,7 +585,6 @@ static void DoGameOver(void)
 			DrawText(160, 380+i*newyork_height, buffer,
 				newyork, STYLE_NORM, 30000>>8, 30000>>8, 0xFF);
 		}
-		fontserv->FreeFont(newyork);
 	}
 	screen->Update();
 
@@ -628,10 +617,7 @@ static void DoGameOver(void)
 		}
 
 		/* -- Draw the "Enter your name" string */
-		if ( (newyork = fontserv->NewFont("New York", 18)) == NULL ) {
-                        error("Can't use New York font! -- Exiting.\n");
-                        exit(255);
-                }
+		newyork = fonts[NEWYORK_18];
 		newyork_height = fontserv->TextHeight(newyork);
 		x = (SCREEN_WIDTH-(fontserv->TextWidth("Enter your name: ",
 						newyork, STYLE_NORM)*2))/2;
@@ -683,7 +669,6 @@ static void DoGameOver(void)
 				screen->Update();
 			}
 		}
-		fontserv->FreeFont(newyork);
 		SDL_StopTextInput();
 
 		/* In case the user just pressed <Return> */
diff --git a/scores.cpp b/scores.cpp
index 4108e686..126d60dc 100644
--- a/scores.cpp
+++ b/scores.cpp
@@ -130,13 +130,9 @@ int ZapHighScores(void)
 	X=179;
 	Y=89;
 #endif
-	if ( (chicago = fontserv->NewFont("Chicago", 12)) == NULL ) {
-		error("Can't use Chicago font!\n");
-		return(0);
-	}
+	chicago = fonts[CHICAGO_12];
 	if ( (splash = Load_Title(screen, 102)) == NULL ) {
 		error("Can't load score zapping splash!\n");
-		delete chicago;
 		return(0);
 	}
 	dialog = new Maclike_Dialog(X, Y, CLR_DIALOG_WIDTH, CLR_DIALOG_HEIGHT,
@@ -156,7 +152,6 @@ int ZapHighScores(void)
 
 	/* Clean up and return */
 	screen->FreeImage(splash);
-	fontserv->FreeFont(chicago);
 	delete dialog;
 	if ( do_clear ) {
 		memset(hScores, 0, sizeof(hScores));
@@ -202,13 +197,9 @@ int GetStartLevel(void)
 	int startlevel=10, startlives=5, turbofunk=0;
 
 	/* Set up all the components of the dialog box */
-	if ( (chicago = fontserv->NewFont("Chicago", 12)) == NULL ) {
-		error("Can't use Chicago font!\n");
-		return(0);
-	}
+	chicago = fonts[CHICAGO_12];
 	if ( (splash = GetCIcon(screen, 103)) == NULL ) {
 		error("Can't load alien level splash!\n");
-		delete chicago;
 		return(0);
 	}
 	X=(SCREEN_WIDTH-LVL_DIALOG_WIDTH)/2;
@@ -252,7 +243,6 @@ int GetStartLevel(void)
 	fontserv->FreeText(text2);
 	fontserv->FreeText(text3);
 	fontserv->FreeText(text4);
-	fontserv->FreeFont(chicago);
 	delete dialog;
 	if ( do_level ) {
 		if ( ! startlives || (startlives > 40) )