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