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