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