1 #include "LRSDL_video.h"
2 #include "../nx.h"
3 #include "font.h"
4 #include "font.fdh"
5
6 #include "libretro_shared.h"
7
8 static int text_draw(int x, int y, const char *text, int spacing=0, NXFont *font=&whitefont);
9
10 #ifdef FRONTEND_SUPPORTS_RGB565
11 #define RED_SHIFT 11
12 #define GREEN_SHIFT 5
13 #define BLUE_SHIFT 0
14 #elif defined(ABGR1555)
15 #define RED_SHIFT 0
16 #define GREEN_SHIFT 5
17 #define BLUE_SHIFT 10
18 #else
19 #define RED_SHIFT 10
20 #define GREEN_SHIFT 5
21 #define BLUE_SHIFT 0
22 #endif
23
24
25 static SDL_Surface *sdl_screen = NULL;
26 static SDL_Surface *shadesfc = NULL;
27
28 static bool initialized = false;
29 static bool rendering = true;
30 static bool shrink_spaces = true;
31 static int fontheight = 0;
32
33 NXFont whitefont;
34 NXFont greenfont;
35 NXFont bluefont; // used for "F3:Options" text on pause screen
36 NXFont shadowfont; // white letters w/ drop shadow
37
38 #include "../libretro/bitmap_font.h"
39
font_init(void)40 bool font_init(void)
41 {
42 bool error = false;
43 LRSDL_RWops *rw = LRSDL_RWFromMem(font_bmp, sizeof(font_bmp));
44
45 // we'll be bypassing the NXSurface automatic scaling features
46 // and drawing at the real resolution so we can get better-looking fonts.
47 sdl_screen = screen->fSurface;
48
49 SDL_Surface *font = LRSDL_LoadBMP_RW(rw, 1);
50 SetColorKey(font, SDL_SRCCOLORKEY, 0);
51
52 error |= whitefont.InitChars(font, 0xffffff);
53 error |= greenfont.InitChars(font, 0xffffff); // Workaround for avoiding diacritics to show in green color
54 error |= bluefont.InitCharsShadowed(font, 0xffffff, 0x000000); // Workaround for avoiding diacritics not showing on map location names
55 error |= shadowfont.InitCharsShadowed(font, 0xffffff, 0x000000);
56 error |= create_shade_sfc();
57
58 FreeSurface(font);
59
60 if (error) return 1;
61
62 fontheight = 0;
63 for (char c = 'A'; c <= 'Z'; c++)
64 {
65 if (whitefont.letters[c]->h > fontheight)
66 fontheight = whitefont.letters[c]->h;
67 }
68
69 for (char c = 'a'; c <= 'z'; c++)
70 {
71 if (whitefont.letters[c]->h > fontheight)
72 fontheight = whitefont.letters[c]->h;
73 }
74
75 initialized = true;
76 return 0;
77 }
78
font_close(void)79 void font_close(void)
80 {
81 }
82
font_reload()83 bool font_reload()
84 {
85 if (!initialized)
86 return 0;
87
88 whitefont.free();
89 greenfont.free();
90 bluefont.free();
91 shadowfont.free();
92
93 return font_init();
94 }
95
96 /*
97 void c------------------------------() {}
98 */
99
NXFont()100 NXFont::NXFont()
101 {
102 memset(letters, 0, sizeof(letters));
103 }
104
~NXFont()105 NXFont::~NXFont()
106 {
107 free();
108 }
109
free()110 void NXFont::free()
111 {
112 for(int i=0;i<NUM_LETTERS_RENDERED;i++)
113 {
114 if (letters[i])
115 FreeSurface(letters[i]);
116 letters[i] = NULL;
117 }
118 }
119
set_color(SDL_Surface * font,uint16_t color,uint16_t key)120 static void set_color(SDL_Surface *font, uint16_t color, uint16_t key)
121 {
122 for (unsigned h = 0; h < font->h; h++)
123 {
124 uint16_t *pixels = (uint16_t*)font->pixels + h * (font->pitch / 2);
125 for (unsigned w = 0; w < font->w; w++)
126 {
127 if (pixels[w] != key)
128 pixels[w] = color;
129 }
130 }
131 }
132
InitChars(SDL_Surface * font,uint32_t color)133 bool NXFont::InitChars(SDL_Surface *font, uint32_t color)
134 {
135 SDL_Color fgcolor;
136 SDL_Surface *letter;
137
138 fgcolor.r = (uint8_t)(color >> 16);
139 fgcolor.g = (uint8_t)(color >> 8);
140 fgcolor.b = (uint8_t)(color);
141
142 char str[2];
143 str[1] = 0;
144 uint16_t blue = 0x1f;
145
146 for(int i=1;i<NUM_LETTERS_RENDERED;i++)
147 {
148 str[0] = i;
149
150 letter = (SDL_Surface*)AllocNewSurface(0, 6, 10);
151
152 SDL_Rect src = {0};
153
154 src.w = 5;
155 src.h = 10;
156 src.x = (i % 16) * 16;
157 src.y = (i / 16) * 16;
158
159 SDL_Rect dst = {0};
160 dst.w = letter->w;
161 dst.h = letter->h;
162
163 SetColorKey(letter, SDL_SRCCOLORKEY, 0x1f);
164 FillRectangle(letter, NULL, 0x1f);
165
166 DrawBlit(font, &src, letter, &dst);
167
168 uint16 color = fgcolor.r << RED_SHIFT
169 | fgcolor.g << GREEN_SHIFT
170 | fgcolor.b << BLUE_SHIFT;
171
172 set_color(letter, color, blue);
173
174 letters[i] = letter;
175 }
176
177 return 0;
178 }
179
180 // create a font with a drop-shadow (used for "MNA" stage-name displays)
InitCharsShadowed(SDL_Surface * font,uint32_t color,uint32_t shadowcolor)181 bool NXFont::InitCharsShadowed(SDL_Surface *font, uint32_t color, uint32_t shadowcolor)
182 {
183 SDL_Color fgcolor, bgcolor;
184 SDL_Surface *top, *bottom;
185 SDL_Rect dstrect;
186 const int offset = 2;
187
188 fgcolor.r = (uint8_t)(color >> 16);
189 fgcolor.g = (uint8_t)(color >> 8);
190 fgcolor.b = (uint8_t)(color);
191
192 bgcolor.r = (uint8_t)(shadowcolor >> 16);
193 bgcolor.g = (uint8_t)(shadowcolor >> 8);
194 bgcolor.b = (uint8_t)(shadowcolor);
195
196 char str[2];
197 str[1] = 0;
198
199
200 for(int i=1;i<NUM_LETTERS_RENDERED;i++)
201 {
202 str[0] = i;
203
204 uint16_t blue = 0x1f;
205
206 top = (SDL_Surface*)AllocNewSurface(0, 6, 10);
207 bottom = (SDL_Surface*)AllocNewSurface(0, 6, 10);
208
209 FillRectangle(top, NULL, blue);
210 FillRectangle(bottom, NULL, blue);
211 SetColorKey(top, SDL_SRCCOLORKEY, blue);
212 SetColorKey(bottom, SDL_SRCCOLORKEY, blue);
213
214 SDL_Rect src = {0};
215 src.w = 5;
216 src.h = 10;
217 src.x = (i % 16) * 16;
218 src.y = (i / 16) * 16;
219
220 SDL_Rect dst = {0};
221 dst.w = top->w;
222 dst.h = top->h;
223
224 DrawBlit(font, &src, top, &dst);
225 DrawBlit(font, &src, bottom, &dst);
226
227 uint16_t color_fg = fgcolor.r << RED_SHIFT
228 | fgcolor.g << GREEN_SHIFT
229 | fgcolor.b << BLUE_SHIFT;
230 uint16_t color_bg = bgcolor.r << RED_SHIFT
231 | bgcolor.g << GREEN_SHIFT
232 | bgcolor.b << BLUE_SHIFT;
233
234 set_color(top, color_fg, blue);
235 set_color(bottom, color_bg, blue);
236
237 letters[i] = (SDL_Surface*)AllocNewSurface(0, top->w, top->h+offset);
238
239 SetColorKey(letters[i], SDL_SRCCOLORKEY, blue);
240 FillRectangle(letters[i], NULL, blue);
241
242 dstrect.x = 0;
243 dstrect.y = offset;
244 DrawBlit(bottom, NULL, letters[i], &dstrect);
245
246 dstrect.x = 0;
247 dstrect.y = 0;
248 DrawBlit(top, NULL, letters[i], &dstrect);
249 }
250
251 return 0;
252 }
253
254 /*
255 void c------------------------------() {}
256 */
257
258 // draw a text string
text_draw(int x,int y,const char * text,int spacing,NXFont * font)259 static int text_draw(int x, int y, const char *text, int spacing, NXFont *font)
260 {
261 int orgx = x;
262 int i;
263 SDL_Rect dstrect;
264
265 for(i=0;text[i];i++)
266 {
267 char ch = text[i];
268 SDL_Surface *letter = font->letters[ch];
269
270 if (ch == '=' && game.mode != GM_CREDITS)
271 {
272 if (rendering)
273 draw_sprite((x), (y)+2, SPR_TEXTBULLET);
274 }
275 else if (rendering && ch != ' ' && letter)
276 {
277 // must set this every time, because SDL_BlitSurface overwrites
278 // dstrect with final clipping rectangle.
279 dstrect.x = x;
280 dstrect.y = y;
281 DrawBlit(letter, NULL, sdl_screen, &dstrect);
282 }
283
284 if (spacing != 0)
285 { // fixed spacing
286 x += spacing;
287 }
288 else
289 { // variable spacing
290 if (ch == ' ' && shrink_spaces)
291 { // 10.5 px for spaces - make smaller than they really are - the default
292 x += 6;
293 if (i & 1) x++;
294 }
295 else
296 {
297 if (letter)
298 x += letter->w;
299 }
300 }
301 }
302
303 // return the final width of the text drawn
304 return (x - orgx);
305 }
306
307
GetFontWidth(const char * text,int spacing,bool is_shaded)308 int GetFontWidth(const char *text, int spacing, bool is_shaded)
309 {
310 int wd;
311
312 if (spacing)
313 return (strlen(text) * spacing);
314
315 rendering = false;
316 shrink_spaces = is_shaded;
317
318 wd = text_draw(0, 0, text, spacing);
319
320 rendering = true;
321 shrink_spaces = true;
322
323 return (wd);
324 }
325
GetFontHeight()326 int GetFontHeight()
327 {
328 return fontheight;
329 }
330
331 /*
332 void c------------------------------() {}
333 */
334
335 // create the shadesfc, used by font_draw_shaded. It's just a big long black surface
336 // with 50% per-surface alpha applied, that we can use to darken the background.
create_shade_sfc(void)337 static bool create_shade_sfc(void)
338 {
339 if (shadesfc)
340 FreeSurface(shadesfc);
341
342 int ht = whitefont.letters['M']->h;
343
344 shadesfc = (SDL_Surface*)AllocNewSurface(SDL_SRCALPHA | SDL_SWSURFACE, SCREEN_WIDTH, ht);
345
346 if (!shadesfc)
347 return 1;
348
349 FillRectangle(shadesfc, NULL, 0);
350 LRSDL_SetAlpha(shadesfc, SDL_SRCALPHA, 128);
351
352 return 0;
353 }
354
355
font_draw(int x,int y,const char * text,int spacing,NXFont * font)356 int font_draw(int x, int y, const char *text, int spacing, NXFont *font)
357 {
358 return (text_draw(x, y, text, spacing, font));
359 }
360
361 // draw a text string with a 50% dark border around it
font_draw_shaded(int x,int y,const char * text,int spacing,NXFont * font)362 int font_draw_shaded(int x, int y, const char *text, int spacing, NXFont *font)
363 {
364 SDL_Rect srcrect, dstrect;
365 int wd;
366
367 // get full-res width of final text
368 rendering = false;
369 shrink_spaces = false;
370
371 srcrect.x = 0;
372 srcrect.y = 0;
373 srcrect.h = shadesfc->h;
374 srcrect.w = text_draw(0, 0, text, spacing, font);
375
376 rendering = true;
377
378 // shade
379 dstrect.x = x;
380 dstrect.y = y;
381 DrawBlit(shadesfc, &srcrect, sdl_screen, &dstrect);
382
383 // draw the text on top as normal
384 wd = text_draw(x, y, text, spacing, font);
385
386 shrink_spaces = true;
387 return (wd);
388 }
389
390
391
392
393
394