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