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