1/*****************************************************************************\
2 Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
3 This file is licensed under the Snes9x License.
4 For further information, consult the LICENSE file in the root directory.
5\*****************************************************************************/
6
7#ifdef HAVE_LIBPNG
8#include <png.h>
9#endif
10#include "snes9x.h"
11#include "memmap.h"
12#include "display.h"
13#include "screenshot.h"
14
15
16bool8 S9xDoScreenshot (int width, int height)
17{
18 Settings.TakeScreenshot = FALSE;
19
20#ifdef HAVE_LIBPNG
21 FILE *fp;
22 png_structp png_ptr;
23 png_infop info_ptr;
24 png_color_8 sig_bit;
25 int imgwidth, imgheight;
26 const char *fname;
27
28 fname = S9xGetFilenameInc(".png", SCREENSHOT_DIR);
29
30 fp = fopen(fname, "wb");
31 if (!fp)
32 {
33 S9xMessage(S9X_ERROR, 0, "Failed to take screenshot.");
34 return (FALSE);
35 }
36
37 png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
38 if (!png_ptr)
39 {
40 fclose(fp);
41 remove(fname);
42 S9xMessage(S9X_ERROR, 0, "Failed to take screenshot.");
43 return (FALSE);
44 }
45
46 info_ptr = png_create_info_struct(png_ptr);
47 if (!info_ptr)
48 {
49 png_destroy_write_struct(&png_ptr, (png_infopp) NULL);
50 fclose(fp);
51 remove(fname);
52 S9xMessage(S9X_ERROR, 0, "Failed to take screenshot.");
53 return (FALSE);
54 }
55
56 if (setjmp(png_jmpbuf(png_ptr)))
57 {
58 png_destroy_write_struct(&png_ptr, &info_ptr);
59 fclose(fp);
60 remove(fname);
61 S9xMessage(S9X_ERROR, 0, "Failed to take screenshot.");
62 return (FALSE);
63 }
64
65 imgwidth = width;
66 imgheight = height;
67
68 if (Settings.StretchScreenshots == 1)
69 {
70 if (width > SNES_WIDTH && height <= SNES_HEIGHT_EXTENDED)
71 imgheight = height << 1;
72 }
73 else
74 if (Settings.StretchScreenshots == 2)
75 {
76 if (width <= SNES_WIDTH)
77 imgwidth = width << 1;
78 if (height <= SNES_HEIGHT_EXTENDED)
79 imgheight = height << 1;
80 }
81
82 png_init_io(png_ptr, fp);
83
84 png_set_IHDR(png_ptr, info_ptr, imgwidth, imgheight, 8, PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
85
86 sig_bit.red = 5;
87 sig_bit.green = 5;
88 sig_bit.blue = 5;
89 png_set_sBIT(png_ptr, info_ptr, &sig_bit);
90 png_set_shift(png_ptr, &sig_bit);
91
92 png_write_info(png_ptr, info_ptr);
93
94 png_set_packing(png_ptr);
95
96 png_byte *row_pointer = new png_byte[png_get_rowbytes(png_ptr, info_ptr)];
97 uint16 *screen = GFX.Screen;
98
99 for (int y = 0; y < height; y++, screen += GFX.RealPPL)
100 {
101 png_byte *rowpix = row_pointer;
102
103 for (int x = 0; x < width; x++)
104 {
105 uint32 r, g, b;
106
107 DECOMPOSE_PIXEL(screen[x], r, g, b);
108
109 *(rowpix++) = r;
110 *(rowpix++) = g;
111 *(rowpix++) = b;
112
113 if (imgwidth != width)
114 {
115 *(rowpix++) = r;
116 *(rowpix++) = g;
117 *(rowpix++) = b;
118 }
119 }
120
121 png_write_row(png_ptr, row_pointer);
122 if (imgheight != height)
123 png_write_row(png_ptr, row_pointer);
124 }
125
126 delete [] row_pointer;
127
128 png_write_end(png_ptr, info_ptr);
129 png_destroy_write_struct(&png_ptr, &info_ptr);
130
131 fclose(fp);
132
133 fprintf(stderr, "%s saved.\n", fname);
134
135 const char *base = S9xBasename(fname);
136 sprintf(String, "Saved screenshot %s", base);
137 S9xMessage(S9X_INFO, 0, String);
138
139 return (TRUE);
140#else
141 fprintf(stderr, "Screenshot support not available (libpng was not found at build time).\n");
142 return (FALSE);
143#endif
144}
145