1 /*
2 Copyright (C) 2009-2021 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, 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
18 */
19 
20 #include "../headers.h"
21 
22 #include "../collisions.h"
23 #include "../entity.h"
24 #include "../map.h"
25 #include "../system/error.h"
26 #include "../system/pak.h"
27 #include "decoration.h"
28 #include "graphics.h"
29 #include "save_png.h"
30 
31 extern Game game;
32 extern Entity *self;
33 
34 static Uint32 getPixel(SDL_Surface *, int, int);
35 static void putPixel(int, int, Colour);
36 static void putPixelToSurface(SDL_Surface *, int, int, Uint32);
37 Texture *convertSurfaceToTexture(SDL_Surface *, int);
38 void destroyTexture(Texture *);
39 
40 static char screenshotPath[MAX_PATH_LENGTH];
41 static int frame = 0;
42 
loadImage(char * name)43 Texture *loadImage(char *name)
44 {
45 	/* Load the image using SDL Image */
46 
47 	SDL_Surface *image;
48 	Texture *texture;
49 
50 	image = loadImageFromPak(name);
51 
52 	texture = convertSurfaceToTexture(image, TRUE);
53 
54 	/* Return the processed image */
55 
56 	return texture;
57 }
58 
loadImageAsSurface(char * name)59 SDL_Surface *loadImageAsSurface(char *name)
60 {
61 	/* Load the image using SDL Image */
62 
63 	SDL_Surface *image;
64 
65 	image = loadImageFromPak(name);
66 
67 	/* Return the processed image */
68 
69 	return image;
70 }
71 
convertSurfaceToTexture(SDL_Surface * surface,int delete)72 Texture *convertSurfaceToTexture(SDL_Surface *surface, int delete)
73 {
74 	SDL_Texture *texture;
75 	Texture *textureWrapper;
76 
77 	textureWrapper = malloc(sizeof(Texture));
78 
79 	if (textureWrapper == NULL)
80 	{
81 		showErrorAndExit("Failed to allocate %ld bytes to create texture", sizeof(Texture));
82 	}
83 
84 	texture = SDL_CreateTextureFromSurface(game.renderer, surface);
85 
86 	if (texture == NULL)
87 	{
88 		showErrorAndExit("Failed to convert image to texture");
89 	}
90 
91 	textureWrapper->texture = texture;
92 
93 	textureWrapper->w = surface->w;
94 	textureWrapper->h = surface->h;
95 
96 	if (delete == TRUE)
97 	{
98 		SDL_FreeSurface(surface);
99 	}
100 
101 	return textureWrapper;
102 }
103 
createTexture(int width,int height,int r,int g,int b)104 Texture *createTexture(int width, int height, int r, int g, int b)
105 {
106 	Texture *texture;
107 	SDL_Surface *surface;
108 
109 	surface = createSurface(width, height, FALSE);
110 
111 	SDL_FillRect(surface, NULL, SDL_MapRGB(surface->format, r, g, b));
112 
113 	texture = convertSurfaceToTexture(surface, TRUE);
114 
115 	return texture;
116 }
117 
createWritableTexture(int width,int height)118 Texture *createWritableTexture(int width, int height)
119 {
120 	SDL_Texture *texture;
121 	Texture *textureWrapper;
122 
123 	textureWrapper = malloc(sizeof(Texture));
124 
125 	if (textureWrapper == NULL)
126 	{
127 		showErrorAndExit("Failed to allocate %ld bytes to create texture", sizeof(Texture));
128 	}
129 
130 	texture = SDL_CreateTexture(game.renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, width, height);
131 
132 	if (texture == NULL)
133 	{
134 		showErrorAndExit("Failed to create writable texture");
135 	}
136 
137 	textureWrapper->texture = texture;
138 
139 	textureWrapper->w = width;
140 	textureWrapper->h = height;
141 
142 	return textureWrapper;
143 }
144 
destroyTexture(Texture * image)145 void destroyTexture(Texture *image)
146 {
147 	if (image != NULL)
148 	{
149 		SDL_DestroyTexture(image->texture);
150 
151 		free(image);
152 	}
153 }
154 
drawImage(Texture * image,int x,int y,int flip,int alpha)155 void drawImage(Texture *image, int x, int y, int flip, int alpha)
156 {
157 	SDL_Rect dest;
158 
159 	if (alpha == 0)
160 	{
161 		return;
162 	}
163 
164 	/* Set the blitting rectangle to the size of the source image */
165 
166 	dest.x = game.offsetX + x;
167 	dest.y = game.offsetY + y;
168 	dest.w = image->w;
169 	dest.h = image->h;
170 
171 	if (alpha != 255 && alpha != -1)
172 	{
173 		SDL_SetTextureAlphaMod(image->texture, alpha);
174 	}
175 
176 	/* Blit the entire image onto the screen at coordinates x and y */
177 
178 	SDL_RenderCopyEx(game.renderer, image->texture, NULL, &dest, 0, NULL, flip == TRUE ? SDL_FLIP_HORIZONTAL : SDL_FLIP_NONE);
179 
180 	SDL_SetTextureAlphaMod(image->texture, 255);
181 }
182 
drawImageToMap(Texture * image,int x,int y,int flip,int alpha)183 void drawImageToMap(Texture *image, int x, int y, int flip, int alpha)
184 {
185 	drawImage(image, x - getMapStartX(), y - getMapStartY(), flip, alpha);
186 }
187 
drawClippedImage(Texture * image,int srcX,int srcY,int destX,int destY,int width,int height)188 void drawClippedImage(Texture *image, int srcX, int srcY, int destX, int destY, int width, int height)
189 {
190 	SDL_Rect src, dest;
191 
192 	src.x = srcX;
193 	src.y = srcY;
194 	src.w = width;
195 	src.h = height;
196 
197 	dest.x = game.offsetX + destX;
198 	dest.y = game.offsetY + destY;
199 	dest.w = width;
200 	dest.h = height;
201 
202 	SDL_RenderCopy(game.renderer, image->texture, &src, &dest);
203 }
204 
drawBoxToSurface(SDL_Surface * surface,int x,int y,int w,int h,int r,int g,int b)205 void drawBoxToSurface(SDL_Surface *surface, int x, int y, int w, int h, int r, int g, int b)
206 {
207 	SDL_Rect rect;
208 	Uint32 colour;
209 
210 	colour = SDL_MapRGB(surface->format, r, g, b);
211 
212 	rect.x = x;
213 	rect.y = y;
214 	rect.w = w;
215 	rect.h = h;
216 
217 	SDL_FillRect(surface, &rect, colour);
218 }
219 
drawBox(int x,int y,int w,int h,int r,int g,int b,int a)220 void drawBox(int x, int y, int w, int h, int r, int g, int b, int a)
221 {
222 	SDL_Rect rect;
223 
224 	SDL_SetRenderDrawColor(game.renderer, r, g, b, a);
225 
226 	rect.x = x;
227 	rect.y = y;
228 	rect.w = w;
229 	rect.h = h;
230 
231 	SDL_RenderFillRect(game.renderer, &rect);
232 }
233 
drawBoxToMap(int x,int y,int w,int h,int r,int g,int b)234 void drawBoxToMap(int x, int y, int w, int h, int r, int g, int b)
235 {
236 	SDL_Rect rect;
237 
238 	rect.x = x - getMapStartX();
239 	rect.y = y - getMapStartY();
240 	rect.w = w;
241 	rect.h = h;
242 
243 	if (collision(rect.x, rect.y, rect.w, rect.h, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT) == TRUE)
244 	{
245 		SDL_SetRenderDrawColor(game.renderer, r, g, b, 255);
246 
247 		SDL_RenderFillRect(game.renderer, &rect);
248 	}
249 }
250 
putPixelToMap(int x,int y,int r,int g,int b)251 void putPixelToMap(int x, int y, int r, int g, int b)
252 {
253 	int startX, startY;
254 	Colour colour;
255 
256 	startX = getMapStartX();
257 	startY = getMapStartY();
258 
259 	x -= startX;
260 	y -= startY;
261 
262 	if (collision(x, y, 1, 1, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT) == FALSE)
263 	{
264 		return;
265 	}
266 
267 	colour.r = r;
268 	colour.g = g;
269 	colour.b = b;
270 	colour.a = 255;
271 
272 	putPixel(x, y, colour);
273 }
274 
drawLine(int x1,int y1,int x2,int y2,int r,int g,int b)275 void drawLine(int x1, int y1, int x2, int y2, int r, int g, int b)
276 {
277 	int lDelta, sDelta, cycle, lStep, sStep;
278 	int startX, startY;
279 	int clipX, clipY, clipW, clipH;
280 	SDL_Rect clipRect;
281 	Colour colour;
282 
283 	colour.r = r;
284 	colour.g = g;
285 	colour.b = b;
286 	colour.a = 255;
287 
288 	startX = getMapStartX();
289 	startY = getMapStartY();
290 
291 	SDL_RenderGetClipRect(game.renderer, &clipRect);
292 
293 	clipX = clipRect.x;
294 	clipY = clipRect.y;
295 
296 	clipW = clipRect.x + clipRect.w;
297 	clipH = clipRect.y + clipRect.h;
298 
299 	if (clipX == 0 && clipY == 0 && clipW == 0 && clipH == 0)
300 	{
301 		clipW = SCREEN_WIDTH;
302 		clipH = SCREEN_HEIGHT;
303 	}
304 
305 	x1 -= startX;
306 	y1 -= startY;
307 
308 	x2 -= startX;
309 	y2 -= startY;
310 
311 	if (collision(x1, y1, x2 - x1, y2 - y1, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT) == FALSE)
312 	{
313 		return;
314 	}
315 
316 	lDelta = x2 - x1;
317 	sDelta = y2 - y1;
318 
319 	lStep = SIGN(lDelta);
320 	lDelta = abs(lDelta);
321 
322 	sStep = SIGN(sDelta);
323 	sDelta = abs(sDelta);
324 
325 	if (sDelta < lDelta)
326 	{
327 		cycle = lDelta >> 1;
328 
329 		while (x1 != x2)
330 		{
331 			if (x1 >= clipX && x1 < clipW && y1 >= clipY && y1 < clipH)
332 			{
333 				putPixel(x1, y1, colour);
334 			}
335 
336 			cycle += sDelta;
337 
338 			if (cycle > lDelta)
339 			{
340 				cycle -= lDelta;
341 
342 				y1 += sStep;
343 			}
344 
345 			x1 += lStep;
346 		}
347 
348 		if (x1 >= clipX && x1 < clipW && y1 >= clipY && y1 < clipH)
349 		{
350 			putPixel(x1, y1, colour);
351 		}
352 	}
353 
354 	cycle = sDelta >> 1;
355 
356 	while (y1 != y2)
357 	{
358 		if (x1 >= clipX && x1 < clipW && y1 >= clipY && y1 < clipH)
359 		{
360 			putPixel(x1, y1, colour);
361 		}
362 
363 		cycle += lDelta;
364 
365 		if (cycle > sDelta)
366 		{
367 			cycle -= sDelta;
368 
369 			x1 += lStep;
370 		}
371 
372 		y1 += sStep;
373 	}
374 
375 	if (x1 >= clipX && x1 < clipW && y1 >= clipY && y1 < clipH)
376 	{
377 		putPixel(x1, y1, colour);
378 	}
379 }
380 
drawColouredLine(int x1,int y1,int x2,int y2,Colour colour1,Colour colour2,Colour colour3)381 void drawColouredLine(int x1, int y1, int x2, int y2, Colour colour1, Colour colour2, Colour colour3)
382 {
383 	int lDelta, sDelta, cycle, lStep, sStep;
384 	int startX, startY;
385 	int clipX, clipY, clipW, clipH;
386 	SDL_Rect clipRect;
387 
388 	startX = getMapStartX();
389 	startY = getMapStartY();
390 
391 	SDL_RenderGetClipRect(game.renderer, &clipRect);
392 
393 	clipX = clipRect.x;
394 	clipY = clipRect.y;
395 
396 	clipW = clipRect.x + clipRect.w;
397 	clipH = clipRect.y + clipRect.h;
398 
399 	if (clipX == 0 && clipY == 0 && clipW == 0 && clipH == 0)
400 	{
401 		clipW = SCREEN_WIDTH;
402 		clipH = SCREEN_HEIGHT;
403 	}
404 
405 	x1 -= startX;
406 	y1 -= startY;
407 
408 	x2 -= startX;
409 	y2 -= startY;
410 
411 	if (collision(x1, y1, x2 - x1, y2 - y1, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT) == FALSE)
412 	{
413 		return;
414 	}
415 
416 	lDelta = x2 - x1;
417 	sDelta = y2 - y1;
418 
419 	lStep = SIGN(lDelta);
420 	lDelta = abs(lDelta);
421 
422 	sStep = SIGN(sDelta);
423 	sDelta = abs(sDelta);
424 
425 	if (sDelta < lDelta)
426 	{
427 		cycle = lDelta >> 1;
428 
429 		while (x1 != x2)
430 		{
431 			if (x1 >= clipX && x1 < clipW && y1 - 2 >= clipY && y1 + 2 < clipH)
432 			{
433 				putPixel(x1, y1 - 2, colour3);
434 				putPixel(x1, y1 - 1, colour2);
435 				putPixel(x1, y1, colour1);
436 				putPixel(x1, y1 + 1, colour2);
437 				putPixel(x1, y1 + 2, colour3);
438 			}
439 
440 			cycle += sDelta;
441 
442 			if (cycle > lDelta)
443 			{
444 				cycle -= lDelta;
445 
446 				y1 += sStep;
447 			}
448 
449 			x1 += lStep;
450 		}
451 
452 		if (x1 >= clipX && x1 < clipW && y1 - 2 >= clipY && y1 + 2 < clipH)
453 		{
454 			putPixel(x1, y1 - 2, colour3);
455 			putPixel(x1, y1 - 1, colour2);
456 			putPixel(x1, y1, colour1);
457 			putPixel(x1, y1 + 1, colour2);
458 			putPixel(x1, y1 + 2, colour3);
459 		}
460 	}
461 
462 	cycle = sDelta >> 1;
463 
464 	while (y1 != y2)
465 	{
466 		if (x1 >= clipX && x1 < clipW && y1 - 2 >= clipY && y1 + 2 < clipH)
467 		{
468 			putPixel(x1, y1 - 2, colour3);
469 			putPixel(x1, y1 - 1, colour2);
470 			putPixel(x1, y1, colour1);
471 			putPixel(x1, y1 + 1, colour2);
472 			putPixel(x1, y1 + 2, colour3);
473 		}
474 
475 		cycle += lDelta;
476 
477 		if (cycle > sDelta)
478 		{
479 			cycle -= sDelta;
480 
481 			x1 += lStep;
482 		}
483 
484 		y1 += sStep;
485 	}
486 
487 	if (x1 >= clipX && x1 < clipW && y1 - 2 >= clipY && y1 + 2 < clipH)
488 	{
489 		putPixel(x1, y1 - 2, colour3);
490 		putPixel(x1, y1 - 1, colour2);
491 		putPixel(x1, y1, colour1);
492 		putPixel(x1, y1 + 1, colour2);
493 		putPixel(x1, y1 + 2, colour3);
494 	}
495 }
496 
drawCircle(int x,int y,int radius,int r,int g,int b)497 void drawCircle(int x, int y, int radius, int r, int g, int b)
498 {
499     int xx = radius - 1;
500     int yy = 0;
501     int dx = 1;
502     int dy = 1;
503     int err = dx - radius * 2;
504 
505     SDL_SetRenderDrawColor(game.renderer, r, g, b, 255);
506 
507     while (xx >= yy)
508     {
509 		SDL_RenderDrawLine(game.renderer, x - xx, y + yy, x + xx, y + yy);
510 
511 		SDL_RenderDrawLine(game.renderer, x - yy, y - xx, x + yy, y - xx);
512 
513 		SDL_RenderDrawLine(game.renderer, x - xx, y - yy, x + xx, y - yy);
514 
515 		SDL_RenderDrawLine(game.renderer, x - yy, y + xx, x + yy, y + xx);
516 
517         if (err <= 0)
518         {
519             yy++;
520             err += dy;
521             dy += 2;
522         }
523 
524         if (err > 0)
525         {
526             xx--;
527             dx += 2;
528             err += dx - (radius << 1);
529         }
530     }
531 }
532 
drawCircleFromSurface(int x,int y,int radius)533 void drawCircleFromSurface(int x, int y, int radius)
534 {
535     int xx = radius - 1;
536     int yy = 0;
537     int dx = 1;
538     int dy = 1;
539     int err = dx - radius * 2;
540     SDL_Rect rect;
541 
542     SDL_SetRenderDrawColor(game.renderer, 0, 0, 0, 255);
543 
544     rect.x = 0;
545     rect.y = 0;
546     rect.w = SCREEN_WIDTH;
547     rect.h = y - radius + 1;
548 
549     if (rect.h > 0)
550     {
551     	SDL_RenderFillRect(game.renderer, &rect);
552     }
553 
554     rect.x = 0;
555     rect.y = y + radius;
556     rect.w = SCREEN_WIDTH;
557     rect.h = SCREEN_HEIGHT - y - radius;
558 
559     if (rect.h > 0)
560     {
561     	SDL_RenderFillRect(game.renderer, &rect);
562     }
563 
564     while (xx >= yy)
565     {
566 		SDL_RenderDrawLine(game.renderer, 0, y + yy, x - xx, y + yy);
567 
568 		SDL_RenderDrawLine(game.renderer, x + xx, y + yy, SCREEN_WIDTH, y + yy);
569 
570 		SDL_RenderDrawLine(game.renderer, 0, y - xx, x - yy, y - xx);
571 
572 		SDL_RenderDrawLine(game.renderer, x + yy, y - xx, SCREEN_WIDTH, y - xx);
573 
574 		SDL_RenderDrawLine(game.renderer, 0, y - yy, x - xx, y - yy);
575 
576 		SDL_RenderDrawLine(game.renderer, x + xx, y - yy, SCREEN_WIDTH, y - yy);
577 
578 		SDL_RenderDrawLine(game.renderer, 0, y + xx, x - yy, y + xx);
579 
580 		SDL_RenderDrawLine(game.renderer, x + yy, y + xx, SCREEN_WIDTH, y + xx);
581 
582         if (err <= 0)
583         {
584             yy++;
585             err += dy;
586             dy += 2;
587         }
588 
589         if (err > 0)
590         {
591             xx--;
592             dx += 2;
593             err += dx - (radius << 1);
594         }
595     }
596 }
597 
addBorder(SDL_Surface * surface,int r,int g,int b,int br,int bg,int bb)598 Texture *addBorder(SDL_Surface *surface, int r, int g, int b, int br, int bg, int bb)
599 {
600 	int colour;
601 	SDL_Rect rect;
602 	SDL_Surface *newSurface;
603 	Texture *texture;
604 
605 	newSurface = createSurface(surface->w + BORDER_PADDING * 2, surface->h + BORDER_PADDING * 2, FALSE);
606 
607 	colour = SDL_MapRGB(surface->format, r, g, b);
608 
609 	SDL_FillRect(newSurface, NULL, SDL_MapRGB(newSurface->format, br, bg, bb));
610 
611 	rect.x = BORDER_PADDING;
612 	rect.y = BORDER_PADDING;
613 	rect.w = surface->w;
614 	rect.h = surface->h;
615 
616 	SDL_BlitSurface(surface, NULL, newSurface, &rect);
617 
618 	/* Top */
619 
620 	rect.x = 0;
621 	rect.y = 0;
622 	rect.w = newSurface->w;
623 	rect.h = 1;
624 
625 	SDL_FillRect(newSurface, &rect, colour);
626 
627 	/* Left */
628 
629 	rect.x = 0;
630 	rect.y = 0;
631 	rect.w = 1;
632 	rect.h = newSurface->h;
633 
634 	SDL_FillRect(newSurface, &rect, colour);
635 
636 	/* Right */
637 
638 	rect.x = newSurface->w - 1;
639 	rect.y = 0;
640 	rect.w = 1;
641 	rect.h = newSurface->h;
642 
643 	SDL_FillRect(newSurface, &rect, colour);
644 
645 	/* Bottom */
646 
647 	rect.x = 0;
648 	rect.y = newSurface->h - 1;
649 	rect.w = newSurface->w;
650 	rect.h = 1;
651 
652 	SDL_FillRect(newSurface, &rect, colour);
653 
654 	SDL_FreeSurface(surface);
655 
656 	texture = convertSurfaceToTexture(newSurface, TRUE);
657 
658 	return texture;
659 }
660 
copyScreen()661 Texture *copyScreen()
662 {
663 	SDL_Surface *tempSurface;
664 	Texture *texture;
665 
666 	tempSurface = createSurface(SCREEN_WIDTH, SCREEN_HEIGHT, TRUE);
667 
668 	SDL_SetRenderDrawColor(game.renderer, 255, 255, 255, 255);
669 
670 	SDL_RenderReadPixels(game.renderer, NULL, SDL_PIXELFORMAT_ARGB8888, tempSurface->pixels, tempSurface->pitch);
671 
672 	texture = convertSurfaceToTexture(tempSurface, TRUE);
673 
674 	return texture;
675 }
676 
clearScreen(int r,int g,int b)677 void clearScreen(int r, int g, int b)
678 {
679 	SDL_SetRenderDrawColor(game.renderer, r, g, b, 255);
680 
681 	SDL_RenderClear(game.renderer);
682 }
683 
drawHitBox(int startX,int startY,int w,int h)684 void drawHitBox(int startX, int startY, int w, int h)
685 {
686 	int x, y;
687 	Uint32 red, transparent;
688 	SDL_Rect dest;
689 	SDL_Surface *image;
690 	Texture *texture;
691 
692 	transparent = 0;
693 
694 	image = createSurface(w, h, FALSE);
695 
696 	red = SDL_MapRGB(image->format, 255, 0, 0);
697 
698 	if (SDL_MUSTLOCK(image))
699 	{
700 		SDL_LockSurface(image);
701 	}
702 
703 	for (y=0;y<image->h;y++)
704 	{
705 		for (x=0;x<image->w;x++)
706 		{
707 			if (y == 0 || y == (image->h - 1))
708 			{
709 				putPixelToSurface(image, x, y, red);
710 			}
711 
712 			else if (x == 0 || x == (image->w - 1))
713 			{
714 				putPixelToSurface(image, x, y, red);
715 			}
716 
717 			else
718 			{
719 				putPixelToSurface(image, x, y, transparent);
720 			}
721 		}
722 	}
723 
724 	if (SDL_MUSTLOCK(image))
725 	{
726 		SDL_UnlockSurface(image);
727 	}
728 
729 	texture = convertSurfaceToTexture(image, TRUE);
730 
731 	dest.x = startX;
732 	dest.y = startY;
733 	dest.w = image->w;
734 	dest.h = image->h;
735 
736 	SDL_RenderCopy(game.renderer, texture->texture, NULL, &dest);
737 
738 	destroyTexture(texture);
739 }
740 
convertImageToWhite(SDL_Surface * image,int delete)741 Texture *convertImageToWhite(SDL_Surface *image, int delete)
742 {
743 	unsigned char r, g, b, a;
744 	int x, y;
745 	Uint32 white = SDL_MapRGB(image->format, 255, 255, 255);
746 	Uint32 pixel;
747 	SDL_Surface *whiteImage;
748 	Texture *texture;
749 
750 	whiteImage = createSurface(image->w, image->h, FALSE);
751 
752 	if (SDL_MUSTLOCK(image))
753 	{
754 		SDL_LockSurface(image);
755 	}
756 
757 	for (x=0;x<image->w;x++)
758 	{
759 		for (y=0;y<image->h;y++)
760 		{
761 			pixel = getPixel(image, x, y);
762 
763 			SDL_GetRGBA(pixel, image->format, &r, &g, &b, &a);
764 
765 			if (a == 255)
766 			{
767 				putPixelToSurface(whiteImage, x, y, white);
768 			}
769 		}
770 	}
771 
772 	if (SDL_MUSTLOCK(image))
773 	{
774 		SDL_UnlockSurface(image);
775 	}
776 
777 	texture = convertSurfaceToTexture(whiteImage, delete);
778 
779 	return texture;
780 }
781 
createPixelsFromSprite(Sprite * sprite)782 EntityList *createPixelsFromSprite(Sprite *sprite)
783 {
784 	unsigned char r, g, b, a;
785 	int x, y;
786 	Uint32 pixel;
787 	SDL_Surface *image;
788 	Entity *d;
789 	EntityList *list;
790 
791 	image = loadImageFromPak(sprite->name);
792 
793 	list = malloc(sizeof(EntityList));
794 
795 	if (list == NULL)
796 	{
797 		showErrorAndExit("Failed to allocate a whole %d bytes for Entity List", (int)sizeof(EntityList));
798 	}
799 
800 	list->next = NULL;
801 
802 	if (SDL_MUSTLOCK(image))
803 	{
804 		SDL_LockSurface(image);
805 	}
806 
807 	for (y=0;y<image->h;y++)
808 	{
809 		for (x=0;x<image->w;x++)
810 		{
811 			pixel = getPixel(image, x, y);
812 
813 			SDL_GetRGBA(pixel, image->format, &r, &g, &b, &a);
814 
815 			if (a != 0)
816 			{
817 				d = addPixelDecoration(self->x + x, self->y + y);
818 
819 				if (d != NULL)
820 				{
821 					d->health = r;
822 
823 					d->maxHealth = g;
824 
825 					d->mental = b;
826 
827 					addEntityToList(list, d);
828 				}
829 			}
830 		}
831 	}
832 
833 	if (SDL_MUSTLOCK(image))
834 	{
835 		SDL_UnlockSurface(image);
836 	}
837 
838 	SDL_FreeSurface(image);
839 
840 	return list;
841 }
842 
createSurface(int width,int height,int useDefaults)843 SDL_Surface *createSurface(int width, int height, int useDefaults)
844 {
845     SDL_Surface *newSurface;
846     Uint32 rmask, gmask, bmask, amask;
847 
848 	#if SDL_BYTEORDER == SDL_BIG_ENDIAN
849 		rmask = 0xff000000;
850 		gmask = 0x00ff0000;
851 		bmask = 0x0000ff00;
852 		amask = 0x000000ff;
853 	#else
854 		rmask = 0x000000ff;
855 		gmask = 0x0000ff00;
856 		bmask = 0x00ff0000;
857 		amask = 0xff000000;
858 	#endif
859 
860 	if (useDefaults == TRUE)
861 	{
862 		newSurface = SDL_CreateRGBSurface(0, width, height, 32, 0, 0, 0, 0);
863 	}
864 
865 	else
866 	{
867 		newSurface = SDL_CreateRGBSurface(0, width, height, 32, rmask, gmask, bmask, amask);
868 	}
869 
870 	if (newSurface == NULL)
871 	{
872 		showErrorAndExit("Failed to create a surface");
873 	}
874 
875 	return newSurface;
876 }
877 
getPixel(SDL_Surface * surface,int x,int y)878 static Uint32 getPixel(SDL_Surface *surface, int x, int y)
879 {
880 	int bpp = surface->format->BytesPerPixel;
881 
882 	Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;
883 
884 	switch (bpp)
885 	{
886 		case 1:
887 		case 8:
888 			return *p;
889 
890 		case 2:
891 		case 16:
892 			return *(Uint16 *)p;
893 
894 		case 3:
895 		case 24:
896 			if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
897 			{
898 				return p[0] << 16 | p[1] << 8 | p[2];
899 			}
900 
901 			else
902 			{
903 				return p[0] | p[1] << 8 | p[2] << 16;
904 			}
905 
906 		case 4:
907 		case 32:
908 			return *(Uint32 *)p;
909 
910 		default:
911 			return 0;
912 	}
913 }
914 
putPixel(int x,int y,Colour colour)915 static void putPixel(int x, int y, Colour colour)
916 {
917 	SDL_SetRenderDrawColor(game.renderer, colour.r, colour.g, colour.b, colour.a);
918 
919 	SDL_RenderDrawPoint(game.renderer, x, y);
920 }
921 
putPixelToSurface(SDL_Surface * surface,int x,int y,Uint32 pixel)922 static void putPixelToSurface(SDL_Surface *surface, int x, int y, Uint32 pixel)
923 {
924 	int bpp = surface->format->BytesPerPixel;
925 
926 	Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;
927 
928 	switch (bpp)
929 	{
930 		case 1:
931 		case 8:
932 			*p = pixel;
933 		break;
934 
935 		case 2:
936 		case 16:
937 			*(Uint16 *)p = pixel;
938 		break;
939 
940 		case 3:
941 		case 24:
942 			if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
943 			{
944 				p[0] = (pixel >> 16) & 0xff;
945 				p[1] = (pixel >> 8) & 0xff;
946 				p[2] = pixel & 0xff;
947 			}
948 
949 			else
950 			{
951 				p[0] = pixel & 0xff;
952 				p[1] = (pixel >> 8) & 0xff;
953 				p[2] = (pixel >> 16) & 0xff;
954 			}
955 		break;
956 
957 		case 4:
958 		case 32:
959 			*(Uint32 *)p = pixel;
960 		break;
961 	}
962 }
963 
setScreenshotDir(char * name)964 void setScreenshotDir(char *name)
965 {
966 	STRNCPY(screenshotPath, name, sizeof(screenshotPath));
967 
968 	printf("Set screenshot directory to %s\n", screenshotPath);
969 }
970 
takeScreenshot()971 void takeScreenshot()
972 {
973 	char filename[MAX_PATH_LENGTH];
974 	SDL_Surface *tempSurface;
975 
976 	tempSurface = createSurface(SCREEN_WIDTH, SCREEN_HEIGHT, TRUE);
977 
978 	SDL_RenderReadPixels(game.renderer, NULL, SDL_PIXELFORMAT_ARGB8888, tempSurface->pixels, tempSurface->pitch);
979 
980 	if (strlen(screenshotPath) != 0)
981 	{
982 		SNPRINTF(filename, sizeof(filename), "%s/edgar%06d.png", screenshotPath, frame);
983 
984 		frame++;
985 
986 		savePNG(tempSurface, filename);
987 	}
988 
989 	SDL_FreeSurface(tempSurface);
990 }
991 
takeSingleScreenshot(char * name)992 void takeSingleScreenshot(char *name)
993 {
994 	SDL_Surface *tempSurface;
995 
996 	tempSurface = createSurface(SCREEN_WIDTH, SCREEN_HEIGHT, TRUE);
997 
998 	SDL_RenderReadPixels(game.renderer, NULL, SDL_PIXELFORMAT_ARGB8888, tempSurface->pixels, tempSurface->pitch);
999 
1000 	savePNG(tempSurface, name);
1001 
1002 	SDL_FreeSurface(tempSurface);
1003 }
1004