1 /* NetHack may be freely redistributed under the Nethack General Public License
2 * See nethack/dat/license for details */
3 
4 #include <stdlib.h>
5 #include <string.h>
6 #include <ctype.h>
7 #include <SDL.h>
8 #include "SDL_ttf.h"
9 
10 #include "vulture_txt.h"
11 
12 #define VULTURE_MAX_FONTS  2
13 
14 /* the rest of vulture gets these defines indirectly from nethack code.
15 * but I'd prefer not to pull all that in here */
16 #define TRUE 1
17 #define FALSE 0
18 
19 static struct vulture_font {
20 	TTF_Font *fontptr;
21 	char lineheight;
22 } *vulture_fonts = NULL;
23 
24 
25 /* load a font from a ttf file with the given fontindex and pointsize as font font_id */
vulture_load_font(int font_id,const char * ttf_filename,int fontindex,int pointsize)26 int vulture_load_font (int font_id, const char * ttf_filename, int fontindex, int pointsize)
27 {
28 	TTF_Font *newfont;
29 	if(!TTF_WasInit()) {
30 		if(TTF_Init()==-1)
31 			return FALSE;
32 
33 		if (!vulture_fonts)
34 			vulture_fonts = (struct vulture_font *)calloc(VULTURE_MAX_FONTS, sizeof(struct vulture_font));
35 	}
36 
37 	/* font_id should always be passed as a #define, which is always <  VULTURE_MAX_FONTS */
38 	if (font_id >= VULTURE_MAX_FONTS)
39 		return FALSE;
40 
41 	newfont = TTF_OpenFontIndex(ttf_filename, pointsize, fontindex);
42 
43 	if (!newfont)
44 		return FALSE;
45 
46 	if (vulture_fonts[font_id].fontptr)
47 		TTF_CloseFont(vulture_fonts[font_id].fontptr);
48 
49 	vulture_fonts[font_id].fontptr = newfont;
50 	vulture_fonts[font_id].lineheight = TTF_FontAscent(newfont) + 2;
51 
52 	return TRUE;
53 }
54 
55 
vulture_put_text(int font_id,std::string str,SDL_Surface * dest,int x,int y,Uint32 color)56 int vulture_put_text (int font_id, std::string str, SDL_Surface *dest, int x, int y, Uint32 color)
57 {
58 	SDL_Surface *textsurface;
59 	SDL_Color fontcolor;
60 	SDL_Rect dstrect;
61   std::string cleaned_str;
62 	unsigned int i;
63 
64 	if (font_id >= VULTURE_MAX_FONTS || (!vulture_fonts[font_id].fontptr) || str.empty())
65 		return FALSE;
66 
67 	/* sanitize the input string of unprintable characters */
68 	cleaned_str = str;
69 	for (i = 0; i < cleaned_str.length(); i++)
70 		if (!isprint(cleaned_str[i]))
71 			cleaned_str[i] = ' ';
72 
73 
74 	/* extract components from the 32-bit color value */
75 	fontcolor.r = (color & dest->format->Rmask) >> dest->format->Rshift;
76 	fontcolor.g = (color & dest->format->Gmask) >> dest->format->Gshift;
77 	fontcolor.b = (color & dest->format->Bmask) >> dest->format->Bshift;
78 	fontcolor.unused = 0;
79 
80 	textsurface = TTF_RenderText_Blended(vulture_fonts[font_id].fontptr,
81 	                                     cleaned_str.c_str(), fontcolor);
82 	if (!textsurface)
83 		return FALSE;
84 
85 	dstrect.x = x;
86 	dstrect.y = y - 1;
87 	dstrect.w = textsurface->w;
88 	dstrect.h = textsurface->h;
89 
90 	SDL_BlitSurface(textsurface, NULL, dest, &dstrect);
91 	SDL_FreeSurface(textsurface);
92 
93 	return TRUE;
94 }
95 
96 
97 
vulture_put_text_shadow(int font_id,std::string str,SDL_Surface * dest,int x,int y,Uint32 textcolor,Uint32 shadowcolor)98 int vulture_put_text_shadow (int font_id, std::string str, SDL_Surface *dest,
99 							int x, int y, Uint32 textcolor, Uint32 shadowcolor)
100 {
101 	/* draw the shadow first */
102 	vulture_put_text(font_id, str, dest, x+1, y+1, shadowcolor);
103 	/* we only truly care that the actual text got drawn, so only retrun that status */
104 	return vulture_put_text(font_id, str, dest, x, y, textcolor);
105 }
106 
107 
108 /* draw text over multiple lines if its length exceeds maxlen */
vulture_put_text_multiline(int font_id,std::string str,SDL_Surface * dest,int x,int y,Uint32 color,Uint32 shadowcolor,int maxlen)109 void vulture_put_text_multiline(int font_id, std::string str, SDL_Surface *dest,
110 								int x, int y, Uint32 color, Uint32 shadowcolor, int maxlen)
111 {
112   std::string str_copy;
113 	int lastfit, txtlen, lineno, text_height;
114 	size_t endpos, startpos;
115 
116 	lineno = 0;
117 	lastfit = 0;
118 	startpos = endpos = 0;
119 	text_height = vulture_text_height(font_id, str);
120 
121 	/* lastfit is true when the last segment has been fit onto the surface (drawn) */
122 	while (!lastfit) {
123 		lastfit = 1;
124 
125 		startpos = startpos + endpos;
126 		str_copy = str.substr(startpos, std::string::npos);
127 		endpos = str_copy.length() - 1;
128 
129 		txtlen = vulture_text_length(font_id, str_copy);
130 
131 		/* split word off the end of the string until it is short enough to fit */
132 		while (txtlen > maxlen) {
133 			/* a piece will be split off the end, so this is not the last piece */
134 			lastfit = 0;
135 
136 			/* find a suitable place to split */
137 			endpos = str_copy.find_last_of(" \t\n");
138 
139 			/* prevent infinite loops if a long word doesn't fit */
140 			if (endpos == std::string::npos) {
141 				endpos = str_copy.length() - 1;
142 				lastfit = 1;
143 				break;
144 			}
145 
146 			/* truncate the text */
147 			str_copy.erase(endpos++);
148 			txtlen = vulture_text_length(font_id, str_copy);
149 		}
150 		vulture_put_text_shadow(font_id, str_copy, dest, x, y + lineno * text_height, color, shadowcolor);
151 
152 		lineno++;
153 	}
154 }
155 
156 
157 
vulture_text_length(int font_id,std::string str)158 int vulture_text_length (int font_id, std::string str)
159 {
160 	int width = 0;
161 
162 	if (!vulture_fonts[font_id].fontptr || str.empty())
163 		return 0;
164 
165 	TTF_SizeText(vulture_fonts[font_id].fontptr, str.c_str(), &width, NULL);
166 
167 	return width;
168 }
169 
170 
171 
vulture_text_height(int font_id,std::string str)172 int vulture_text_height (int font_id, std::string str)
173 {
174 	int height = 0;
175 
176 	if (!vulture_fonts[font_id].fontptr || str.empty())
177 		return 0;
178 
179 	TTF_SizeText(vulture_fonts[font_id].fontptr, str.c_str(), NULL, &height);
180 
181 	return height;
182 }
183 
184 
185 
vulture_get_lineheight(int font_id)186 int vulture_get_lineheight(int font_id)
187 {
188 	if (font_id < VULTURE_MAX_FONTS && vulture_fonts[font_id].fontptr)
189 		return vulture_fonts[font_id].lineheight;
190 	return 0;
191 }
192 
193 
194 
vulture_free_fonts()195 void vulture_free_fonts()
196 {
197 	int font_id;
198 
199 	for (font_id = 0; font_id < VULTURE_MAX_FONTS; font_id++)
200 	{
201 		if (vulture_fonts[font_id].fontptr)
202 			TTF_CloseFont(vulture_fonts[font_id].fontptr);
203 		vulture_fonts[font_id].fontptr = NULL;
204 	}
205 
206 	free(vulture_fonts);
207 	vulture_fonts = NULL;
208 
209 	TTF_Quit();
210 }
211