1 #if defined(USE_SDL) || defined(USE_SDL2)
2 #include <SDL.h>
3 #include "c-angband.h"
4 
5 #if defined(USE_SDL2_IMAGE) || defined(USE_SDL_IMAGE)
6 #include <SDL_image.h>
7 #else
8 #include "lupng/lupng.h"
9 #endif
10 #if defined(USE_SDL2_TTF) || defined(USE_SDL_TTF)
11 #include <SDL_ttf.h>
12 #endif
13 
14 /*
15  * This file contains various font loading routines, extracted from
16  * both SDL1 and SDL2 clients, to be then used by both.
17  */
18 
19 static cptr ANGBAND_DIR_XTRA_FONT;
20 
21 #define USE_BITMASK /* Load "mask files" and use them as colorkeys when doing graphics. Slower, but neatier */
22 
23 /* Global config option: */
24 bool sdl_graf_prefer_rgba = FALSE;
25 
26 /* Useful constants */
27 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
28 #define RMASK 0xff000000
29 #define GMASK 0x00ff0000
30 #define BMASK 0x0000ff00
31 #define AMASK 0x000000ff
32 #else
33 #define RMASK 0x000000ff
34 #define GMASK 0x0000ff00
35 #define BMASK 0x00ff0000
36 #define AMASK 0xff000000
37 #endif
38 #define RGBAMASK RMASK, GMASK, BMASK, AMASK
39 
40 /* The following function will extract height and width info from a filename
41  * such as 16x16.xyz or 8X13.bar or even argle8ook16.foo
42  * I realize now that it's also useful for reading integers out of an argument
43  * such as --fooscale1=2
44  - Taken from "maim_sdl.c", Copyright 2001 Gregory Velichansky (hmaon@bumba.net)
45  */
strtoii(const char * str,Uint32 * w,Uint32 * h)46 static errr strtoii(const char *str, Uint32 *w, Uint32 *h) {
47 	char buf[1024];
48 	char *s = buf;
49 	char *tok;
50 	char *numeric = "0123456789";
51 
52 	size_t l; /* length of numeric string */
53 
54 	if (!str || !w || !h) return -1;
55 
56 	if (strlen(str) < 3) return -1; /* must have room for at least "1x1" */
57 
58 	strncpy(buf, str, 1023);
59 	buf[1023] = '\0';
60 
61 	tok = strpbrk(buf, numeric);
62 	if (!tok) return -1;
63 
64 	l = strspn(tok, numeric);
65 	if (!l) return -1;
66 
67 	tok[l] = '\0';
68 
69 	s = tok + l + 1;
70 
71 	if(!sscanf(tok, "%d", w)) return -1;
72 
73 	/* next token */
74 	tok = strpbrk(s, numeric);
75 	if (!tok) return -1;
76 
77 	l = strspn(tok, numeric);
78 	if (!l) return -1;
79 
80 	tok[l] = '\0';
81 	/* no need to set s since this is the last token */
82 
83 	if(!sscanf(tok, "%d", h)) return -1;
84 
85 	return 0;
86 }
87 
88 
89 /* Generate a surface with a filled circle on a transparent background */
SDL_CreateCircleSurface32(int w,int h,int r,SDL_Color * c)90 SDL_Surface* SDL_CreateCircleSurface32(int w, int h, int r, SDL_Color *c)
91 {
92 	int x, y, cx, cy;
93 	SDL_Surface *face;
94 	face = SDL_CreateRGBSurface(0, w, h, 32, RGBAMASK);
95 	if (!face) return NULL;
96 
97 	/* Center pixel */
98 	cx = w / 2;
99 	cy = h / 2;
100 
101 	/* Iterate over each pixel... */
102 	for (y = 0; y < h; y++)
103 	{
104 		for (x = 0; x < w; x++)
105 		{
106 			Uint32 col; Uint32 *px;
107 			if (IHYPOT(cx - x, cy - y) > r)
108 			{
109 				col = SDL_MapRGBA(face->format, 0, 0, 0, 0);
110 			}
111 			else
112 			{
113 				col = SDL_MapRGBA(face->format, c->r, c->g, c->b, 255);
114 			}
115 			/* Get pointer and set color */
116 			px = (Uint32*)((Uint8*)face->pixels
117 				+ (y * face->pitch + x * face->format->BytesPerPixel));
118 			*px = col;
119 		}
120 	}
121 	return face;
122 }
123 
124 /* Create a software, 8-bpp SDL Surface */
SDL_Create8BITSurface(int w,int h)125 SDL_Surface* SDL_Create8BITSurface(int w, int h)
126 {
127 	SDL_Color pal[2];
128 	SDL_Surface *face;
129 	face = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 8, 0, 0, 0, 0);
130 	if (!face) return NULL;
131 
132 	/* Set monochrome palette */
133 	pal[0].r = pal[0].g = pal[0].b = 0;
134 	pal[1].r = pal[1].g = pal[1].b = 255;
135 #if SDL_MAJOR_VERSION < 2
136 	SDL_SetColors(face, pal, 0, 2);
137 #else
138 	pal[0].a = 0;
139 	pal[1].a = 255;
140 	SDL_SetPaletteColors(face->format->palette, pal, 0, 2);
141 #endif
142 	return face;
143 }
144 
145 /*
146  * bmpToFont
147  * This assumes the file is already in the correct
148  * 16x16 glyph table format, and is a pallettized one.
149  */
bmpToFont(SDL_Rect * fd,cptr filename)150 SDL_Surface *bmpToFont(SDL_Rect *fd, cptr filename) {
151 	SDL_Surface *font;
152 	Uint32 width, height;
153 	char buf[1036];
154 #if 0
155 	SDL_Surface *surface;
156 	SDL_Rect full_rect;
157 #endif
158 
159 	// Get and open our BMP font from the xtra dir
160 	path_build(buf, 1024, ANGBAND_DIR_XTRA_FONT, filename);
161 	font = SDL_LoadBMP(buf);
162 	if (!font) {
163 		plog_fmt("bmpToFont: %s", SDL_GetError());
164 		return NULL;
165 	}
166 	if (font->format->BitsPerPixel != 8) {
167 		plog_fmt("bmpToFont: was expecting bitmap with a palette");
168 		return NULL;
169 	}
170 	// Poorly get our font metrics and maximum cell size in pixels
171 	width = 0;
172 	height = 0;
173 	if (strtoii(filename, &width, &height) != 0) {
174 		width = font->w / 16;
175 		height = font->h / 16;
176 	}
177 	fd->w = width;
178 	fd->h = height;
179 
180 	return font;
181 #if 0
182 	//SDL_SaveBMP(font, "original_font.bmp");//debug
183 
184 	// Create our glyph surface that will store 256 characters in a 16x16 matrix
185 	surface = SDL_Create8BITSurface(width*16, height*16);
186 
187 	full_rect.x = 0;
188 	full_rect.y = 0;
189 	full_rect.w = font->w;
190 	full_rect.h = font->h;
191 
192 #if SDL_MAJOR_VERSION < 2
193 	SDL_SetColors(surface, font->format->palette->colors, 0, font->format->palette->ncolors);
194 #else
195 	SDL_SetPaletteColors(surface->format->palette, font->format->palette->colors, 0, font->format->palette->ncolors);
196 #endif
197 	surface->format->palette->ncolors = font->format->palette->ncolors;
198 	SDL_BlitSurface(font, &full_rect, surface, &full_rect);
199 
200 	//plog_fmt("Loaded font: %s (%d x %d)", filename, width, height);
201 
202 	SDL_FreeSurface(font);
203 
204 	return surface;
205 #endif
206 }
207 
208 #if defined(USE_SDL2_TTF) || defined(USE_SDL_TTF)
209 /* ttfToFont
210 This function takes the given FontData structure and attempts to make a Glyph Table texture from the filename at the point size fontsize with sharp or smooth rendering via the smoothing boolean.
211 taken from main-sdl2.c
212 */
ttfToFont(SDL_Rect * fd,cptr filename,int fontsize,int smoothing)213 SDL_Surface* ttfToFont(SDL_Rect *fd, cptr filename, int fontsize, int smoothing) {
214   SDL_Surface *surface;
215   TTF_Font *font;
216   int minx, maxx, miny, maxy, width, height;
217   int i;
218   char buf[1036];
219   //if (fd->w || fd->h) return 1; // Return if FontData is not clean
220 
221   fd->w = fd->h = 0;
222   // Get and open our TTF font from the xtra dir
223   path_build(buf, 1024, ANGBAND_DIR_XTRA_FONT, filename);
224   font = TTF_OpenFont(buf, fontsize);
225   if (!font) {
226     plog_fmt("ttfToFont: %s", TTF_GetError());
227     return NULL;
228   }
229   // Poorly get our font metrics and maximum cell size in pixels
230   width = 0;
231   height = 0;
232   for (i = 0; i < 255; i++) {
233     TTF_GlyphMetrics(font, (char)i, &minx, &maxx, &miny, &maxy, NULL);
234     if (minx+maxx > width) width = minx+maxx;
235     if (miny+maxy > height) height = miny+maxy;
236   }
237   /* Hack -- square'ize */
238   if (smoothing == 2)
239   {
240     if (width > height) height = width;
241     else if (height > width) width = height;
242   }
243   // For .fon files, try the NxN-in-filename approach
244   if (isuffix(filename, ".fon")) {
245     int _width = 0;
246     int _height = 0;
247     if (!strtoii(filename, &_width, &_height)) {
248       width = _width;
249       height = _height;
250     }
251   }
252 
253   fd->w = width;
254   fd->h = height;
255 
256   // Create our glyph surface that will store 256 characters in a 16x16 matrix
257   surface = SDL_CreateRGBSurface(0, width*16, height*16, 32, RGBAMASK);
258   if (surface == NULL) {
259     plog_fmt("ttfToFont: %s", SDL_GetError());
260     TTF_CloseFont(font);
261     return NULL;
262   }
263   // Painstakingly create each glyph as a surface and blit to our glyphs surface
264   {
265     int ch = 0;
266     for (ch = 0; ch < 256; ch++) {
267       SDL_Color color = { 255, 255, 255 };
268       SDL_Surface *char_surface = (smoothing ? TTF_RenderGlyph_Blended(font, ch, color) : TTF_RenderGlyph_Solid(font, ch, color));
269       int row = ch / 16;
270       int col = ch - (row*16);
271       SDL_Rect glyph_rect = { col*width, row*height, width, height };
272       SDL_BlitSurface(char_surface, NULL, surface, &glyph_rect);
273       SDL_FreeSurface(char_surface);
274     }
275   }
276   // We're done with the font
277   TTF_CloseFont(font);
278   return surface;
279 }
280 #endif
281 
282 /*
283 Taken from "main-sdl.c", Copyright 2001 Gregory Velichansky (hmaon@bumba.net)
284 */
285 /*
286  * Load a HEX font.
287  * See http://czyborra.com/unifont/
288  *
289  * XXX Note. Your file should not be all full-width glyphs. At least one
290  * half-width glyph must be present for my lame algorithm to work.
291  * It is OK to have all half-width glyphs.
292  *
293  * This routine will try to use strtoii() to figure out the font's bounding
294  * box from the filename. This seems to be an acceptable thing to try,
295  * as seen in main-win.c
296  *
297  * FIXME
298  * BUGS: There is no attempt made at figuring out a righteous bounding box.
299  *	      Certain HEX fonts can be *wider* than 16 pixels. They may break.
300  *
301  *	What we need is a BDF loader. It's not a high priority though.
302  *
303  */
304 
305 #define highhextoi(x) (strchr("ABCDEF", (x))? 0xA + ((x)-'A'):0)
306 #define hexchartoi(x) (strchr("0123456789", (x))? (x)-'0' : highhextoi((x)))
307 
308 #ifndef MAX_HEX_FONT_LINE
309 #define MAX_HEX_FONT_LINE 1024
310 #endif
311 
load_HEX_font_sdl(SDL_Rect * fd,cptr filename,bool justmetrics)312 SDL_Surface* load_HEX_font_sdl(SDL_Rect *fd, cptr filename, bool justmetrics)
313 {
314 	SDL_Surface *face;
315 	ang_file *f;
316 
317 	char buf[1036]; /* 12 (or 11? ;->)extra bytes for good luck. */
318 
319 	char gs[MAX_HEX_FONT_LINE]; /* glyph string */
320 
321 	Uint32 i,j;
322 
323 	errr fail = 0; /* did we fail? */
324 
325 	Uint32 x; /* current x in fd->face */
326 	Uint32 y; /* current y in fd->face */
327 
328 	Uint32 gn; /* current glyph n */
329 
330 	Uint32 n; /* current nibble or byte or whatever data from file */
331 
332 	Uint32 pos; /* position in the nasty string */
333 
334 	Uint32 bytesdone; /* bytes processed */
335 
336 	Uint32 mw, mh; /* for strtoii() */
337 
338 	Uint32 iw, ih; /* internal width and height. sometimes larger then final character size */
339 
340 	/* check font_data */
341 	fd->w = fd->h = 0;
342 	//if (fd->w || fd->h) return NULL; /* dealloc it first, dummy. */
343 
344 	/* Build the filename */
345 	path_build(buf, 1024, ANGBAND_DIR_XTRA_FONT, filename);
346 
347 	f = file_open(buf, MODE_READ, FTYPE_TEXT);
348 
349 	if (!f)
350 	{
351 		plog(format("Couldn't open: %s", buf));
352 		return NULL;
353 	}
354 
355 	/* try hard to figure out the font metrics */
356 
357 	while (file_getl(f, gs, MAX_HEX_FONT_LINE))
358 	{
359 		i = strlen(gs);
360 
361 		if (gs[i-1] == '\n') i--;
362 		if (gs[i-1] == '\r') i--;
363 
364 		i -= 5; /* each line begins with 1234: */
365 
366 		/* now i is the number of nibbles in the line */
367 
368 		if (i & 1)
369 		{
370 			plog("Error in HEX line measurment. Report to hmaon@bumba.net.");
371 			file_close(f);
372 			fail = -1;
373 			break;
374 		}
375 
376 		i >>= 1; /* i is number of bytes */
377 
378 		if (!fd->h)
379 		{
380 			fd->w = 8; /* a nasty guess. */
381 			fd->h = i;
382 			/*if (i & 1) break;*/ /* odd number of bytes. this is the height. */
383 		} else
384 		{
385 			if (i > fd->h) {
386 				fd->w = 16; /* an even nastier guess (full-width glyphs here) */
387 				if(fd -> h / 2 == i / 3)
388 				{
389 					/* this sucks. */
390 					fd->h = i / 3;
391 					fd->w = 24;
392 				} else
393 				if(i != (fd->h)*2) /* check sanity and file integrity */
394 				{
395 					plog("Error 2 in HEX measurement.");
396 					/*fail = -1;*/
397 				}
398 				break; /* this is a full-width glyph. We have the height. */
399 			} else
400 			if (i < fd->h) {
401 				if (i*2 != fd->h)
402 				{
403 					plog("Error 3 in HEX measurement.");
404 					/*fail = -1;*/
405 				}
406 				fd->w = 16; /* the same nastier guess. */
407 				fd->h = i; /* Ah, so this is the height */
408 			}
409 			/* they're equal. we can say nothing about the glyph height */
410 		}
411 	}
412 
413 	/* Use those dimensions for reading anyway */
414 	iw = fd->w;
415 	ih = fd->h;
416 
417 	/* analyze the file name */
418 	if(!strtoii(filename, &mw, &mh))
419 	{
420 		/* success! */
421 		fd->w = mw;
422 		fd->h = mh;
423 	} else {
424 		plog("You may wish to incude the dimensions of a font in its file name. ie \"vga8x16.hex\"");
425 	}
426 
427 	if (justmetrics)
428 	{
429 		file_close(f);
430 		return NULL;
431 	}
432 
433 	/* Allocate the bitmap here. */
434 	face = SDL_Create8BITSurface(iw, 256 * ih);
435 
436 	if (!face)
437 	{
438 		file_close(f);
439 		return NULL;
440 	}
441 	//SDL_SetAlpha(face, SDL_RLEACCEL, SDL_ALPHA_OPAQUE); /* use RLE */
442 
443 	file_seek(f, 0);
444 
445 	while (file_getl(f, gs, MAX_HEX_FONT_LINE))
446 	{
447 #ifdef FONT_LOAD_DEBUGGING
448 		puts("");
449 		puts(gs);
450 #endif
451 		/* figure out character code (aka index). xxxx:... */
452 		if (sscanf(gs, "%4x", &gn) != 1)
453 		{
454 			plog("Broken HEX file.");
455 			fail = -1;
456 			break;
457 		}
458 
459 #ifdef FONT_LOAD_DEBUGGING
460 		printf("%4x:\n", gn);
461 #endif
462 		if (gn > 255) {
463 			gn = 255;
464 		}
465 
466 		x = 0;
467 		y = fd->h * gn;
468 
469 		i = strlen(gs);
470 
471 		if (gs[i-1] == '\n') {
472 			i--;
473 			gs[i] = '\0';
474 		}
475 		if (gs[i-1] == '\r')
476 		{
477 			i--;
478 			gs[i] = '\0';
479 		}
480 
481 		i -= 5; /* each line begins with 1234: */
482 		/* now i is the number of nibbles represented in the line */
483 		i >>= 1; /* now bytes. */
484 
485 		pos = 5;
486 		bytesdone = 0;
487 
488 		while (gs[pos] != '\0' && pos < strlen(gs))
489 		{
490 			n  = (hexchartoi(gs[pos])) << 4; pos++;
491 			n += (hexchartoi(gs[pos])); pos++;
492 			/* they're macros. do NOT pass a "pos++" to them! :) :) :) */
493 
494 			for(j = 0; j < 8; ++j, ++x, n <<= 1)
495 			{
496 				if (n & 0x80)
497 				{
498 #ifdef FONT_LOAD_DEBUGGING
499 					printf("#");
500 #endif
501 					((Uint8 *)face->pixels)[x + y*face->pitch] = 0x01;
502 				} else
503 				{
504 #ifdef FONT_LOAD_DEBUGGING
505 					printf("-");
506 #endif
507 					((Uint8 *)face->pixels)[x + y*face->pitch] = 0x00;
508 				}
509 			}
510 			++bytesdone;
511 
512 			/* processing half-width glyph or just finished even byte */
513 			if (i == ih || ((i == 2*ih) && !(bytesdone & 1)))
514 			{
515 				x = 0;
516 				++y;
517 #ifdef FONT_LOAD_DEBUGGING
518 				printf("\n");
519 #endif
520 			} else if (i == 2*ih)
521 			{
522 				/* XXX do nothing? */
523 			} else
524 			{
525 				/* XXX XXX XXX softer errors since HEX seems to actually permit
526 				 * this situation
527 				 */
528 				/*plog("HEX measurement error, fd->h is not a multiple of i.");*/
529 				/*fail = -1;*/
530 			}
531 		} /* while (gs[pos... */
532 	} /* while (fgets... */
533 
534 	file_close(f);
535 
536 	if (fail == -1)
537 	{
538 		SDL_FreeSurface(face);
539 		face = NULL;
540 	}
541 
542 	/* Hack -- limit palette */
543 	face->format->palette->ncolors = 2;
544 
545 	return face;
546 }
load_HEX_font_sdl_(SDL_Rect * fd,cptr filename)547 SDL_Surface* load_HEX_font_sdl_(SDL_Rect *fd, cptr filename) {
548 	SDL_Color pal[2];
549 	SDL_Surface *font, *surface;
550 	SDL_Rect sr, dr;
551 	int i;
552 	char buf[1036];
553 
554 	// Get and open our BMP font from the xtra dir
555 	path_build(buf, 1024, ANGBAND_DIR_XTRA_FONT, filename);
556 	// Call the original load_HEX_font_sdl function,
557 	// which returns a 1x256 glyph table. Ideally, it should return
558 	// 16x16 table by itself, but it doesn't, and I don't want to mess
559 	// with it. So we re-arrange into proper table on a new surface
560 	// after loading.
561 	font = load_HEX_font_sdl(fd, filename, 0);
562 
563 	if (font == NULL)
564 	{
565 		return NULL;
566 	}
567 
568 	// Create our glyph surface that will store 256 characters in a 16x16 matrix
569 	surface = SDL_Create8BITSurface(fd->w*16, fd->h*16);
570 
571 	sr.w = dr.w = fd->w;
572 	sr.h = dr.h = fd->h;
573 
574 #if SDL_MAJOR_VERSION < 2
575 	SDL_SetColors(surface, font->format->palette->colors, 0, 2);
576 	surface->format->palette->ncolors = 2;
577 #else
578 	SDL_SetPaletteColors(surface->format->palette, font->format->palette->colors, 0, 2);
579 	surface->format->palette->ncolors = 2;
580 #endif
581 
582 	// Copy original 1x256 table into 16x16 table
583 
584 	for (i = 0; i < 256; i++)
585 	{
586 		sr.x = 0;
587 		sr.y = i * sr.h;
588 
589 		dr.x = (i % 16) * dr.w;
590 		dr.y = (i / 16) * dr.h;
591 
592 		SDL_BlitSurface(font, &sr, surface, &dr);
593 	}
594 
595 	SDL_FreeSurface(font);
596 
597 	return surface;
598 }
599 
600 /*
601  * BDF font loader.
602  *
603  * NOTE: This function will crash hard on any kind of error.
604  * The air around it is charged with crash-inducing electricity.
605  */
load_BDF_font(SDL_Rect * fd,cptr filename)606 SDL_Surface* load_BDF_font(SDL_Rect *fd, cptr filename)
607 {
608 	ang_file *f;
609 	SDL_Surface *face;
610 	char buf[1024];
611 	char line[1024];
612 
613 	int n, bitmap_mode = 0, bitmap_line = 0;
614 	bool fony_error = FALSE;
615 
616 	int iw = 16;
617 	int ih = 24;
618 
619 	int glyph_w, glyph_h;
620 	int glyph_x, glyph_y;
621 	int font_ox, font_oy;
622 	int num_chars = 256;
623 	int cols = 16;
624 	int rows = 16;
625 	int cx, cy;
626 
627 	/* Build the filename */
628 	path_build(buf, 1024, ANGBAND_DIR_XTRA_FONT, filename);
629 
630 	f = file_open(buf, MODE_READ, FTYPE_TEXT);
631 
632 	if (!f)
633 	{
634 		plog(format("Couldn't open: %s", buf));
635 		return NULL;
636 	}
637 
638 	while (file_getl(f, line, 1024))
639 	{
640 		/* Chomp */
641 		n = strlen(line);
642 		if (n && line[n-1] == '\n') n--;
643 		if (n && line[n-1] == '\r') n--;
644 		line[n] = '\0';
645 
646 		/* "Parse" */
647 		if (!my_strnicmp(line, "ENDCHAR", 7)) {
648 			bitmap_mode = 0;
649 			continue;
650 		}
651 		else if (bitmap_mode) {
652 			/* We get a string with hex, e.g. FF0C */
653 			u32b b;
654 			char hbuf[3] = { 0, 0, 0 };
655 			int i, j, l = strlen(line) / 2; /* num bytes */
656 			if (!face) {
657 				file_close(f);
658 				return NULL;
659 			}
660 			for (j = 0; j < l; j++) { /* for each byte */
661 				/* Read hex string, 2 chars at a time */
662 				hbuf[0] = line[(j*2) + 0];
663 				hbuf[1] = line[(j*2) + 1];
664 				b = (u32b)strtol(hbuf, NULL, 16);
665 				for (i = 0; i < 8; i++) { /* for each bit */
666 					int mask =  (1 << i);
667 					int test = (b & mask);
668 
669 					int x = cx * iw + j*8 + (8-i) + glyph_x + font_ox;
670 					int y = cy * ih + bitmap_line + (ih-glyph_h) - glyph_y + font_oy;
671 
672 					/* ignore padding bits */
673 					if ( j*8 + (8-i) > glyph_w ) continue;
674 
675 					((Uint8 *)face->pixels)[
676 					  x + y * face->pitch] = test ? 1 : 0;
677 
678 					//printf("%c", mask ? 'X' : '.');
679 				}
680 			}
681 			bitmap_line++;
682 			//printf("\n");
683 		}
684 		else if (!my_strnicmp(line, "STARTCHAR", 9)) {
685 			int i = atoi(&line[10]);
686 			cx = i % cols;
687 			cy = i / cols;
688 			glyph_w = 0;
689 			glyph_h = 0;
690 			glyph_x = 0;
691 			glyph_y = 0;
692 		}
693 		else if (!my_strnicmp(line, "BBX", 3)) {
694 			char *sp;
695 			char *t = strtok(line, " ");
696 			char *_w = strtok(NULL, " ");
697 			char *_h = strtok(NULL, " ");
698 			char *_x = strtok(NULL, " ");
699 			char *_y = strtok(NULL, " ");
700 			glyph_w = atoi(_w);
701 			glyph_h = atoi(_h);
702 			glyph_x = atoi(_x);
703 			glyph_y = atoi(_y);
704 		}
705 		else if (!my_strnicmp(line, "BITMAP", 6)) {
706 			bitmap_mode = 1;
707 			bitmap_line = 0;
708 		}
709 		else if (!my_strnicmp(line, "SIZE", 4)) {
710 			ih = atoi(&line[5]);
711 		}
712 		else if (!my_strnicmp(line, "FONTBOUNDINGBOX", 15)) {
713 			char *sp;
714 			char *t = strtok(line, " ");
715 			char *_w = strtok(NULL, " ");
716 			char *_h = strtok(NULL, " ");
717 			char *_x = strtok(NULL, " ");
718 			char *_y = strtok(NULL, " ");
719 			int font_w = atoi(_w);
720 			int font_h = atoi(_h);
721 			font_ox = atoi(_x);
722 			font_oy = atoi(_y);
723 			iw = font_w;
724 			font_oy = ih - font_h + font_oy;
725 			/*font_ox = iw - font_w + font_ox;*/
726 			if (fony_error) {
727 				font_ox -= 1;
728 				font_oy -= 1;
729 			}
730 		}
731 		else if (!my_strnicmp(line, "COMMENT Exported by Fony v1.4.", 30)) {
732 			fony_error = TRUE;
733 		}
734 		else if (!my_strnicmp(line, "CHARS", 5)) {
735 			num_chars = atoi(&line[6]);
736 			rows = num_chars / cols;
737 		}
738 		else if (!my_strnicmp(line, "ENDPROPERTIES", 13)) {
739 			/* By this time, we should know our bounding box */
740 			if (iw <= 0 || ih <= 0)
741 			{
742 				file_close(f);
743 				return NULL;
744 			}
745 			face = SDL_Create8BITSurface(cols * iw, rows * ih);
746 			if (!face)
747 			{
748 				file_close(f);
749 				return NULL;
750 			}
751 		}
752 	}
753 
754 	file_close(f);
755 
756 	face->format->palette->ncolors = 2;
757 
758 	fd->w = iw;
759 	fd->h = ih;
760 
761 	return face;
762 }
763 
764 /* Read a PNG file using LuPng, convert it to SDL_Surface. */
765 #if defined(USE_SDL2_IMAGE) || defined(USE_SDL_IMAGE)
766 #else
RWopsLuRead(void * outPtr,size_t size,size_t count,void * userPtr)767 size_t RWopsLuRead(void *outPtr, size_t size, size_t count, void *userPtr)
768 {
769 	return SDL_RWread((SDL_RWops*)userPtr, outPtr, size, count);
770 }
RWopsLuWrite(const void * inPtr,size_t size,size_t count,void * userPtr)771 size_t RWopsLuWrite(const void *inPtr, size_t size, size_t count, void *userPtr)
772 {
773 	return SDL_RWwrite((SDL_RWops*)userPtr, inPtr, size, count);
774 }
775 
SDLU_LoadPNG_RW(SDL_RWops * rw,int freesrc)776 SDL_Surface* SDLU_LoadPNG_RW(SDL_RWops *rw, int freesrc)
777 {
778 	SDL_Surface *face;
779 	int x, y, i;
780 	int npal = 0;
781 	SDL_Color pal[256];
782 	LuUserContext userCtx;
783 	LuImage *img;
784 
785 	luUserContextInitDefault(&userCtx);
786 	userCtx.readProc = RWopsLuRead;
787 	userCtx.readProcUserPtr = (void*)rw;
788 
789 	img = luPngReadUC(&userCtx);
790 
791 	if (freesrc) SDL_RWclose(rw);
792 
793 	if (!img)
794 	{
795 		SDL_SetError("Can't read png file");
796 		return NULL;
797 	}
798 
799 	/* Make 32-bit image */
800 	if (sdl_graf_prefer_rgba)
801 	{
802 		face = SDL_CreateRGBSurface(0, img->width, img->height, 32, RGBAMASK);
803 		if (!face)
804 		{
805 			luImageRelease(img, NULL);
806 			return NULL;
807 		}
808 		for (y = 0; y < img->height; y++) {
809 		for (x = 0; x < img->width ; x++) {
810 			Uint8 r = img->data[y * img->width * img->channels + x * img->channels + 0];
811 			Uint8 g = img->data[y * img->width * img->channels + x * img->channels + 1];
812 			Uint8 b = img->data[y * img->width * img->channels + x * img->channels + 2];
813 			Uint8 a = 255;
814 			Uint32 col; Uint32 *px;
815 			if (img->channels == 4) {
816 				a = img->data[y * img->width * img->channels + x * img->channels + 3];
817 			}
818 			col = SDL_MapRGBA(face->format, r, g, b, a);
819 			px = (Uint32*)((Uint8*)face->pixels + (y * face->pitch + x * face->format->BytesPerPixel));
820 			*px = col;
821 		} }
822 		luImageRelease(img, NULL);
823 		return face;
824 	}
825 
826 	luImageDarkenAlpha(img);
827 
828 	/* Make 8-bit image */
829 	face = SDL_CreateRGBSurface(SDL_SWSURFACE, img->width, img->height, 8, 0,0,0,0);
830 	if (!face)
831 	{
832 		luImageRelease(img, NULL);
833 		return NULL;
834 	}
835 #if SDL_MAJOR_VERSION < 2
836 	SDL_SetAlpha(face, SDL_RLEACCEL, SDL_ALPHA_OPAQUE); /* use RLE */
837 #endif
838 
839 	pal[0].r = pal[0].g = pal[0].b = 0; /* chroma black */
840 	pal[1].r = pal[1].g = pal[1].b = 1; /* subtitution black */
841 #if SDL_MAJOR_VERSION >= 2
842 	pal[0].a = 0; pal[1].a = 255;
843 #endif
844 	npal = 2;
845 
846 	for (y = 0; y < img->height; y++) {
847 	for (x = 0; x < img->width ; x++) {
848 
849 		Uint8 r = img->data[y * img->width * img->channels + x * img->channels + 0];
850 		Uint8 g = img->data[y * img->width * img->channels + x * img->channels + 1];
851 		Uint8 b = img->data[y * img->width * img->channels + x * img->channels + 2];
852 		Uint8 col = 255;
853 		for (i = 0; i < npal; i++) {
854 			if (pal[i].r == r && pal[i].g == g && pal[i].b == b) {
855 				col = i;
856 				break;
857 			}
858 		}
859 		if (col == 255 && npal < 255) {
860 			i = npal;
861 			npal++;
862 			pal[i].r = r;
863 			pal[i].g = g;
864 			pal[i].b = b;
865 #if SDL_MAJOR_VERSION >= 2
866 			pal[i].a = 255;
867 #endif
868 			col = i;
869 		}
870 		if (col == 0 && img->channels == 4) {
871 			Uint8 a = img->data[y * img->width * img->channels + x * img->channels + 3];
872 			if (a <= 32) col = 0;
873 			else col = 1;
874 		}
875 		((Uint8*)face->pixels)[y * face->pitch + x * face->format->BytesPerPixel] = col;
876 	} }
877 #if SDL_MAJOR_VERSION < 2
878 	SDL_SetColors(face, &pal[0], 0, npal);
879 #else
880 	SDL_SetPaletteColors(face->format->palette, pal, 0, npal);
881 #endif
882 
883 	luImageRelease(img, NULL);
884 
885 	return face;
886 }
SDLU_LoadPNG(const char * path)887 SDL_Surface* SDLU_LoadPNG(const char *path)
888 {
889 	return SDLU_LoadPNG_RW(SDL_RWFromFile(path, "rb"), 1);
890 }
891 #endif
892 
sdl_font_init(void)893 errr sdl_font_init(void)
894 {
895 	char path[1024];
896 
897 	/* Font */
898 	path_build(path, 1024, ANGBAND_DIR_XTRA, "font");
899 	ANGBAND_DIR_XTRA_FONT = string_make(path);
900 
901 #if defined(USE_SDL2_TTF) || defined(USE_SDL_TTF)
902 	if (TTF_Init() == -1) {
903 		plog_fmt("TTF_Init(): %s", TTF_GetError());
904 		return -1;
905 	}
906 #endif
907 
908 #if defined(USD_SDL2_IMAGE) || defined(USE_SDL_IMAGE)
909 	if (IMG_Init(IMG_INIT_PNG) == -1) {
910 		plog_fmt("IMG_Init(): %s", IMG_GetError());
911 		return -2;
912 	}
913 #endif
914 
915 	return 0;
916 }
sdl_font_quit()917 errr sdl_font_quit()
918 {
919 	string_free(ANGBAND_DIR_XTRA_FONT);
920 
921 #if defined(USE_SDL2_TTF) || defined(USE_SDL_TTF)
922 	TTF_Quit();
923 #endif
924 
925 #if defined(USD_SDL2_IMAGE) || defined(USE_SDL_IMAGE)
926 	IMG_Quit();
927 #endif
928 	return 0;
929 }
930 
sdl_font_load(cptr filename,SDL_Rect * info,int fontsize,int smoothing)931 SDL_Surface* sdl_font_load(cptr filename, SDL_Rect* info, int fontsize, int smoothing)
932 {
933 	SDL_Rect glyph_info;
934 	SDL_Surface *surface;
935 
936 	char *ext;
937 	enum {
938 		FONT_BMP,
939 		FONT_HEX,
940 		FONT_BDF,
941 		FONT_TTF,
942 		FONT_OTF,
943 		FONT_FON,
944 		FONT_FNT,
945 		FONT_PCF,
946 	} fonttype;
947 	int fontdefault;
948 	char* typenames[] = {
949 		".bmp",
950 		".hex",
951 		".bdf",
952 		".ttf",
953 		".otf",
954 		".fon",
955 		".fnt",
956 		".pcf",
957 	};
958 
959 #if defined(USE_SDL2_TTF) || defined(USE_SDL_TTF)
960 	fontdefault = FONT_TTF;
961 #else
962 	fontdefault = FONT_BMP;
963 #endif
964 
965 	/* Extract file extension */
966 	ext = strrchr(filename, '.');
967 
968 	/* Failed to get extension? */
969 	if (ext == NULL)
970 	{
971 		fonttype = fontdefault;
972 	}
973 	else if (!my_stricmp(ext, typenames[FONT_HEX]))
974 	{
975 		fonttype = FONT_HEX;
976 	}
977 	else if (!my_stricmp(ext, typenames[FONT_BDF]))
978 	{
979 		fonttype = FONT_BDF;
980 	}
981 	else if (!my_stricmp(ext, typenames[FONT_TTF]))
982 	{
983 		fonttype = FONT_TTF;
984 	}
985 	else if (!my_stricmp(ext, typenames[FONT_OTF]))
986 	{
987 		fonttype = FONT_OTF;
988 	}
989 	else if (!my_stricmp(ext, typenames[FONT_FON]))
990 	{
991 		fonttype = FONT_FON;
992 	}
993 	else if (!my_stricmp(ext, typenames[FONT_FNT]))
994 	{
995 		fonttype = FONT_FNT;
996 	}
997 	else if (!my_stricmp(ext, typenames[FONT_PCF]))
998 	{
999 		fonttype = FONT_PCF;
1000 	}
1001 	else if (!my_stricmp(ext, typenames[FONT_BMP]))
1002 	{
1003 		fonttype = FONT_BMP;
1004 	}
1005 	else {
1006 		fonttype = fontdefault;
1007 	}
1008 
1009 	switch (fonttype)
1010 	{
1011 		case FONT_HEX:
1012 			surface = load_HEX_font_sdl_(info, filename);
1013 		break;
1014 		case FONT_BDF:
1015 		/*#if !(defined(USE_SDL2_TTF) || defined(USE_SDL_TTF))*/
1016 		/* XXX Do not use SDL_ttf, opt for our loader. */
1017 			surface = load_BDF_font(info, filename);
1018 		break;
1019 		/*#endif*/
1020 		case FONT_PCF:
1021 		case FONT_FON:
1022 		case FONT_FNT:
1023 		/*
1024 		* if we ever implement our own .FON loading, it will go here.
1025 		* for now, drop to SDL_ttf, which can actually load them
1026 		*
1027 		* //surface = fonToFont(info, filename, :raw_fnt => fonttype == FONT_FNT ? 1 : 0)
1028 		* //break;
1029 		*/
1030 		case FONT_TTF:
1031 		case FONT_OTF:
1032 #if defined(USE_SDL2_TTF) || defined(USE_SDL_TTF)
1033 			surface = ttfToFont(info, filename, fontsize, smoothing);
1034 #else
1035 			surface = NULL;
1036 			plog_fmt("compiled without ttf support, can't load %s\n", filename);
1037 #endif
1038 		break;
1039 		default:
1040 		case FONT_BMP:
1041 			surface = bmpToFont(info, filename);
1042 		break;
1043 	}
1044 
1045 	if (surface == NULL)
1046 	{
1047 		plog_fmt("%s: %s: failed to load %s", ANGBAND_SYS, typenames[fonttype], filename);
1048 	}
1049 
1050 	return surface;
1051 }
1052 
1053 /* Graphics loading API. */
1054 
1055 
1056 /*
1057 This function was known as "load_BMP_graf_sdl"
1058 Taken from "main-sdl.c", Copyright 2001 Gregory Velichansky (hmaon@bumba.net)
1059 Updated to support SDL_Image.
1060 Updated to support LuPNG.
1061 */
sdl_graf_load(cptr filename,SDL_Rect * info,cptr maskname)1062 SDL_Surface* sdl_graf_load(cptr filename, SDL_Rect *info, cptr maskname)
1063 {
1064 #ifdef USE_BITMASK
1065 	int x, y, mask_offset, tile_offset;
1066 	Uint8 *mask_pixels, *tile_pixels;
1067 	Uint8 sub_black; /* substitution color for black */
1068 	SDL_Surface *mask;
1069 #endif
1070 	SDL_Surface *face;
1071 	char path[1024];
1072 	Uint32 mw, mh;
1073 
1074 	info->w = info->h = 0;
1075 
1076 	path_build(path, 1024, ANGBAND_DIR_XTRA_GRAF, filename);
1077 #if defined(USE_SDL2_IMAGE) || defined(USE_SDL_IMAGE)
1078 	face = IMG_Load(path);
1079 #else
1080 	if (isuffix(filename, ".png"))
1081 	{
1082 		face = SDLU_LoadPNG(path);
1083 		maskname = NULL;
1084 	}
1085 	else
1086 	{
1087 		face = SDL_LoadBMP(path);
1088 	}
1089 #endif
1090 	if (face != NULL)
1091 	{
1092 		/* Attempt to get dimensions from filename */
1093 		if (!strtoii(filename, &mw, &mh))
1094 		{
1095 			info->w = mw;
1096 			info->h = mh;
1097 		}
1098 
1099 		/* Convert mask to color-key */
1100 #ifdef USE_BITMASK
1101 		if (!maskname) return face; /* No mask, we're done */
1102 
1103 		path_build(path, 1024, ANGBAND_DIR_XTRA_GRAF, maskname);
1104 
1105 #if defined(USE_SDL2_IMAGE) || defined(USE_SDL_IMAGE)
1106 		if ((mask = IMG_Load(path)) != NULL)
1107 #else
1108 		if ((mask = SDL_LoadBMP(path)) != NULL)
1109 #endif
1110 		{
1111 			sub_black = SDL_MapRGB(face->format, 1, 1, 1);
1112 
1113 			mask_pixels = (Uint8 *)mask->pixels;
1114 			tile_pixels = (Uint8 *)face->pixels;
1115 
1116 			for (y = 0; y < mask->h; y++) {
1117 			for (x = 0; x < mask->w; x++) {
1118 
1119 				mask_offset = (mask->pitch/2 * y + x);
1120 				tile_offset = (face->pitch/2 * y + x);
1121 
1122 				if (!tile_pixels[tile_offset])
1123 					tile_pixels[tile_offset] = ( mask_pixels[mask_offset] ? 0 : sub_black );
1124 
1125 			}
1126 			}
1127 
1128 			SDL_FreeSurface(mask);
1129 			mask = NULL;
1130 		}
1131 #endif
1132 	}
1133 	else
1134 	{
1135 #if defined(USE_SDL2_IMAGE) || defined(USE_SDL_IMAGE)
1136 		plog_fmt("%s %s: %s", ANGBAND_SYS, filename, IMG_GetError());
1137 #else
1138 		plog_fmt("%s %s: %s", ANGBAND_SYS, filename, SDL_GetError());
1139 #endif
1140 		return NULL;
1141 	}
1142 
1143 	return face;
1144 }
1145 #endif
1146