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