1 /*
2 SDL_extras.c:
3
4 Headers for wrapper and utility functions for use with the
5 SDL libraries.
6
7 Copyright 2007, 2008, 2009, 2010.
8 Authors: David Bruce, Tim Holy.
9
10 Project email: <tux4kids-tuxtype-dev@lists.alioth.debian.org>
11 Project website: http://tux4kids.alioth.debian.org
12
13 SDL_extras.c is part of Tux Typing, a.k.a "tuxtype".
14
15 Tux Typing is free software: you can redistribute it and/or modify
16 it under the terms of the GNU General Public License as published by
17 the Free Software Foundation; either version 3 of the License, or
18 (at your option) any later version.
19
20 Tux Typing is distributed in the hope that it will be useful,
21 but WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 GNU General Public License for more details.
24
25 You should have received a copy of the GNU General Public License
26 along with this program. If not, see <http://www.gnu.org/licenses/>.
27 */
28
29
30
31 #include <math.h>
32
33 #include "convert_utf.h"
34 #include "SDL_extras.h"
35 #include "globals.h"
36 #include "pixels.h"
37 //Just need funcs.h for CurrentBkgd()
38 #include "funcs.h"
39
40 /**************************************************************************/
41 /* */
42 /* Begin graphics utility functions */
43 /* */
44 /* These functions provide handy ways to do various types of drawing */
45 /* without troubling the rest of tuxtype with messy mathematical details. */
46 /**************************************************************************/
47
48
49 /* DrawButton() creates and draws a translucent button with */
50 /* rounded ends. All colors and alpha values are supported.*/
DrawButton(SDL_Rect * target_rect,int radius,Uint8 r,Uint8 g,Uint8 b,Uint8 a)51 void DrawButton(SDL_Rect* target_rect,
52 int radius,
53 Uint8 r, Uint8 g, Uint8 b, Uint8 a)
54 {
55 /* NOTE - we use a 32-bit temp surface even if we have a 16-bit */
56 /* screen - it gets converted during blitting. */
57 SDL_Surface* tmp_surf = SDL_CreateRGBSurface(SDL_SWSURFACE|SDL_SRCALPHA,
58 target_rect->w,
59 target_rect->h,
60 32,
61 rmask, gmask, bmask, amask);
62 Uint32 color = SDL_MapRGBA(tmp_surf->format, r, g, b, a);
63 SDL_FillRect(tmp_surf, NULL, color);
64 RoundCorners(tmp_surf, radius);
65
66 SDL_BlitSurface(tmp_surf, NULL, screen, target_rect);
67 SDL_FreeSurface(tmp_surf);
68 }
69
70
71
RoundCorners(SDL_Surface * s,Uint16 radius)72 void RoundCorners(SDL_Surface* s, Uint16 radius)
73 {
74 int y = 0;
75 int x_dist, y_dist;
76 Uint32* p = NULL;
77 Uint32 alpha_mask;
78 int bytes_per_pix;
79
80 if (!s)
81 return;
82 if (SDL_LockSurface(s) == -1)
83 return;
84
85 bytes_per_pix = s->format->BytesPerPixel;
86 if (bytes_per_pix != 4)
87 return;
88
89 /* radius cannot be more than half of width or height: */
90 if (radius > (s->w)/2)
91 radius = (s->w)/2;
92 if (radius > (s->h)/2)
93 radius = (s->h)/2;
94
95
96 alpha_mask = s->format->Amask;
97
98 /* Now round off corners: */
99 /* upper left: */
100 for (y = 0; y < radius; y++)
101 {
102 p = (Uint32*)(s->pixels + (y * s->pitch));
103 x_dist = radius;
104 y_dist = radius - y;
105
106 while (((x_dist * x_dist) + (y_dist * y_dist)) > (radius * radius))
107 {
108 /* (make pixel (x,y) transparent) */
109 *p = *p & ~alpha_mask;
110 p++;
111 x_dist--;
112 }
113 }
114
115 /* upper right: */
116 for (y = 0; y < radius; y++)
117 {
118 /* start at end of top row: */
119 p = (Uint32*)(s->pixels + ((y + 1) * s->pitch) - bytes_per_pix);
120
121 x_dist = radius;
122 y_dist = radius - y;
123
124 while (((x_dist * x_dist) + (y_dist * y_dist)) > (radius * radius))
125 {
126 /* (make pixel (x,y) transparent) */
127 *p = *p & ~alpha_mask;
128 p--;
129 x_dist--;
130 }
131 }
132
133 /* bottom left: */
134 for (y = (s->h - 1); y > (s->h - radius); y--)
135 {
136 /* start at beginning of bottom row */
137 p = (Uint32*)(s->pixels + (y * s->pitch));
138 x_dist = radius;
139 y_dist = y - (s->h - radius);
140
141 while (((x_dist * x_dist) + (y_dist * y_dist)) > (radius * radius))
142 {
143 /* (make pixel (x,y) transparent) */
144 *p = *p & ~alpha_mask;
145 p++;
146 x_dist--;
147 }
148 }
149
150 /* bottom right: */
151 for (y = (s->h - 1); y > (s->h - radius); y--)
152 {
153 /* start at end of bottom row */
154 p = (Uint32*)(s->pixels + ((y + 1) * s->pitch) - bytes_per_pix);
155 x_dist = radius;
156 y_dist = y - (s->h - radius);
157
158 while (((x_dist * x_dist) + (y_dist * y_dist)) > (radius * radius))
159 {
160 /* (make pixel (x,y) transparent) */
161 *p = *p & ~alpha_mask;
162 p--;
163 x_dist--;
164 }
165 }
166 SDL_UnlockSurface(s);
167 }
168
169
170 /**********************
171 Flip:
172 input: a SDL_Surface, x, y
173 output: a copy of the SDL_Surface flipped via rules:
174
175 if x is a nonzero value, then flip horizontally
176 if y is a nonzero value, then flip vertically
177
178 note: you can have it flip both
179 **********************/
Flip(SDL_Surface * in,int x,int y)180 SDL_Surface* Flip( SDL_Surface *in, int x, int y ) {
181 SDL_Surface *out, *tmp;
182 SDL_Rect from_rect, to_rect;
183 Uint32 flags;
184 Uint32 colorkey=0;
185
186 /* --- grab the settings for the incoming pixmap --- */
187
188 SDL_LockSurface(in);
189 flags = in->flags;
190
191 /* --- change in's flags so ignore colorkey & alpha --- */
192
193 if (flags & SDL_SRCCOLORKEY) {
194 in->flags &= ~SDL_SRCCOLORKEY;
195 colorkey = in->format->colorkey;
196 }
197 if (flags & SDL_SRCALPHA) {
198 in->flags &= ~SDL_SRCALPHA;
199 }
200
201 SDL_UnlockSurface(in);
202
203 /* --- create our new surface --- */
204
205 out = SDL_CreateRGBSurface(
206 SDL_SWSURFACE,
207 in->w, in->h, 32, rmask, gmask, bmask, amask);
208
209 /* --- flip horizontally if requested --- */
210
211 if (x) {
212 from_rect.h = to_rect.h = in->h;
213 from_rect.w = to_rect.w = 1;
214 from_rect.y = to_rect.y = 0;
215 from_rect.x = 0;
216 to_rect.x = in->w - 1;
217
218 do {
219 SDL_BlitSurface(in, &from_rect, out, &to_rect);
220 from_rect.x++;
221 to_rect.x--;
222 } while (to_rect.x >= 0);
223 }
224
225 /* --- flip vertically if requested --- */
226
227 if (y) {
228 from_rect.h = to_rect.h = 1;
229 from_rect.w = to_rect.w = in->w;
230 from_rect.x = to_rect.x = 0;
231 from_rect.y = 0;
232 to_rect.y = in->h - 1;
233
234 do {
235 SDL_BlitSurface(in, &from_rect, out, &to_rect);
236 from_rect.y++;
237 to_rect.y--;
238 } while (to_rect.y >= 0);
239 }
240
241 /* --- restore colorkey & alpha on in and setup out the same --- */
242
243 SDL_LockSurface(in);
244
245 if (flags & SDL_SRCCOLORKEY) {
246 in->flags |= SDL_SRCCOLORKEY;
247 in->format->colorkey = colorkey;
248 tmp = SDL_DisplayFormat(out);
249 SDL_FreeSurface(out);
250 out = tmp;
251 out->flags |= SDL_SRCCOLORKEY;
252 out->format->colorkey = colorkey;
253 } else if (flags & SDL_SRCALPHA) {
254 in->flags |= SDL_SRCALPHA;
255 tmp = SDL_DisplayFormatAlpha(out);
256 SDL_FreeSurface(out);
257 out = tmp;
258 } else {
259 tmp = SDL_DisplayFormat(out);
260 SDL_FreeSurface(out);
261 out = tmp;
262 }
263
264 SDL_UnlockSurface(in);
265
266 return out;
267 }
268
269 /* Blend two surfaces together. The third argument is between 0.0 and
270 1.0, and represents the weight assigned to the first surface. If
271 the pointer to the second surface is NULL, this performs fading.
272
273 Currently this works only with RGBA images, but this is largely to
274 make the (fast) pointer arithmetic work out; it could be easily
275 generalized to other image types. */
Blend(SDL_Surface * S1,SDL_Surface * S2,float gamma)276 SDL_Surface* Blend(SDL_Surface* S1, SDL_Surface* S2, float gamma)
277 {
278 SDL_PixelFormat *fmt1, *fmt2;
279 Uint8 r1, r2, g1, g2, b1, b2, a1, a2;
280 SDL_Surface *tmpS, *ret;
281 Uint32 *cpix1, *epix1, *cpix2, *epix2;
282 float gamflip;
283
284 if (!S1)
285 return NULL;
286
287 fmt1 = fmt2 = NULL;
288 tmpS = ret = NULL;
289
290 gamflip = 1.0 - gamma;
291 if (gamma < 0 || gamflip < 0)
292 {
293 perror("gamma must be between 0 and 1");
294 exit(0);
295 }
296
297 fmt1 = S1->format;
298
299 if (fmt1 && fmt1->BitsPerPixel != 32)
300 {
301 perror("This works only with RGBA images");
302 return S1;
303 }
304 if (S2 != NULL)
305 {
306 fmt2 = S2->format;
307 if (fmt2->BitsPerPixel != 32)
308 {
309 perror("This works only with RGBA images");
310 return S1;
311 }
312 // Check that both images have the same width dimension
313 if (S1->w != S2->w)
314 {
315 printf("S1->w %d, S2->w %d; S1->h %d, S2->h %d\n",
316 S1->w, S2->w, S1->h, S2->h);
317 printf("Both images must have the same width dimensions\n");
318 return S1;
319 }
320 }
321
322 tmpS = SDL_ConvertSurface(S1, fmt1, SDL_SWSURFACE);
323 if (tmpS == NULL)
324 {
325 perror("SDL_ConvertSurface() failed");
326 return S1;
327 }
328 if (-1 == SDL_LockSurface(tmpS))
329 {
330 perror("SDL_LockSurface() failed");
331 return S1;
332 }
333
334 // We're going to go through the pixels in reverse order, to start
335 // from the bottom of each image. That way, we can blend things that
336 // are not of the same height and have them align at the bottom.
337 // So the "ending pixel" (epix) will be before the first pixel, and
338 // the current pixel (cpix) will be the last pixel.
339 epix1 = (Uint32*) tmpS->pixels - 1;
340 cpix1 = epix1 + tmpS->w * tmpS->h;
341 if (S2 != NULL
342 && (SDL_LockSurface(S2) != -1))
343 {
344 epix2 = (Uint32*) S2->pixels - 1;
345 cpix2 = epix2 + S2->w * S2->h;
346 }
347 else
348 {
349 epix2 = epix1;
350 cpix2 = cpix1;
351 }
352
353 for (; cpix1 > epix1; cpix1--, cpix2--)
354 {
355 SDL_GetRGBA(*cpix1, fmt1, &r1, &g1, &b1, &a1);
356 a1 = gamma * a1;
357 if (S2 != NULL && cpix2 > epix2)
358 {
359 SDL_GetRGBA(*cpix2, fmt2, &r2, &g2, &b2, &a2);
360 r1 = gamma * r1 + gamflip * r2;
361 g1 = gamma * g1 + gamflip * g2;
362 b1 = gamma * b1 + gamflip * b2;
363 a1 += gamflip * a2;
364 }
365 *cpix1 = SDL_MapRGBA(fmt1,r1,g1,b1,a1);
366 }
367
368 SDL_UnlockSurface(tmpS);
369
370 if (S2 != NULL)
371 SDL_UnlockSurface(S2);
372
373 ret = SDL_DisplayFormatAlpha(tmpS);
374 SDL_FreeSurface(tmpS);
375
376 return ret;
377 }
378
379
380
381
inRect(SDL_Rect r,int x,int y)382 int inRect( SDL_Rect r, int x, int y)
383 {
384 if ((x < r.x)
385 || (y < r.y)
386 || (x > r.x + r.w)
387 || (y > r.y + r.h))
388 return 0;
389 return 1;
390 }
391
392
393 /* Darkens the screen by a factor of 2^bits */
DarkenScreen(Uint8 bits)394 void DarkenScreen(Uint8 bits)
395 {
396 #if BPP == 32
397 Uint32* p;
398 #elif BPP == 16
399 Uint16* p;
400 #else
401 return;
402 #endif
403
404 Uint32 rm = screen->format->Rmask;
405 Uint32 gm = screen->format->Gmask;
406 Uint32 bm = screen->format->Bmask;
407 int x, y;
408
409 /* (realistically, 1 and 2 are the only useful values) */
410 if (bits > 8)
411 return;
412
413 p = screen->pixels;
414
415 for (y = 0; y < screen->h; y++)
416 {
417 for (x = 0; x < screen->w; x++)
418 {
419 *p = (((*p&rm)>>bits)&rm)
420 | (((*p&gm)>>bits)&gm)
421 | (((*p&bm)>>bits)&bm);
422 p++;
423 }
424 }
425 }
426
427
SwitchScreenMode(void)428 void SwitchScreenMode(void)
429 {
430 int window = (screen->flags & SDL_FULLSCREEN);
431 SDL_Surface* oldscreen = screen;
432
433 if (!window)
434 {
435 screen = SDL_SetVideoMode(fs_res_x,
436 fs_res_y,
437 BPP,
438 SDL_SWSURFACE|SDL_HWPALETTE|SDL_FULLSCREEN);
439 }
440 else
441 {
442 screen = SDL_SetVideoMode(RES_X,
443 RES_Y,
444 BPP,
445 SDL_SWSURFACE|SDL_HWPALETTE);
446
447 }
448
449 if (screen == NULL)
450 {
451 fprintf(stderr,
452 "\nError: I could not switch to %s mode.\n"
453 "The Simple DirectMedia error that occured was:\n"
454 "%s\n\n",
455 window ? "windowed" : "fullscreen",
456 SDL_GetError());
457 screen = oldscreen;
458 }
459 else
460 {
461 SDL_FreeSurface(oldscreen);
462 oldscreen = NULL;
463 SDL_UpdateRect(screen, 0, 0, 0, 0);
464 }
465
466 }
467
468
WaitForKeypress(void)469 int WaitForKeypress(void)
470 {
471 SDL_Event evt;
472 while (1)
473 while (SDL_PollEvent(&evt) )
474 if (evt.type == SDL_KEYDOWN)
475 return evt.key.keysym.sym;
476 else SDL_Delay(50);
477 }
478 /* Swiped shamelessly from TuxPaint
479 Based on code from: http://www.codeproject.com/cs/media/imageprocessing4.asp
480 copyright 2002 Christian Graus */
481
zoom(SDL_Surface * src,int new_w,int new_h)482 SDL_Surface* zoom(SDL_Surface* src, int new_w, int new_h)
483 {
484 SDL_Surface* s;
485
486 /* These function pointers will point to the appropriate */
487 /* putpixel() and getpixel() variants to be used in the */
488 /* current colorspace: */
489 void (*putpixel) (SDL_Surface*, int, int, Uint32);
490 Uint32(*getpixel) (SDL_Surface*, int, int);
491
492 float xscale, yscale;
493 int x, y;
494 int floor_x, ceil_x,
495 floor_y, ceil_y;
496 float fraction_x, fraction_y,
497 one_minus_x, one_minus_y;
498 float n1, n2;
499 Uint8 r1, g1, b1, a1;
500 Uint8 r2, g2, b2, a2;
501 Uint8 r3, g3, b3, a3;
502 Uint8 r4, g4, b4, a4;
503 Uint8 r, g, b, a;
504
505 /* Create surface for zoom: */
506
507 s = SDL_CreateRGBSurface(src->flags, /* SDL_SWSURFACE, */
508 new_w, new_h, src->format->BitsPerPixel,
509 src->format->Rmask,
510 src->format->Gmask,
511 src->format->Bmask,
512 src->format->Amask);
513
514 if (s == NULL)
515 {
516 fprintf(stderr, "\nError: Can't build zoom surface\n"
517 "The Simple DirectMedia Layer error that occurred was:\n"
518 "%s\n\n", SDL_GetError());
519 return NULL;
520 // cleanup();
521 // exit(1);
522 }
523
524
525 /* Now assign function pointers to correct functions based */
526 /* on data format of original and zoomed surfaces: */
527 getpixel = getpixels[src->format->BytesPerPixel];
528 putpixel = putpixels[s->format->BytesPerPixel];
529
530 SDL_LockSurface(src);
531 SDL_LockSurface(s);
532
533 xscale = (float) src->w / (float) new_w;
534 yscale = (float) src->h / (float) new_h;
535
536 for (x = 0; x < new_w; x++)
537 {
538 for (y = 0; y < new_h; y++)
539 {
540 /* Here we calculate the new RGBA values for each pixel */
541 /* using a "weighted average" of the four pixels in the */
542 /* corresponding location in the orginal surface: */
543
544 /* figure out which original pixels to use in the calc: */
545 floor_x = floor((float) x * xscale);
546 ceil_x = floor_x + 1;
547 if (ceil_x >= src->w)
548 ceil_x = floor_x;
549
550 floor_y = floor((float) y * yscale);
551 ceil_y = floor_y + 1;
552 if (ceil_y >= src->h)
553 ceil_y = floor_y;
554
555 fraction_x = x * xscale - floor_x;
556 fraction_y = y * yscale - floor_y;
557
558 one_minus_x = 1.0 - fraction_x;
559 one_minus_y = 1.0 - fraction_y;
560
561 /* Grab their values: */
562 SDL_GetRGBA(getpixel(src, floor_x, floor_y), src->format,
563 &r1, &g1, &b1, &a1);
564 SDL_GetRGBA(getpixel(src, ceil_x, floor_y), src->format,
565 &r2, &g2, &b2, &a2);
566 SDL_GetRGBA(getpixel(src, floor_x, ceil_y), src->format,
567 &r3, &g3, &b3, &a3);
568 SDL_GetRGBA(getpixel(src, ceil_x, ceil_y), src->format,
569 &r4, &g4, &b4, &a4);
570
571 /* Create the weighted averages: */
572 n1 = (one_minus_x * r1 + fraction_x * r2);
573 n2 = (one_minus_x * r3 + fraction_x * r4);
574 r = (one_minus_y * n1 + fraction_y * n2);
575
576 n1 = (one_minus_x * g1 + fraction_x * g2);
577 n2 = (one_minus_x * g3 + fraction_x * g4);
578 g = (one_minus_y * n1 + fraction_y * n2);
579
580 n1 = (one_minus_x * b1 + fraction_x * b2);
581 n2 = (one_minus_x * b3 + fraction_x * b4);
582 b = (one_minus_y * n1 + fraction_y * n2);
583
584 n1 = (one_minus_x * a1 + fraction_x * a2);
585 n2 = (one_minus_x * a3 + fraction_x * a4);
586 a = (one_minus_y * n1 + fraction_y * n2);
587
588 /* and put them into our new surface: */
589 putpixel(s, x, y, SDL_MapRGBA(s->format, r, g, b, a));
590
591 }
592 }
593
594 SDL_UnlockSurface(s);
595 SDL_UnlockSurface(src);
596
597 return s;
598 }
599
600
601
602 /*************************************************/
603 /* TransWipe: Performs various wipes to new bkgs */
604 /*************************************************/
605 /*
606 * Given a wipe request type, and any variables
607 * that wipe requires, will perform a wipe from
608 * the current screen image to a new one.
609 */
TransWipe(const SDL_Surface * newbkg,int type,int segments,int duration)610 int TransWipe(const SDL_Surface* newbkg, int type, int segments, int duration)
611 {
612 int i, j, x1, x2, y1, y2;
613 int step1, step2, step3, step4;
614 int frame;
615 SDL_Rect src;
616 SDL_Rect dst;
617
618 LOG("->TransWipe(): START\n");
619
620 /* Input validation: ----------------------- */
621 if (!newbkg)
622 {
623 fprintf(stderr, "TransWipe() - 'newbkg' arg invalid!\n");
624 return 0;
625 }
626
627 /* FIXME should support scaling here - DSB */
628 if(newbkg->w != screen->w || newbkg->h != screen->h)
629 {
630 fprintf(stderr, "TransWipe() - wrong size newbkg* arg");
631 return 0;
632 }
633
634 /* segments is num of divisions */
635 /* duration is how many frames animation should take */
636
637 if(segments < 1)
638 segments = 1;
639 if(duration < 1)
640 duration = 1;
641
642 /* Pick a card, any card... */
643 while(type == RANDOM_WIPE)
644 type = rand() % NUM_WIPES;
645
646
647 ResetBlitQueue();
648 frame = 0;
649
650 switch(type)
651 {
652 case WIPE_BLINDS_VERT:
653 {
654 LOG("--+ Doing 'WIPE_BLINDS_VERT'\n");
655
656 step1 = screen->w/segments;
657 step2 = step1/duration;
658
659 for(i = 0; i <= duration; i++)
660 {
661 for(j = 0; j <= segments; j++)
662 {
663 x1 = step1 * (j - 0.5) - i * step2 + 1;
664 x2 = step1 * (j - 0.5) + i * step2 + 1;
665 src.x = x1;
666 src.y = 0;
667 src.w = step2;
668 src.h = screen->h;
669 dst.x = x2;
670 dst.y = 0;
671 dst.w = step2;
672 dst.h = screen->h;
673 SDL_BlitSurface(newbkg, &src, screen, &src);
674 SDL_BlitSurface(newbkg, &dst, screen, &dst);
675 AddRect(&src, &src);
676 AddRect(&dst, &dst);
677 }
678 UpdateScreen(&frame);
679 }
680
681 src.x = 0;
682 src.y = 0;
683 src.w = screen->w;
684 src.h = screen->h;
685 SDL_BlitSurface(newbkg, NULL, screen, &src);
686 SDL_Flip(screen);
687
688 break;
689 }
690
691 case WIPE_BLINDS_HORIZ:
692 {
693 LOG("--+ Doing 'WIPE_BLINDS_HORIZ'\n");
694
695 step1 = screen->h / segments;
696 step2 = step1 / duration;
697
698 for(i = 0; i <= duration; i++)
699 {
700 for(j = 0; j <= segments; j++)
701 {
702 y1 = step1 * (j - 0.5) - i * step2 + 1;
703 y2 = step1 * (j - 0.5) + i * step2 + 1;
704 src.x = 0;
705 src.y = y1;
706 src.w = screen->w;
707 src.h = step2;
708 dst.x = 0;
709 dst.y = y2;
710 dst.w = screen->w;
711 dst.h = step2;
712 SDL_BlitSurface(newbkg, &src, screen, &src);
713 SDL_BlitSurface(newbkg, &dst, screen, &dst);
714 AddRect(&src, &src);
715 AddRect(&dst, &dst);
716 }
717 UpdateScreen(&frame);
718 }
719
720 src.x = 0;
721 src.y = 0;
722 src.w = screen->w;
723 src.h = screen->h;
724 SDL_BlitSurface(newbkg, NULL, screen, &src);
725 SDL_Flip(screen);
726
727 break;
728 }
729
730 case WIPE_BLINDS_BOX:
731 {
732 LOG("--+ Doing 'WIPE_BLINDS_BOX'\n");
733
734 step1 = screen->w/segments;
735 step2 = step1/duration;
736 step3 = screen->h/segments;
737 step4 = step1/duration;
738
739 for(i = 0; i <= duration; i++)
740 {
741 for(j = 0; j <= segments; j++)
742 {
743 x1 = step1 * (j - 0.5) - i * step2 + 1;
744 x2 = step1 * (j - 0.5) + i * step2 + 1;
745 src.x = x1;
746 src.y = 0;
747 src.w = step2;
748 src.h = screen->h;
749 dst.x = x2;
750 dst.y = 0;
751 dst.w = step2;
752 dst.h = screen->h;
753 SDL_BlitSurface(newbkg, &src, screen, &src);
754 SDL_BlitSurface(newbkg, &dst, screen, &dst);
755 AddRect(&src, &src);
756 AddRect(&dst, &dst);
757 y1 = step3 * (j - 0.5) - i * step4 + 1;
758 y2 = step3 * (j - 0.5) + i * step4 + 1;
759 src.x = 0;
760 src.y = y1;
761 src.w = screen->w;
762 src.h = step4;
763 dst.x = 0;
764 dst.y = y2;
765 dst.w = screen->w;
766 dst.h = step4;
767 SDL_BlitSurface(newbkg, &src, screen, &src);
768 SDL_BlitSurface(newbkg, &dst, screen, &dst);
769 AddRect(&src, &src);
770 AddRect(&dst, &dst);
771 }
772 UpdateScreen(&frame);
773 }
774
775 src.x = 0;
776 src.y = 0;
777 src.w = screen->w;
778 src.h = screen->h;
779 SDL_BlitSurface(newbkg, NULL, screen, &src);
780 SDL_Flip(screen);
781
782 break;
783 }
784 default:
785 break;
786 }
787 return 1;
788 }
789
790
791
792
793
794
795 /************************************************************************/
796 /* */
797 /* Begin blit queue support */
798 /* */
799 /* This code (modified from Sam Lantinga's "Alien" example program) */
800 /* implements a blit queue to perform screen updates in a more */
801 /* optimized fashion. */
802 /************************************************************************/
803
804 //With fullscreen, we need more updates - 180 wasn't enough
805 #define MAX_UPDATES 512
806
807 /* --- Data Structure for Dirty Blitting --- */
808 static SDL_Rect srcupdate[MAX_UPDATES];
809 static SDL_Rect dstupdate[MAX_UPDATES];
810 static int numupdates = 0; // tracks how many blits to be done
811
812 struct blit {
813 SDL_Surface* src;
814 SDL_Rect* srcrect;
815 SDL_Rect* dstrect;
816 unsigned char type;
817 } blits[MAX_UPDATES];
818
819
820
821 /***********************
822 InitBlitQueue()
823 ***********************/
InitBlitQueue(void)824 void InitBlitQueue(void)
825 {
826 int i;
827
828 /* --- Set up the update rectangle pointers --- */
829 for (i = 0; i < MAX_UPDATES; ++i)
830 {
831 blits[i].srcrect = &srcupdate[i];
832 blits[i].dstrect = &dstupdate[i];
833 }
834 numupdates = 0;
835 }
836
837
838 /**************************
839 ResetBlitQueue(): just set the number
840 of pending updates to zero
841 ***************************/
ResetBlitQueue(void)842 void ResetBlitQueue(void)
843 {
844 numupdates = 0;
845 }
846
847
848 /******************************
849 AddRect : Don't actually blit a surface,
850 but add a rect to be updated next
851 update
852 *******************************/
AddRect(SDL_Rect * src,SDL_Rect * dst)853 int AddRect(SDL_Rect* src, SDL_Rect* dst)
854 {
855
856 /*borrowed from SL's alien (and modified)*/
857 struct blit* update;
858
859 if(!src)
860 {
861 fprintf(stderr, "AddRect() - invalid 'src' arg!\n");
862 return 0;
863 }
864
865 if(!dst)
866 {
867 fprintf(stderr, "AddRect() - invalid 'dst' arg!\n");
868 return 0;
869 }
870
871 if(numupdates >= MAX_UPDATES)
872 {
873 fprintf(stderr, "Warning - MAX_UPDATES exceeded, cannot add blit to queue\n");
874 return 0;
875 }
876
877 update = &blits[numupdates++];
878
879 if(!update || !update->srcrect || !update->dstrect)
880 {
881 fprintf(stderr, "AddRect() - 'update' ptr invalid!\n");
882 return 0;
883 }
884
885 update->srcrect->x = src->x;
886 update->srcrect->y = src->y;
887 update->srcrect->w = src->w;
888 update->srcrect->h = src->h;
889 update->dstrect->x = dst->x;
890 update->dstrect->y = dst->y;
891 update->dstrect->w = dst->w;
892 update->dstrect->h = dst->h;
893 update->type = 'I';
894
895 return 1;
896 }
897
898
899
DrawSprite(sprite * gfx,int x,int y)900 int DrawSprite(sprite* gfx, int x, int y)
901 {
902 LOG("Entering DrawSprite()\n");
903
904 if (!gfx || !gfx->frame[gfx->cur])
905 {
906 fprintf(stderr, "DrawSprite() - 'gfx' arg invalid!\n");
907 LOG("Leaving DrawSprite()\n");
908 return 0;
909 }
910
911 LOG("Leaving DrawSprite()\n");
912
913 return DrawObject(gfx->frame[gfx->cur], x, y);
914
915 }
916
917
918
919 /**********************
920 DrawObject : Draw an object at the specified
921 location. No respect to clipping!
922 *************************/
DrawObject(SDL_Surface * surf,int x,int y)923 int DrawObject(SDL_Surface* surf, int x, int y)
924 {
925 struct blit *update;
926
927 LOG("Entering DrawObject()\n");
928
929 if (!surf)
930 {
931 fprintf(stderr, "DrawObject() - invalid 'surf' arg!\n");
932 return 0;
933 }
934
935 DOUT(numupdates);
936
937 if(numupdates >= MAX_UPDATES)
938 {
939 fprintf(stderr, "Warning - MAX_UPDATES exceeded, cannot add blit to queue\n");
940 return 0;
941 }
942
943 update = &blits[numupdates++];
944
945 if(!update || !update->srcrect || !update->dstrect)
946 {
947 fprintf(stderr, "DrawObject() - 'update' ptr invalid!\n");
948 return 0;
949 }
950
951 update->src = surf;
952 update->srcrect->x = 0;
953 update->srcrect->y = 0;
954 update->srcrect->w = surf->w;
955 update->srcrect->h = surf->h;
956 update->dstrect->x = x;
957 update->dstrect->y = y;
958 update->dstrect->w = surf->w;
959 update->dstrect->h = surf->h;
960 update->type = 'D';
961
962 LOG("Leaving DrawObject()\n");
963
964 return 1;
965 }
966
967
968
969 /************************
970 UpdateScreen : Update the screen and increment the frame num
971 ***************************/
UpdateScreen(int * frame)972 void UpdateScreen(int* frame)
973 {
974 int i;
975
976 LOG("Entering UpdateScreen()\n");
977 DOUT(numupdates);
978
979 /* -- First erase everything we need to -- */
980 for (i = 0; i < numupdates; i++)
981 {
982 if (blits[i].type == 'E')
983 {
984 // DEBUGCODE
985 // {
986 // fprintf(stderr, "Erasing blits[%d]\n", i);
987 // fprintf(stderr, "srcrect->x = %d\t srcrect->y = %d\t srcrect->w = %d\t srcrect->h = %d\n",
988 // blits[i].srcrect->x, blits[i].srcrect->y, blits[i].srcrect->w, blits[i].srcrect->h);
989 // fprintf(stderr, "dstrect->x = %d\t dstrect->y = %d\t dstrect->w = %d\t dstrect->h = %d\n",
990 // blits[i].dstrect->x, blits[i].dstrect->y, blits[i].dstrect->w, blits[i].dstrect->h);
991 // }
992
993 SDL_LowerBlit(blits[i].src, blits[i].srcrect, screen, blits[i].dstrect);
994 }
995 }
996
997 LOG("Done erasing\n");
998
999 // SNOW_erase();
1000
1001 /* -- then draw -- */
1002 for (i = 0; i < numupdates; i++)
1003 {
1004 if (blits[i].type == 'D')
1005 {
1006 // DEBUGCODE
1007 // {
1008 // fprintf(stderr, "drawing blits[%d]\n", i);
1009 // fprintf(stderr, "srcrect->x = %d\t srcrect->y = %d\t srcrect->w = %d\t srcrect->h = %d\n",
1010 // blits[i].srcrect->x, blits[i].srcrect->y, blits[i].srcrect->w, blits[i].srcrect->h);
1011 // fprintf(stderr, "dstrect->x = %d\t dstrect->y = %d\t dstrect->w = %d\t dstrect->h = %d\n",
1012 // blits[i].dstrect->x, blits[i].dstrect->y, blits[i].dstrect->w, blits[i].dstrect->h);
1013 // }
1014
1015 SDL_BlitSurface(blits[i].src, blits[i].srcrect, screen, blits[i].dstrect);
1016 }
1017 }
1018
1019 LOG("Done drawing\n");
1020
1021 // SNOW_draw();
1022
1023 /* -- update the screen only where we need to! -- */
1024 // if (SNOW_on)
1025 // SDL_UpdateRects(screen, SNOW_add( (SDL_Rect*)&dstupdate, numupdates ), SNOW_rects);
1026 // else
1027 SDL_UpdateRects(screen, numupdates, dstupdate);
1028
1029 numupdates = 0;
1030 *frame = *frame + 1;
1031
1032 LOG("Leaving UpdateScreen()\n");
1033 }
1034
1035
1036 /* basically puts in an order to overdraw sprite with corresponding */
1037 /* rect of bkgd img */
EraseSprite(sprite * img,int x,int y)1038 int EraseSprite(sprite* img, int x, int y)
1039 {
1040 // struct blit* update;
1041
1042 LOG("Entering EraseSprite()\n");
1043
1044 if( !img
1045 || img->cur < 0
1046 || img->cur > MAX_SPRITE_FRAMES
1047 || !img->frame[img->cur])
1048 {
1049 fprintf(stderr, "EraseSprite() - invalid 'img' arg!\n");
1050 LOG("Leaving EraseSprite()\n");
1051 return 0;
1052 }
1053
1054 LOG("Leaving EraseSprite()\n");
1055
1056 return EraseObject(img->frame[img->cur], x, y);
1057 }
1058
1059
1060
1061 /*************************
1062 EraseObject : Erase an object from the screen
1063 **************************/
EraseObject(SDL_Surface * surf,int x,int y)1064 int EraseObject(SDL_Surface* surf, int x, int y)
1065 {
1066 struct blit* update = NULL;
1067
1068 LOG("Entering EraseObject()\n");
1069
1070 if(!surf)
1071 {
1072 fprintf(stderr, "EraseObject() - invalid 'surf' arg!\n");
1073 return 0;
1074 }
1075
1076 if(numupdates >= MAX_UPDATES)
1077 {
1078 fprintf(stderr, "Warning - MAX_UPDATES exceeded, cannot add blit to queue\n");
1079 return 0;
1080 }
1081
1082 update = &blits[numupdates++];
1083
1084 if(!update || !update->srcrect || !update->dstrect)
1085 {
1086 fprintf(stderr, "EraseObject() - 'update' ptr invalid!\n");
1087 return 0;
1088 }
1089
1090 update->src = CurrentBkgd();
1091
1092 /* take dimentsions from src surface: */
1093 update->srcrect->x = x;
1094 update->srcrect->y = y;
1095 update->srcrect->w = surf->w;
1096 update->srcrect->h = surf->h;
1097
1098 /* NOTE this is needed because the letters may go beyond the size of */
1099 /* the fish, and we only erase the fish image before we redraw the */
1100 /* fish followed by the letter - DSB */
1101 /* add margin of a few pixels on each side: */
1102 update->srcrect->x -= ERASE_MARGIN;
1103 update->srcrect->y -= ERASE_MARGIN;
1104 update->srcrect->w += (ERASE_MARGIN * 2);
1105 update->srcrect->h += (ERASE_MARGIN * 2);
1106
1107
1108 /* Adjust srcrect so it doesn't go past bkgd: */
1109 if (update->srcrect->x < 0)
1110 {
1111 update->srcrect->w += update->srcrect->x; //so right edge stays correct
1112 update->srcrect->x = 0;
1113 }
1114 if (update->srcrect->y < 0)
1115 {
1116 update->srcrect->h += update->srcrect->y; //so bottom edge stays correct
1117 update->srcrect->y = 0;
1118 }
1119
1120 if (update->srcrect->x + update->srcrect->w > CurrentBkgd()->w)
1121 update->srcrect->w = CurrentBkgd()->w - update->srcrect->x;
1122 if (update->srcrect->y + update->srcrect->h > CurrentBkgd()->h)
1123 update->srcrect->h = CurrentBkgd()->h - update->srcrect->y;
1124
1125
1126 update->dstrect->x = update->srcrect->x;
1127 update->dstrect->y = update->srcrect->y;
1128 update->dstrect->w = update->srcrect->w;
1129 update->dstrect->h = update->srcrect->h;
1130 update->type = 'E';
1131
1132 LOG("Leaving EraseObject()\n");
1133
1134 return 1;
1135 }
1136
1137
1138
1139
1140
1141 /************************************************************************/
1142 /* */
1143 /* Begin text drawing functions */
1144 /* */
1145 /* These functions support text drawing using either SDL_Pango */
1146 /* or SDL_ttf. SDL_Pango is preferable but is not available on all */
1147 /* platforms. Code outside of this file does not have to worry about */
1148 /* which library is used to do the actual rendering. */
1149 /************************************************************************/
1150
1151
1152 //NOTE to test program with SDL_ttf, do "./configure --without-sdlpango"
1153
1154
1155 #define MAX_FONT_SIZE 72
1156
1157 /*-- file-scope variables and local file prototypes for SDL_Pango-based code: */
1158 #ifdef HAVE_LIBSDL_PANGO
1159 #include "SDL_Pango.h"
1160
1161 SDLPango_Context* context = NULL;
1162 static SDLPango_Matrix* SDL_Colour_to_SDLPango_Matrix(const SDL_Color* cl);
1163 static int Set_SDL_Pango_Font_Size(int size);
1164
1165
1166
1167 /*-- file-scope variables and local file prototypes for SDL_ttf-based code: */
1168 #else
1169 #include "SDL_ttf.h"
1170 /* We cache fonts here once loaded to improve performance: */
1171 TTF_Font* font_list[MAX_FONT_SIZE + 1] = {NULL};
1172 static void free_font_list(void);
1173 static TTF_Font* get_font(int size);
1174 static TTF_Font* load_font(const char* font_name, int font_size);
1175 #endif
1176
1177
1178
1179
1180 /* "Public" functions called from other files that use either */
1181 /*SDL_Pango or SDL_ttf: */
1182
1183
1184 /* For setup, we either initialize SDL_Pango and set its context, */
1185 /* or we initialize SDL_ttf: */
Setup_SDL_Text(void)1186 int Setup_SDL_Text(void)
1187 {
1188
1189 #ifdef HAVE_LIBSDL_PANGO
1190 LOG("Setup_SDL_Text() - using SDL_Pango\n");
1191
1192 SDLPango_Init();
1193 if (!Set_SDL_Pango_Font_Size(DEFAULT_MENU_FONT_SIZE))
1194 {
1195 fprintf(stderr, "\nError: I could not set SDL_Pango context\n");
1196 return 0;
1197 }
1198 #else
1199 /* using SDL_ttf: */
1200 LOG("Setup_SDL_Text() - using SDL_ttf\n");
1201
1202 if (TTF_Init() < 0)
1203 {
1204 fprintf(stderr, "\nError: I could not initialize SDL_ttf\n");
1205 return 0;
1206 }
1207 #endif
1208
1209 SDL_EnableKeyRepeat(0, SDL_DEFAULT_REPEAT_INTERVAL);
1210 SDL_EnableUNICODE(1);
1211 return 1;
1212 }
1213
1214
Cleanup_SDL_Text(void)1215 void Cleanup_SDL_Text(void)
1216 {
1217 #ifdef HAVE_LIBSDL_PANGO
1218 if(context != NULL)
1219 SDLPango_FreeContext(context);
1220 context = NULL;
1221 #else
1222 free_font_list();
1223 TTF_Quit();
1224 #endif
1225 }
1226
1227
1228 /* BlackOutline() creates a surface containing text of the designated */
1229 /* foreground color, surrounded by a black shadow, on a transparent */
1230 /* background. The appearance can be tuned by adjusting the number of */
1231 /* background copies and the offset where the foreground text is */
1232 /* finally written (see below). */
1233 //SDL_Surface* BlackOutline(const char *t, TTF_Font *font, SDL_Color *c)
BlackOutline(const char * t,int font_size,const SDL_Color * c)1234 SDL_Surface* BlackOutline(const char* t, int font_size, const SDL_Color* c)
1235 {
1236 SDL_Surface* out = NULL;
1237 SDL_Surface* black_letters = NULL;
1238 SDL_Surface* white_letters = NULL;
1239 SDL_Surface* bg = NULL;
1240 SDL_Rect dstrect;
1241 Uint32 color_key;
1242
1243 /* Make sure everything is sane before we proceed: */
1244 #ifdef HAVE_LIBSDL_PANGO
1245 if (!context)
1246 {
1247 fprintf(stderr, "BlackOutline(): invalid SDL_Pango context - returning.\n");
1248 return NULL;
1249 }
1250 #else
1251 TTF_Font* font = get_font(font_size);
1252 if (!font)
1253 {
1254 fprintf(stderr, "BlackOutline(): could not load needed font - returning.\n");
1255 return NULL;
1256 }
1257 #endif
1258
1259 if (!t || !c)
1260 {
1261 fprintf(stderr, "BlackOutline(): invalid ptr parameter, returning.\n");
1262 return NULL;
1263 }
1264
1265 if (t[0] == '\0')
1266 {
1267 LOG("BlackOutline(): empty string, returning\n");
1268 return NULL;
1269 }
1270
1271 DEBUGCODE
1272 {
1273 fprintf( stderr, "\nEntering BlackOutline(): \n");
1274 fprintf( stderr, "BlackOutline of \"%s\"\n", t );
1275 }
1276
1277 #ifdef HAVE_LIBSDL_PANGO
1278 Set_SDL_Pango_Font_Size(font_size);
1279 SDLPango_SetDefaultColor(context, MATRIX_TRANSPARENT_BACK_BLACK_LETTER);
1280 SDLPango_SetText(context, t, -1);
1281 black_letters = SDLPango_CreateSurfaceDraw(context);
1282 #else
1283 black_letters = TTF_RenderUTF8_Blended(font, t, black);
1284 #endif
1285
1286 if (!black_letters)
1287 {
1288 fprintf (stderr, "Warning - BlackOutline() could not create image for %s\n", t);
1289 return NULL;
1290 }
1291
1292 bg = SDL_CreateRGBSurface(SDL_SWSURFACE,
1293 (black_letters->w) + 5,
1294 (black_letters->h) + 5,
1295 32,
1296 rmask, gmask, bmask, amask);
1297 /* Use color key for eventual transparency: */
1298 color_key = SDL_MapRGB(bg->format, 01, 01, 01);
1299 SDL_FillRect(bg, NULL, color_key);
1300
1301 /* Now draw black outline/shadow 2 pixels on each side: */
1302 dstrect.w = black_letters->w;
1303 dstrect.h = black_letters->h;
1304
1305 /* NOTE: can make the "shadow" more or less pronounced by */
1306 /* changing the parameters of these loops. */
1307 for (dstrect.x = 1; dstrect.x < 4; dstrect.x++)
1308 for (dstrect.y = 1; dstrect.y < 3; dstrect.y++)
1309 SDL_BlitSurface(black_letters , NULL, bg, &dstrect );
1310
1311 SDL_FreeSurface(black_letters);
1312
1313 /* --- Put the color version of the text on top! --- */
1314 #ifdef HAVE_LIBSDL_PANGO
1315 /* convert color arg: */
1316 SDLPango_Matrix* color_matrix = SDL_Colour_to_SDLPango_Matrix(c);
1317
1318 if (color_matrix)
1319 {
1320 SDLPango_SetDefaultColor(context, color_matrix);
1321 free(color_matrix);
1322 }
1323 else /* fall back to just using white if conversion fails: */
1324 SDLPango_SetDefaultColor(context, MATRIX_TRANSPARENT_BACK_WHITE_LETTER);
1325
1326 white_letters = SDLPango_CreateSurfaceDraw(context);
1327
1328 #else
1329 white_letters = TTF_RenderUTF8_Blended(font, t, *c);
1330 #endif
1331
1332 if (!white_letters)
1333 {
1334 fprintf (stderr, "Warning - BlackOutline() could not create image for %s\n", t);
1335 return NULL;
1336 }
1337
1338 dstrect.x = 1;
1339 dstrect.y = 1;
1340 SDL_BlitSurface(white_letters, NULL, bg, &dstrect);
1341 SDL_FreeSurface(white_letters);
1342
1343 /* --- Convert to the screen format for quicker blits --- */
1344 SDL_SetColorKey(bg, SDL_SRCCOLORKEY|SDL_RLEACCEL, color_key);
1345 out = SDL_DisplayFormatAlpha(bg);
1346 SDL_FreeSurface(bg);
1347
1348 DEBUGCODE
1349 { fprintf( stderr, "\nLeaving BlackOutline(): \n"); }
1350
1351
1352 return out;
1353 }
1354
1355
1356
BlackOutline_w(const wchar_t * t,int font_size,const SDL_Color * c,int length)1357 SDL_Surface* BlackOutline_w(const wchar_t* t, int font_size, const SDL_Color* c, int length)
1358 {
1359 wchar_t wchar_tmp[1024];
1360 char tmp[1024];
1361 int i;
1362
1363 // Safety checks:
1364 if (!t || !c)
1365 {
1366 fprintf(stderr, "BlackOutline_w(): invalid ptr parameter, returning.\n");
1367 return NULL;
1368 }
1369
1370 if (t[0] == '\0')
1371 {
1372 fprintf(stderr, "BlackOutline_w(): empty string, returning\n");
1373 return NULL;
1374 }
1375
1376 wcsncpy(wchar_tmp, t, length);
1377 wchar_tmp[length] = '\0';
1378
1379 DEBUGCODE
1380 {
1381 fprintf(stderr, "In BlackOutline_w() - input wchar_t string is: %S\n", wchar_tmp);
1382 }
1383
1384 i = ConvertToUTF8(wchar_tmp, tmp, 1024);
1385 //tmp[i] = 0;
1386
1387 DEBUGCODE
1388 {
1389 fprintf(stderr, "In BlackOutline_w() - converted UTF8 string is: %s\n", tmp);
1390 }
1391
1392 return BlackOutline(tmp, font_size, c);
1393 }
1394
1395 /* This (fast) function just returns a non-outlined surf */
1396 /* using either SDL_Pango or SDL_ttf */
SimpleText(const char * t,int size,const SDL_Color * col)1397 SDL_Surface* SimpleText(const char *t, int size, const SDL_Color* col)
1398 {
1399 SDL_Surface* surf = NULL;
1400
1401 if (!t||!col)
1402 return NULL;
1403
1404 #ifdef HAVE_LIBSDL_PANGO
1405 if (!context)
1406 {
1407 fprintf(stderr, "SimpleText() - context not valid!\n");
1408 return NULL;
1409 }
1410 else
1411 {
1412 SDLPango_Matrix colormatrix =
1413 {
1414 col->r, col->r, 0, 0,
1415 col->g, col->g, 0, 0,
1416 col->b, col->b, 0, 0,
1417 0, 255, 0, 0,
1418 };
1419 Set_SDL_Pango_Font_Size(size);
1420 SDLPango_SetDefaultColor(context, &colormatrix );
1421 SDLPango_SetText(context, t, -1);
1422 surf = SDLPango_CreateSurfaceDraw(context);
1423 }
1424
1425 #else
1426 {
1427 TTF_Font* font = get_font(size);
1428 if (!font)
1429 return NULL;
1430 surf = TTF_RenderUTF8_Blended(font, t, *col);
1431 }
1432 #endif
1433
1434 return surf;
1435 }
1436
1437
1438 /*-----------------------------------------------------------*/
1439 /* Local functions, callable only within SDL_extras, divided */
1440 /* according with which text lib we are using: */
1441 /*-----------------------------------------------------------*/
1442
1443
1444
1445 #ifdef HAVE_LIBSDL_PANGO
1446
1447 /* Local functions when using SDL_Pango: ------------------------------- */
1448
1449 /* NOTE the scaling by 3/4 a few lines down represents a conversion from */
1450 /* the usual text dpi of 72 to the typical screen dpi of 96. It gives */
1451 /* font sizes fairly similar to a SDL_ttf font with the same numerical value. */
Set_SDL_Pango_Font_Size(int size)1452 static int Set_SDL_Pango_Font_Size(int size)
1453 {
1454 /* static so we can "remember" values from previous time through: */
1455 static int prev_pango_font_size;
1456 static char prev_font_name[FNLEN];
1457 /* Do nothing unless we need to change size or font: */
1458 if ((size == prev_pango_font_size)
1459 &&
1460 (0 == strncmp(prev_font_name, settings.theme_font_name, sizeof(prev_font_name))))
1461 return 1;
1462 else
1463 {
1464 char buf[64];
1465 DEBUGCODE { fprintf(stderr, "Setting font size to %d\n", size); }
1466 if(context != NULL)
1467 SDLPango_FreeContext(context);
1468 context = NULL;
1469 snprintf(buf, sizeof(buf), "%s %d", settings.theme_font_name, (int)((size * 3)/4));
1470 #ifdef HAVE_SDLPANGO_CREATECONTEXT_GIVENFONTDESC
1471 context = SDLPango_CreateContext_GivenFontDesc(buf);
1472 #else
1473 fprintf(stderr, "SDL_Pango version is missing needed function:\n"
1474 "SDLPango_CreateContext_GivenFontDesc()\n"
1475 "Will not be able to set font size.\n");
1476 #endif
1477 }
1478
1479 if (!context)
1480 return 0;
1481 else
1482 {
1483 prev_pango_font_size = size;
1484 strncpy(prev_font_name, settings.theme_font_name, sizeof(prev_font_name));
1485 return 1;
1486 }
1487 }
1488
1489
SDL_Colour_to_SDLPango_Matrix(const SDL_Color * cl)1490 SDLPango_Matrix* SDL_Colour_to_SDLPango_Matrix(const SDL_Color *cl)
1491 {
1492 int k = 0;
1493 SDLPango_Matrix* colour = NULL;
1494
1495 if (!cl)
1496 {
1497 fprintf(stderr, "Invalid SDL_Color* arg\n");
1498 return NULL;
1499 }
1500
1501 colour = (SDLPango_Matrix*)malloc(sizeof(SDLPango_Matrix));
1502
1503 for(k = 0; k < 4; k++)
1504 {
1505 (*colour).m[0][k] = (*cl).r;
1506 (*colour).m[1][k] = (*cl).g;
1507 (*colour).m[2][k] = (*cl).b;
1508 }
1509 (*colour).m[3][0] = 0;
1510 (*colour).m[3][1] = 255;
1511 (*colour).m[3][2] = 0;
1512 (*colour).m[3][3] = 0;
1513
1514 return colour;
1515 }
1516
1517 #else
1518 /* Local functions when using SDL_ttf: */
1519
free_font_list(void)1520 static void free_font_list(void)
1521 {
1522 int i;
1523 for(i = 0; i < MAX_FONT_SIZE; i++)
1524 {
1525 if(font_list[i])
1526 {
1527 TTF_CloseFont(font_list[i]);
1528 font_list[i] = NULL;
1529 }
1530 }
1531 }
1532
1533
1534
1535 /* Loads and caches fonts in each size as they are requested: */
1536 /* We use the font size as an array index, keeping each size */
1537 /* font in memory once loaded until cleanup. */
get_font(int size)1538 static TTF_Font* get_font(int size)
1539 {
1540 static char prev_font_name[FNLEN];
1541
1542 if (size < 0)
1543 {
1544 fprintf(stderr, "Error - requested font size %d is negative\n", size);
1545 return NULL;
1546 }
1547
1548 if (size > MAX_FONT_SIZE)
1549 {
1550 fprintf(stderr, "Error - requested font size %d exceeds max = %d, resetting.\n",
1551 size, MAX_FONT_SIZE);
1552 size = MAX_FONT_SIZE;
1553 }
1554
1555 /* If the font has changed, we need to wipe out the old ones: */
1556 if (0 != strncmp(prev_font_name, settings.theme_font_name, FNLEN))
1557 {
1558 free_font_list();
1559 strncpy(prev_font_name, settings.theme_font_name, sizeof(prev_font_name));
1560 }
1561
1562 /* If we can't load the font, this will return NULL: */
1563 if(font_list[size] == NULL)
1564 font_list[size] = load_font(settings.theme_font_name, size);
1565 return font_list[size];
1566 }
1567
1568
1569 /* FIXME need code to search for font paths on different platforms */
load_font(const char * font_name,int font_size)1570 static TTF_Font* load_font(const char* font_name, int font_size)
1571 {
1572 TTF_Font* loaded_font = NULL;
1573 char fn[FNLEN];
1574
1575 /* try to find font in default data dir: */
1576 sprintf(fn, "%s/fonts/%s", settings.default_data_path, font_name);
1577
1578 DEBUGCODE { fprintf(stderr, "load_font(): looking for %s using bundled data paths\n", fn); }
1579
1580 /* try to load the font, if successful, return font*/
1581 loaded_font = TTF_OpenFont(fn, font_size);
1582 if (loaded_font != NULL)
1583 {
1584 DEBUGCODE { fprintf(stderr, "load_font(): found bundled font: %s\n", fn); }
1585 return loaded_font;
1586 }
1587
1588
1589
1590 /* HACK hard-coded for Debian (and current exact font names): */
1591
1592 if (strncmp(font_name, "AndikaDesRevG.ttf", FNLEN ) == 0)
1593 sprintf(fn, "/usr/share/fonts/truetype/ttf-sil-andika/AndikaDesRevG.ttf");
1594 else if (strncmp(font_name, "DoulosSILR.ttf", FNLEN ) == 0)
1595 sprintf(fn, "/usr/share/fonts/truetype/ttf-sil-doulos/DoulosSILR.ttf");
1596 else if (strncmp(font_name, "Kedage-n.ttf", FNLEN ) == 0)
1597 sprintf(fn, "/usr/share/fonts/truetype/ttf-kannada-fonts/Kedage-n.ttf");
1598 else if (strncmp(font_name, "lohit_bn.ttf", FNLEN ) == 0)
1599 sprintf(fn, "/usr/share/fonts/truetype/ttf-bengali-fonts/lohit_bn.ttf");
1600 else if (strncmp(font_name, "lohit_gu.ttf", FNLEN ) == 0)
1601 sprintf(fn, "/usr/share/fonts/truetype/ttf-indic-fonts-core/lohit_gu.ttf");
1602 else if (strncmp(font_name, "lohit_hi.ttf", FNLEN ) == 0)
1603 sprintf(fn, "/usr/share/fonts/truetype/ttf-indic-fonts-core/lohit_hi.ttf");
1604 else if (strncmp(font_name, "lohit_pa.ttf", FNLEN ) == 0)
1605 sprintf(fn, "/usr/share/fonts/truetype/ttf-indic-fonts-core/lohit_pa.ttf");
1606 else if (strncmp(font_name, "lohit_ta.ttf", FNLEN ) == 0)
1607 sprintf(fn, "/usr/share/fonts/truetype/ttf-indic-fonts-core/lohit_ta.ttf");
1608 else if (strncmp(font_name, "Rachana_w01.ttf", FNLEN ) == 0)
1609 sprintf(fn, "/usr/share/fonts/truetype/ttf-malayalam-fonts/Rachana_w01.ttf");
1610 else if (strncmp(font_name, "utkal.ttf", FNLEN ) == 0)
1611 sprintf(fn, "/usr/share/fonts/truetype/ttf-indic-fonts-core/utkal.ttf");
1612 else if (strncmp(font_name, "Vemana.ttf", FNLEN ) == 0)
1613 sprintf(fn, "/usr/share/fonts/truetype/ttf-indic-fonts-core/Vemena.ttf");
1614
1615
1616
1617 DEBUGCODE { fprintf(stderr, "load_font(): looking for %s\n in OS' font path\n", fn); }
1618
1619 /* try to load the font, if successful, return font*/
1620 loaded_font = TTF_OpenFont(fn, font_size);
1621 if (loaded_font != NULL)
1622 {
1623 DEBUGCODE { fprintf(stderr, "load_font(): found font in OS' location: %s\n", fn); }
1624 return loaded_font;
1625 }
1626 /* We could not find desired font. If we were looking for something other */
1627 /* than default (Andika) font, print warning and try to load default font: */
1628 if (strncmp(font_name, DEFAULT_FONT_NAME, FNLEN ) != 0)
1629 {
1630 fprintf(stderr, "Warning - could not load desired font: %s\n", font_name);
1631 fprintf(stderr, "Trying to load default instead: %s\n", DEFAULT_FONT_NAME);
1632 return load_font(DEFAULT_FONT_NAME, font_size);
1633 }
1634 else /* Default failed also - bummer! */
1635 {
1636 fprintf(stderr, "LoadFont(): Error - couldn't load either selected or default font\n");
1637 return NULL;
1638 }
1639 }
1640
1641 #endif
1642