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