]> git.mxchange.org Git - quix0rs-blobwars.git/blob - src/CGraphics.cpp
Added .gitignore to ignore certain files + fixed access rights on Makefile* as
[quix0rs-blobwars.git] / src / CGraphics.cpp
1 /*
2 Copyright (C) 2004-2011 Parallel Realities
3 Copyright (C) 2011-2015 Perpendicular Dimensions
4
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13
14 See the GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19
20 */
21
22 #include "headers.h"
23
24 void SDL_SetAlpha(SDL_Surface *surface, uint8_t value) {
25         SDL_SetSurfaceBlendMode(surface, SDL_BLENDMODE_BLEND);
26         SDL_SetSurfaceAlphaMod(surface, value);
27 }
28
29 Graphics::Graphics()
30 {
31         for (int i = 0 ; i < MAX_TILES ; i++)
32         {
33                 tile[i] = NULL;
34         }
35
36         background = NULL;
37         infoMessage = NULL;
38
39         fontSize = 0;
40         
41         medalMessageTimer = 0;
42         medalType = 0;
43
44         currentLoading = 0;
45
46         screenShotNumber = 0;
47         takeRandomScreenShots = false;
48
49         waterAnim = 201;
50         slimeAnim = 208;
51         lavaAnim = 215;
52 }
53
54 void Graphics::free()
55 {
56         debug(("graphics.free: Background\n"));
57         if (background != NULL)
58         {
59                 SDL_FreeSurface(background);
60         }
61         debug(("graphics.free: Background - Done\n"));
62
63         background = NULL;
64
65         debug(("graphics.free: Tiles\n"));
66         for (int i = 0 ; i < MAX_TILES ; i++)
67         {
68                 if (tile[i] != NULL)
69                 {
70                         SDL_FreeSurface(tile[i]);
71                         tile[i] = NULL;
72                 }
73         }
74         debug(("graphics.free: Tiles - Done\n"));
75
76         debug(("graphics.free: Sprites\n"));
77         Sprite *sprite = (Sprite*)spriteList.getHead();
78         while (sprite->next != NULL)
79         {
80                 sprite = (Sprite*)sprite->next;
81                 //debug(("graphics.free: Sprites Sprite::Free - %s\n", sprite->name));
82                 sprite->free();
83         }
84         debug(("graphics.free: Sprites Clear()\n"));
85         spriteList.clear();
86         debug(("graphics.free: Sprites - Done\n"));
87 }
88
89 void Graphics::destroy()
90 {
91         free();
92
93         for (int i = 0 ; i < 5 ; i++)
94         {
95                 if (font[i])
96                 {
97                         TTF_CloseFont(font[i]);
98                 }
99         }
100         
101         if (medalMessage != NULL)
102         {
103                 SDL_FreeSurface(medalMessage);
104         }
105
106         if (fadeBlack)
107         {
108                 SDL_FreeSurface(fadeBlack);
109         }
110
111         if (infoBar)
112         {
113                 SDL_FreeSurface(infoBar);
114         }
115         
116         for (int i = 0 ; i < 4 ; i++)
117         {
118                 if (medal[i] != NULL)
119                 {
120                         SDL_FreeSurface(medal[i]);
121                         medal[i] = NULL;
122                 }
123         }
124 }
125
126 void Graphics::registerEngine(Engine *engine)
127 {
128         this->engine = engine;
129 }
130
131 void Graphics::mapColors()
132 {
133         red = SDL_MapRGB(screen->format, 0xff, 0x00, 0x00);
134         yellow = SDL_MapRGB(screen->format, 0xff, 0xff, 0x00);
135         green = SDL_MapRGB(screen->format, 0x00, 0xff, 0x00);
136         darkGreen = SDL_MapRGB(screen->format, 0x00, 0x77, 0x00);
137         skyBlue = SDL_MapRGB(screen->format, 0x66, 0x66, 0xff);
138         blue = SDL_MapRGB(screen->format, 0x00, 0x00, 0xff);
139         cyan = SDL_MapRGB(screen->format, 0x00, 0x99, 0xff);
140         white = SDL_MapRGB(screen->format, 0xff, 0xff, 0xff);
141         lightGrey = SDL_MapRGB(screen->format, 0xcc, 0xcc, 0xcc);
142         grey = SDL_MapRGB(screen->format, 0x88, 0x88, 0x88);
143         darkGrey = SDL_MapRGB(screen->format, 0x33, 0x33, 0x33);
144         black = SDL_MapRGB(screen->format, 0x00, 0x00, 0x00);
145
146         fontForeground.r = fontForeground.g = fontForeground.b = 0xff;
147         fontBackground.r = fontBackground.g = fontBackground.b = 0x00;
148
149         fadeBlack = alphaRect(640, 480, 0x00, 0x00, 0x00);
150
151         infoBar = alphaRect(640, 25, 0x00, 0x00, 0x00);
152         
153         medalMessage = NULL;
154 }
155
156 Sprite *Graphics::getSpriteHead()
157 {
158         return (Sprite*)spriteList.getHead();
159 }
160
161 void Graphics::setTransparent(SDL_Surface *sprite)
162 {
163         if (sprite)
164                 SDL_SetColorKey(sprite, SDL_TRUE, SDL_MapRGB(sprite->format, 0, 0, 0));
165 }
166
167 bool Graphics::canShowMedalMessage() const
168 {
169         return (medalMessageTimer <= 0);
170 }
171
172 void Graphics::updateScreen()
173 {
174         if (medalMessageTimer > 0)
175         {
176                 int padding = 0;
177                 
178                 medalMessageTimer--;
179                 
180                 if (medalType >= 0)
181                 {
182                         padding = 18;
183                 }
184                 
185                 drawRect(screen->w - (medalMessage->w + 5 + padding), 5, medalMessage->w + padding - 2, 20, grey, screen);
186                 drawRect(screen->w - (medalMessage->w + 5 + padding - 1), 6, medalMessage->w + padding - 4, 18, black, screen);
187                 blit(medalMessage, screen->w - (medalMessage->w + 5), 7, screen, false);
188                 
189                 if (medalType >= 0)
190                 {
191                         blit(medal[medalType], screen->w - (medalMessage->w + 5 + 16), 7, screen, false);
192                 }
193         }
194         
195         SDL_UpdateTexture(texture, NULL, screen->pixels, screen->w * 4);
196         SDL_RenderCopy(renderer, texture, NULL, NULL);
197         SDL_RenderPresent(renderer);
198         SDL_RenderClear(renderer);
199
200         if (takeRandomScreenShots)
201         {
202                 if ((Math::prand() % 500) == 0)
203                 {
204                         snprintf(screenshot, sizeof screenshot, "screenshots/screenshot%.3d.bmp", screenShotNumber);
205                         SDL_SaveBMP(screen, screenshot);
206                         screenShotNumber++;
207                 }
208
209                 SDL_Delay(16);
210         }
211
212         if (engine->keyState[SDL_SCANCODE_F12])
213         {
214                 snprintf(screenshot, sizeof screenshot, "screenshots/screenshot%.3d.bmp", screenShotNumber);
215                 SDL_SaveBMP(screen, screenshot);
216                 screenShotNumber++;
217
218                 engine->keyState[SDL_SCANCODE_F12] = 0;
219         }
220
221         if ((engine->keyState[SDL_SCANCODE_F10]) || ((engine->keyState[SDL_SCANCODE_RETURN]) && (engine->keyState[SDL_SCANCODE_LALT])))
222         {
223                 engine->fullScreen = !engine->fullScreen;
224                 SDL_SetWindowFullscreen(window, engine->fullScreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
225
226                 engine->keyState[SDL_SCANCODE_F10] = engine->keyState[SDL_SCANCODE_LALT] = engine->keyState[SDL_SCANCODE_RETURN] = 0;
227         }
228 }
229
230 void Graphics::delay(int time)
231 {
232         unsigned long then = SDL_GetTicks();
233
234         engine->keyState[SDL_SCANCODE_ESCAPE] = 0;
235
236         while (true)
237         {
238                 updateScreen();
239                 
240                 if (SDL_GetTicks() >= then + time)
241                 {
242                         break;
243                 }
244
245                 engine->getInput();
246                 
247                 /*
248                 if (engine->keyState[SDL_SCANCODE_ESCAPE])
249                 {
250                         break;
251                 }
252                 */
253         }
254 }
255
256 void Graphics::RGBtoHSV(float r, float g, float b, float *h, float *s, float *v)
257 {
258         float mn, mx, delta;
259         mn = min(min(r, g), b);
260         mx = max(max(r, g), b);
261         *v = mx;
262         delta = mx - mn;
263
264         if (mx != 0)
265         {
266                 *s = delta / mx;
267         }
268         else
269         {
270                 *s = 0;
271                 *h = -1;
272                 return;
273         }
274
275         if (r == mx)
276         {
277                 *h = (g - b) / delta;
278         }
279         else if (g == mx)
280         {
281                 *h = 2 + (b - r) / delta;
282         }
283         else
284         {
285                 *h = 4 + (r - g) / delta;
286         }
287
288         *h *= 60;
289
290         if (*h < 0)
291         {
292                 *h += 360;
293         }
294 }
295
296 void Graphics::HSVtoRGB(float *r, float *g, float *b, float h, float s, float v)
297 {
298         int i;
299         float f, p, q, t;
300         if (s == 0)
301         {
302                 *r = *g = *b = v;
303                 return;
304         }
305
306         h /= 60;
307         i = (int)(h);
308         f = h - i;
309         p = v * (1 - s);
310         q = v * (1 - s * f);
311         t = v * (1 - s * (1 - f));
312
313         switch (i)
314         {
315                 case 0:
316                         *r = v;
317                         *g = t;
318                         *b = p;
319                         break;
320
321                 case 1:
322                         *r = q;
323                         *g = v;
324                         *b = p;
325                         break;
326
327                 case 2:
328                         *r = p;
329                         *g = v;
330                         *b = t;
331                         break;
332
333                 case 3:
334                         *r = p;
335                         *g = q;
336                         *b = v;
337                         break;
338
339                 case 4:
340                         *r = t;
341                         *g = p;
342                         *b = v;
343                         break;
344
345                 default:
346                         *r = v;
347                         *g = p;
348                         *b = q;
349                         break;
350         }
351 }
352
353 SDL_Surface *Graphics::loadImage(const char *filename, bool srcalpha)
354 {
355         SDL_Surface *image, *newImage;
356
357         #if USEPAK
358                 if (!engine->unpack(filename, PAK_IMG))
359                         showErrorAndExit(ERR_FILE, filename);
360                 image = IMG_Load_RW(engine->sdlrw, 1);
361         #else
362                 image = IMG_Load(filename);
363         #endif
364
365         if (!image)
366                 return showErrorAndExit(ERR_FILE, filename), image;
367
368         newImage = SDL_ConvertSurface(image, screen->format, 0);
369
370         if (newImage)
371         {
372                 SDL_FreeSurface(image);
373         }
374         else
375         {
376                 // This happens when we are loading the window icon image
377                 newImage = image;
378         }
379
380         if(srcalpha)
381                 SDL_SetAlpha(newImage, 255);
382         else
383                 setTransparent(newImage);
384
385         return newImage;
386 }
387
388 SDL_Surface *Graphics::loadImage(const char *filename, int hue, int sat, int value)
389 {
390         SDL_Surface *image, *newImage;
391
392         #if USEPAK
393                 if (!engine->unpack(filename, PAK_IMG))
394                         showErrorAndExit(ERR_FILE, filename);
395                 image = IMG_Load_RW(engine->sdlrw, 1);
396         #else
397                 image = IMG_Load(filename);
398         #endif
399
400         if (!image)
401                 return showErrorAndExit(ERR_FILE, filename), image;
402
403         if ((hue != 0) || (sat != 0) || (value != 0))
404         {
405                 if (image->format->BitsPerPixel != 8)
406                 {
407                         debug(("WARNING: Could not set Hue for '%s'! Not an 8 bit image!\n", filename));
408                 }
409                 else
410                 {
411                         SDL_Color *color;
412                         float r, g, b, h, s, v;
413
414                         if (image->format->palette->colors != NULL)
415                         {
416                                 for (int i = 1 ; i < image->format->palette->ncolors ; i++)
417                                 {
418                                         color = &image->format->palette->colors[i];
419
420                                         r = (int)color->r;
421                                         g = (int)color->g;
422                                         b = (int)color->b;
423
424                                         RGBtoHSV(r, g, b, &h, &s, &v);
425
426                                         h += hue;
427                                         s += sat;
428                                         v += value;
429
430                                         HSVtoRGB(&r, &g, &b, h, s, v);
431
432                                         color->r = (int)r;
433                                         color->g = (int)g;
434                                         color->b = (int)b;
435
436                                 }
437                         }
438                 }
439         }
440
441         newImage = SDL_ConvertSurface(image, screen->format, 0);
442
443         if (newImage)
444         {
445                 SDL_FreeSurface(image);
446         }
447         else
448         {
449                 // This happens when we are loading the window icon image
450                 newImage = image;
451         }
452
453         setTransparent(newImage);
454
455         return newImage;
456 }
457
458 SDL_Surface *Graphics::quickSprite(const char *name, SDL_Surface *image)
459 {
460         Sprite *sprite = addSprite(name);
461         sprite->setFrame(0, image, 60);
462
463         return sprite->getCurrentFrame();
464 }
465
466 void Graphics::fade(int amount)
467 {
468         SDL_SetAlpha(fadeBlack, amount);
469         blit(fadeBlack, 0, 0, screen, false);
470 }
471
472 void Graphics::fadeToBlack()
473 {
474         int start = 0;
475
476         while (start < 50)
477         {
478                 SDL_SetAlpha(fadeBlack, start);
479                 blit(fadeBlack, 0, 0, screen, false);
480                 delay(60);
481                 start++;
482         }
483 }
484
485 void Graphics::loadMapTiles(const char *baseDir)
486 {
487         bool found, autoAlpha;
488         char filename[255];
489         filename[0] = 0;
490
491         autoAlpha = false;
492         
493         if (strcmp(baseDir, "gfx/common") == 0)
494         {
495                 autoAlpha = true;
496         }
497
498         #if !USEPAK
499         FILE *fp;
500         #endif
501
502         for (int i = 1 ; i < MAX_TILES ; i++)
503         {
504                 found = true;
505
506                 snprintf(filename, sizeof filename, "%s/%d.png", baseDir, i);
507
508                 #if USEPAK
509                 
510                 if (!engine->getPak()->fileExists(filename))
511                         continue;
512
513                 #else
514
515                 fp = fopen(filename, "rb");
516                 if (!fp)
517                         continue;
518                 fclose(fp);
519
520                 #endif
521
522                 if (found)
523                 {
524                         tile[i] = loadImage(filename);
525
526                         if (!tile[i])
527                                 abort();
528
529                         if (autoAlpha)
530                         {
531                                 if ((i < MAP_EXITSIGN) || (i >= MAP_WATERANIM))
532                                 {
533                                         SDL_SetAlpha(tile[i], 130);
534                                 }
535                         }
536                         else
537                         {
538                                 if (i < MAP_DECORATION)
539                                 {
540                                         SDL_SetColorKey(tile[i], 0, SDL_MapRGB(tile[i]->format, 0, 0, 0));
541                                 }
542                         }
543                 }
544         }
545 }
546
547 void Graphics::loadFont(int i, const char *filename, int pointSize)
548 {
549         debug(("Attempting to load font %s with point size of %d...\n", filename, pointSize));
550         
551         if (font[i])
552         {
553                 debug(("Freeing Font %d first...\n", i));
554                 TTF_CloseFont(font[i]);
555         }
556         
557         #if USEPAK
558                 (void)filename;
559                 char tempPath[PATH_MAX];
560                 snprintf(tempPath, sizeof tempPath, "%sfont.ttf", engine->userHomeDirectory);
561                 font[i] = TTF_OpenFont(tempPath, pointSize);
562         #else
563                 font[i] = TTF_OpenFont(filename, pointSize);
564         #endif
565
566         if (!font[i])
567         {
568                 engine->reportFontFailure();
569         }
570         
571         TTF_SetFontStyle(font[i], TTF_STYLE_NORMAL);
572 }
573
574 Sprite *Graphics::addSprite(const char *name)
575 {
576         Sprite *sprite = new Sprite;
577         strlcpy(sprite->name, name, sizeof sprite->name);
578
579         spriteList.add(sprite);
580
581         return sprite;
582 }
583
584 Sprite *Graphics::getSprite(const char *name, bool required)
585 {
586         Sprite *sprite = (Sprite*)spriteList.getHead();
587
588         while (sprite->next != NULL)
589         {
590                 sprite = (Sprite*)sprite->next;
591                 
592                 if (strcmp(sprite->name, name) == 0)
593                 {
594                         return sprite;
595                 }
596         }
597
598         if (required)
599                 showErrorAndExit("The requested sprite '%s' does not exist", name);
600
601         return NULL;
602 }
603
604 void Graphics::animateSprites()
605 {
606         Sprite *sprite = (Sprite*)spriteList.getHead();
607
608         while (sprite->next != NULL)
609         {
610                 sprite = (Sprite*)sprite->next;
611
612                 sprite->animate();
613         }
614
615         if ((engine->getFrameLoop() % 8) == 0)
616         {
617                 Math::wrapInt(&(++waterAnim), 201, 204);
618                 Math::wrapInt(&(++slimeAnim), 207, 212);
619                 Math::wrapInt(&(++lavaAnim), 214, 220);
620         }
621 }
622
623 int Graphics::getWaterAnim() const
624 {
625         return waterAnim;
626 }
627
628 int Graphics::getSlimeAnim() const
629 {
630         return slimeAnim;
631 }
632
633 int Graphics::getLavaAnim() const
634 {
635         return lavaAnim;
636 }
637
638 int Graphics::getLavaAnim(int current)
639 {
640         if ((engine->getFrameLoop() % 8) == 0)
641                 return Math::rrand(214, 220);
642
643         return current;
644 }
645
646 void Graphics::loadBackground(const char *filename)
647 {
648         if (background != NULL)
649                 SDL_FreeSurface(background);
650
651         if (strcmp(filename, "@none@") == 0)
652                 return;
653
654         background = loadImage(filename);
655
656         SDL_SetColorKey(background, 0, SDL_MapRGB(background->format, 0, 0, 0));
657 }
658
659 void Graphics::putPixel(int x, int y, Uint32 pixel, SDL_Surface *dest)
660 {
661         if ((x < 0) || (x > 639) || (y < 0) || (y > 479))
662                 return;
663
664         int bpp = dest->format->BytesPerPixel;
665         /* Here p is the address to the pixel we want to set */
666         Uint8 *p = (Uint8 *)dest->pixels + y * dest->pitch + x * bpp;
667
668         switch(bpp)
669         {
670                 case 1:
671                         *p = pixel;
672                         break;
673
674                 case 2:
675                         *(Uint16 *)p = pixel;
676                         break;
677
678                 case 3:
679                         if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
680                         {
681                                 p[0] = (pixel >> 16) & 0xff;
682                                 p[1] = (pixel >> 8) & 0xff;
683                                 p[2] = pixel & 0xff;
684                         }
685                         else
686                         {
687                                 p[0] = pixel & 0xff;
688                                 p[1] = (pixel >> 8) & 0xff;
689                                 p[2] = (pixel >> 16) & 0xff;
690                         }
691                         break;
692
693                 case 4:
694                         *(Uint32 *)p = pixel;
695                         break;
696         }
697 }
698
699 Uint32 Graphics::getPixel(SDL_Surface *surface, int x, int y)
700 {
701         if ((x < 0) || (x > (surface->w - 1)) || (y < 0) || (y > (surface->h - 1)))
702                 return 0;
703
704         int bpp = surface->format->BytesPerPixel;
705         Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;
706
707         switch(bpp) {
708         case 1:
709                 return *p;
710
711         case 2:
712                 return *(Uint16 *)p;
713
714         case 3:
715                 if(SDL_BYTEORDER == SDL_BIG_ENDIAN)
716                                 return p[0] << 16 | p[1] << 8 | p[2];
717                 else
718                                 return p[0] | p[1] << 8 | p[2] << 16;
719
720         case 4:
721                 return *(Uint32 *)p;
722
723         default:
724                 return 0;       /* shouldn't happen, but avoids warnings */
725         }
726 }
727
728 void Graphics::drawLine(float startX, float startY, float endX, float endY, int color, SDL_Surface *dest)
729 {
730         lock(screen);
731         
732         float dx, dy;
733         
734         Math::calculateSlope(startX, startY, endX, endY, &dx, &dy);
735
736         while (true)
737         {
738                 putPixel((int)startX, (int)startY, color, dest);
739
740                 if ((int)startX == (int)endX)
741                         break;
742
743                 startX -= dx;
744                 startY -= dy;
745         }
746
747         unlock(screen);
748 }
749
750 void Graphics::blit(SDL_Surface *image, int x, int y, SDL_Surface *dest, bool centered)
751 {
752         if (!image)
753         {
754                 return showErrorAndExit("graphics::blit() - NULL pointer", SDL_GetError());
755         }
756
757         if ((x < -image->w) || (x > 640 + image->w))
758                 return;
759
760         if ((y < -image->h) || (y > 480 + image->h))
761                 return;
762
763         // Set up a rectangle to draw to
764         gRect.x = x;
765         gRect.y = y;
766         if (centered)
767         {
768                 gRect.x -= (image->w / 2);
769                 gRect.y -= (image->h / 2);
770         }
771
772         gRect.w = image->w;
773         gRect.h = image->h;
774
775         /* Blit onto the screen surface */
776         if (SDL_BlitSurface(image, NULL, dest, &gRect) < 0)
777                 showErrorAndExit("graphics::blit() - %s", SDL_GetError());
778 }
779
780 void Graphics::drawBackground()
781 {
782         if (background != NULL)
783                 blit(background, 0, 0, screen, false);
784         else
785                 SDL_FillRect(screen, NULL, black);
786 }
787
788 void Graphics::drawBackground(SDL_Rect *r)
789 {
790         if (r->x < 0) r->x = 0;
791         if (r->y < 0) r->y = 0;
792         if (r->x + r->w > 639) r->w = 640 - r->x;
793         if (r->y + r->h > 639) r->h = 480 - r->y;
794
795         if (SDL_BlitSurface(background, r, screen, r) < 0)
796                 showErrorAndExit("graphics::blit() - %s", SDL_GetError());
797 }
798
799 void Graphics::drawRect(int x, int y, int w, int h, int color, SDL_Surface *dest)
800 {
801         gRect.x = x;
802         gRect.y = y;
803         gRect.w = w;
804         gRect.h = h;
805
806         SDL_FillRect(dest, &gRect, color);
807 }
808
809 void Graphics::drawRect(int x, int y, int w, int h, int color, int borderColor, SDL_Surface *dest)
810 {
811         drawRect(x - 1, y - 1, w + 2, h + 2, borderColor, dest);
812         drawRect(x, y, w, h, color, dest);
813 }
814
815 void Graphics::setFontColor(int red, int green, int blue, int red2, int green2, int blue2)
816 {
817         fontForeground.r = red;
818         fontForeground.g = green;
819         fontForeground.b = blue;
820
821         fontBackground.r = red2;
822         fontBackground.g = green2;
823         fontBackground.b = blue2;
824 }
825
826 void Graphics::setFontSize(int size)
827 {
828         fontSize = size;
829         Math::limitInt(&fontSize, 0, 4);
830 }
831
832 SDL_Surface *Graphics::getString(const char *in, bool transparent)
833 {
834         SDL_Surface *text = TTF_RenderUTF8_Shaded(font[fontSize], in, fontForeground, fontBackground);
835
836         if (!text)
837         {
838                 text = TTF_RenderUTF8_Shaded(font[fontSize], "FONT_ERROR", fontForeground, fontBackground);
839         }
840
841         if (!text)
842         {
843                 fprintf(stderr, "Unable to render text: %s\n", SDL_GetError());
844                 abort();
845         }
846
847         if (transparent)
848                 setTransparent(text);
849
850         return text;
851 }
852
853 void Graphics::drawString(const char *in, int x, int y, int alignment, SDL_Surface *dest)
854 {
855         bool center = false;
856
857         SDL_Surface *text = TTF_RenderUTF8_Shaded(font[fontSize], in, fontForeground, fontBackground);
858
859         if (!text)
860                 text = TTF_RenderUTF8_Shaded(font[fontSize], "FONT_ERROR", fontForeground, fontBackground);
861
862         if (!text)
863                 return;
864
865         setTransparent(text);
866
867         if (alignment == TXT_RIGHT) x -= text->w;
868         if (alignment == TXT_CENTERED) center = true;
869
870         blit(text, x, y, dest, center);
871         SDL_FreeSurface(text);
872 }
873
874 void Graphics::drawString(const char *in, int x, int y, int alignment, SDL_Surface *dest, SurfaceCache &cache)
875 {
876         bool center = false;
877
878         if(!cache.text || strcmp(in, cache.text)) {
879                 if(cache.surface)
880                         SDL_FreeSurface(cache.surface);
881
882                 if(cache.text)
883                         ::free(cache.text);
884
885                 cache.text = strdup(in);
886
887                 cache.surface = TTF_RenderUTF8_Shaded(font[fontSize], in, fontForeground, fontBackground);
888
889                 if (!cache.surface)
890                         cache.surface = TTF_RenderUTF8_Shaded(font[fontSize], "FONT_ERROR", fontForeground, fontBackground);
891
892                 if(!cache.surface)
893                         return;
894
895                 setTransparent(cache.surface);
896         }
897
898         if (alignment == TXT_RIGHT) x -= cache.surface->w;
899         if (alignment == TXT_CENTERED) center = true;
900
901         blit(cache.surface, x, y, dest, center);
902 }
903
904 void Graphics::clearChatString()
905 {
906         chatString[0] = 0;
907 }
908
909 void Graphics::createChatString(const char *in)
910 {
911         strlcat(chatString, " ", sizeof chatString);
912         strlcat(chatString, in, sizeof chatString);
913 }
914
915 void Graphics::drawChatString(SDL_Surface *surface, int y)
916 {
917         char *word = strtok(chatString, " ");
918         char wordWithSpace[100];
919         
920         int r, g, b;
921
922         int x = 10;
923         int surfaceWidth = surface->w - 10;
924
925         SDL_Surface *wordSurface;
926
927         while (word)
928         {
929                 if (strcmp(word, "<RGB>") == 0)
930                 {
931                         r = atoi(strtok(NULL, " "));
932                         g = atoi(strtok(NULL, " "));
933                         b = atoi(strtok(NULL, " "));
934
935                         if ((!r) && (!g) && (!b))
936                         {
937                                 debug(("Parse Error in Text Color (%d:%d:%d)!!\n", r, g, b));
938                                 exit(1);
939                         }
940
941                         setFontColor(r, g, b, 0, 0, 0);
942
943                         word = strtok(NULL, " ");
944
945                         continue;
946                 }
947
948                 snprintf(wordWithSpace, sizeof wordWithSpace, "%s ", word);
949
950                 wordSurface = getString(wordWithSpace, false);
951
952                 if (x + wordSurface->w > surfaceWidth)
953                 {
954                         y += (int)(wordSurface->h * 1.5) ;
955                         x = 10;
956                 }
957
958                 blit(wordSurface, x, y, surface, false);
959
960                 x += wordSurface->w;
961
962                 SDL_FreeSurface(wordSurface);
963
964                 word = strtok(NULL, " ");
965         }
966 }
967
968 void Graphics::showMedalMessage(int type, const char *in)
969 {
970         char message[1024];
971         
972         if (medalMessage != NULL)
973         {
974                 SDL_FreeSurface(medalMessage);
975         }
976         
977         setFontSize(0);
978         
979         switch (type)
980         {
981                 // Bronze
982                 case 1:
983                         setFontColor(0xA6, 0x7D, 0x3D, 0x00, 0x00, 0x00);
984                         break;
985                 
986                 // Silver
987                 case 2:
988                         setFontColor(0xC0, 0xC0, 0xC0, 0x00, 0x00, 0x00);
989                         break;
990                         
991                 // Gold
992                 case 3:
993                         setFontColor(0xFF, 0xCC, 0x33, 0x00, 0x00, 0x00);
994                         break;
995                         
996                 // Ruby
997                 case 4:
998                         setFontColor(0xFF, 0x11, 0x55, 0x00, 0x00, 0x00);
999                         break;
1000         }
1001         
1002         medalType = type - 1; // for indexing on the image
1003         if (type != -1)
1004         {
1005                 snprintf(message, sizeof message, "  Medal Earned - %s  ", in);
1006                 medalMessage = getString(message, true);
1007         }
1008         else
1009         {
1010                 snprintf(message, sizeof message, "  %s  ", in);
1011                 medalMessage = getString(message, true);
1012         }
1013         medalMessageTimer = (5 * 60);
1014 }
1015
1016 void Graphics::drawWidgetRect(int x, int y, int w, int h)
1017 {
1018         drawRect(x - 5, y - 4, w + 10, h + 8, white, screen);
1019         drawRect(x - 4, y - 3, w + 8, h + 6, black, screen);
1020         drawRect(x - 3, y - 2, w + 6, h + 4, green, screen);
1021 }
1022
1023 SDL_Surface *Graphics::createSurface(int width, int height)
1024 {
1025         SDL_Surface *surface, *newImage;
1026
1027         surface = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, screen->format->BitsPerPixel, screen->format->Rmask, screen->format->Gmask, screen->format->Bmask, screen->format->Amask);
1028
1029         if (surface == NULL)
1030                 showErrorAndExit("CreateRGBSurface failed: %s\n", SDL_GetError());
1031
1032         newImage = SDL_ConvertSurface(surface, screen->format, 0);
1033
1034         SDL_FreeSurface(surface);
1035
1036         return newImage;
1037 }
1038
1039 SDL_Surface *Graphics::alphaRect(int width, int height, Uint8 red, Uint8 green, Uint8 blue)
1040 {
1041         SDL_Surface *surface = createSurface(width, height);
1042
1043         SDL_FillRect(surface, NULL, SDL_MapRGB(surface->format, red, green, blue));
1044
1045         SDL_SetAlpha(surface, 130);
1046
1047         return surface;
1048 }
1049
1050 void Graphics::colorize(SDL_Surface *image, int red, int green, int blue)
1051 {
1052         SDL_Surface *alpha = alphaRect(image->w, image->h, red, green, blue);
1053
1054         blit(alpha, 0, 0, image, false);
1055
1056         SDL_SetColorKey(image, SDL_TRUE, SDL_MapRGB(image->format, red / 2, green / 2, blue / 2));
1057 }
1058
1059 void Graphics::lock(SDL_Surface *surface)
1060 {
1061         /* Lock the screen for direct access to the pixels */
1062         if (SDL_MUSTLOCK(surface))
1063         {
1064                 if (SDL_LockSurface(surface) < 0 )
1065                 {
1066                         showErrorAndExit("Could not lock surface", "");
1067                 }
1068         }
1069 }
1070
1071 void Graphics::unlock(SDL_Surface *surface)
1072 {
1073         if (SDL_MUSTLOCK(surface))
1074         {
1075                 SDL_UnlockSurface(surface);
1076         }
1077 }
1078
1079 void Graphics::resetLoading()
1080 {
1081         currentLoading = 0;
1082 }
1083
1084 void Graphics::showLoading(int amount, int max)
1085 {
1086         #if USEPAK
1087         max *= 4;
1088
1089         if (max > 398)
1090                 max = 398;
1091
1092         Math::limitInt(&(currentLoading += amount), 0, max);
1093
1094         drawRect(120, 420, 400, 10, black, white, screen);
1095         drawRect(121, 421, currentLoading, 8, red, screen);
1096         #else
1097         (void)amount;
1098         (void)max;
1099         #endif
1100 }
1101
1102 void Graphics::showLicenseErrorAndExit()
1103 {
1104         setFontSize(3); setFontColor(0xff, 0x00, 0x00, 0x00, 0x00, 0x00);
1105         drawString("License Agreement Missing", 320, 50, true, screen);
1106         
1107         setFontSize(1); setFontColor(0xff, 0xff, 0xff, 0x00, 0x00, 0x00);
1108
1109         drawString("The GNU General Public License was not found.", 320, 180, true, screen);
1110         drawString("It could either not be properly loaded or has been removed.", 320, 220, true, screen);
1111         drawString("Blob Wars : Metal Blob Solid will not run with the license missing.", 320, 260, true, screen);
1112         
1113         drawString("Blob Wars : Metal Blob Solid will now exit", 320, 420, true, screen);
1114         drawString("Press Escape to continue", 320, 450, true, screen);
1115
1116         engine->flushInput();
1117
1118         while (true)
1119         {
1120                 updateScreen();
1121                 engine->getInput();
1122                 if (engine->keyState[SDL_SCANCODE_ESCAPE])
1123                         exit(1);
1124                 SDL_Delay(16);
1125         }
1126 }
1127
1128 void Graphics::showErrorAndExit(const char *error, const char *param)
1129 {
1130         SDL_FillRect(screen, NULL, black);
1131
1132         if (strcmp(param, "LICENSE") == 0)
1133         {
1134                 showLicenseErrorAndExit();
1135         }
1136
1137         char message[256];
1138         snprintf(message, sizeof message, error, param);
1139
1140         setFontSize(3); setFontColor(0xff, 0x00, 0x00, 0x00, 0x00, 0x00);
1141         drawString("An unforseen error has occurred", 320, 50, true, screen);
1142         setFontSize(1); setFontColor(0xff, 0xff, 0xff, 0x00, 0x00, 0x00);
1143         drawString(message, 320, 90, true, screen);
1144
1145         drawString("You may wish to try the following,", 50, 150, false, screen);
1146
1147         setFontSize(0);
1148         drawString("1) Try reinstalling the game.", 75, 190, false, screen);
1149         drawString("2) Ensure you have SDL 1.2.5 or greater installed.", 75, 210, false, screen);
1150         drawString("3) Ensure you have the latest versions of additional required SDL libraries.", 75, 230, false, screen);
1151         drawString("4) Install using an RPM if you originally built the game from source", 75, 250, false, screen);
1152         drawString("or try building from source if you installed using an RPM.", 75, 270, false, screen);
1153         drawString("5) Visit http://www.parallelrealities.co.uk/blobWars.php and check for updates.", 75, 290, false, screen);
1154
1155         setFontSize(1);
1156
1157         drawString("If problems persist contact Parallel Realities. Please be aware however that we will not", 320, 360, true, screen);
1158         drawString("be able to assist in cases where the code or data has been modified.", 320, 380, true, screen);
1159
1160         drawString("Blob Wars : Metal Blob Solid will now exit", 320, 420, true, screen);
1161         drawString("Press Escape to continue", 320, 450, true, screen);
1162
1163         engine->flushInput();
1164
1165         while (true)
1166         {
1167                 updateScreen();
1168                 engine->getInput();
1169                 if (engine->keyState[SDL_SCANCODE_ESCAPE])
1170                 {
1171                         exit(1);
1172                 }
1173                 SDL_Delay(16);
1174         }
1175 }
1176
1177 void Graphics::showRootWarning()
1178 {
1179         setFontSize(3); setFontColor(0xff, 0x00, 0x00, 0x00, 0x00, 0x00);
1180         drawString("CAUTION - RUNNING AS ROOT USER!", 320, 50, true, screen);
1181         
1182         setFontSize(1); setFontColor(0xff, 0xff, 0xff, 0x00, 0x00, 0x00);
1183
1184         drawString("WARNING - You appear to be running the game as the root user!", 320, 180, true, screen);
1185         drawString("This is not recommended and is it strongly advised that you do not run", 320, 220, true, screen);
1186         drawString("the game as root. You may still continue but consider running as regular user in future!", 320, 260, true, screen);
1187         
1188         drawString("Press Space to Exit", 320, 420, true, screen);
1189         drawString("Press Escape to Continue", 320, 450, true, screen);
1190
1191         engine->flushInput();
1192
1193         while (true)
1194         {
1195                 updateScreen();
1196                 engine->getInput();
1197                 
1198                 if (engine->keyState[SDL_SCANCODE_ESCAPE])
1199                 {
1200                         return;
1201                 }
1202                 else if (engine->keyState[SDL_SCANCODE_SPACE])
1203                 {
1204                         exit(0);
1205                 }
1206
1207                 SDL_Delay(16);
1208         }
1209 }