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