|
|
1.1 root 1: /*
1.1.1.5 root 2: Hatari - screenSnapShot.c
1.1 root 3:
1.1.1.5 root 4: This file is distributed under the GNU Public License, version 2 or at
5: your option any later version. Read the file gpl.txt for details.
6:
7: Screen Snapshots.
1.1 root 8: */
1.1.1.11! root 9: const char ScreenSnapShot_fileid[] = "Hatari screenSnapShot.c : " __DATE__ " " __TIME__;
1.1 root 10:
1.1.1.2 root 11: #include <SDL.h>
12: #include <dirent.h>
13: #include <string.h>
1.1 root 14: #include "main.h"
1.1.1.6 root 15: #include "log.h"
1.1.1.8 root 16: #include "paths.h"
1.1 root 17: #include "screen.h"
18: #include "screenSnapShot.h"
19: #include "video.h"
1.1.1.9 root 20: /* after above that bring in config.h */
21: #if HAVE_LIBPNG
22: # include <png.h>
23: # include <assert.h>
24: #endif
1.1 root 25:
1.1.1.2 root 26:
1.1.1.11! root 27: bool bRecordingAnimation = false; /* Recording animation? */
1.1.1.6 root 28: static int nScreenShots = 0; /* Number of screen shots saved */
1.1.1.9 root 29: static bool bGrabWhenChange;
1.1.1.6 root 30:
1.1 root 31:
1.1.1.2 root 32: /*-----------------------------------------------------------------------*/
1.1.1.8 root 33: /**
34: * Scan working directory to get the screenshot number
35: */
1.1.1.5 root 36: static void ScreenSnapShot_GetNum(void)
37: {
1.1.1.8 root 38: char dummy[5];
39: int i, num;
40: DIR *workingdir = opendir(Paths_GetWorkingDir());
41: struct dirent *file;
42:
43: nScreenShots = 0;
44: if (workingdir == NULL) return;
45:
46: file = readdir(workingdir);
47: while (file != NULL)
48: {
49: if ( strncmp("grab", file->d_name, 4) == 0 )
50: {
51: /* copy next 4 numbers */
52: for (i = 0; i < 4; i++)
53: {
54: if (file->d_name[4+i] >= '0' && file->d_name[4+i] <= '9')
55: dummy[i] = file->d_name[4+i];
56: else
57: break;
58: }
59:
60: dummy[i] = '\0'; /* null terminate */
61: num = atoi(dummy);
62: if (num > nScreenShots) nScreenShots = num;
63: }
64: /* next file.. */
65: file = readdir(workingdir);
66: }
67:
68: closedir(workingdir);
1.1.1.2 root 69: }
70:
1.1.1.8 root 71:
1.1.1.9 root 72: #if HAVE_LIBPNG
1.1.1.2 root 73: /*-----------------------------------------------------------------------*/
1.1.1.8 root 74: /**
1.1.1.9 root 75: * Unpack 8-bit data with RGB palette to 24-bit RGB pixels
76: */
77: static inline void ScreenSnapShot_8to24Bits(Uint8 *dst, Uint8 *src, int w, SDL_Color *colors)
78: {
79: int x;
80: for (x = 0; x < w; x++, src++) {
81: *dst++ = colors[*src].r;
82: *dst++ = colors[*src].g;
83: *dst++ = colors[*src].b;
84: }
85: }
86:
87: /**
88: * Unpack 16-bit RGB pixels to 24-bit RGB pixels
89: */
90: static inline void ScreenSnapShot_16to24Bits(Uint8 *dst, Uint16 *src, int w, SDL_PixelFormat *fmt)
91: {
92: int x;
93: for (x = 0; x < w; x++, src++) {
94: *dst++ = (((*src & fmt->Rmask) >> fmt->Rshift) << fmt->Rloss);
95: *dst++ = (((*src & fmt->Gmask) >> fmt->Gshift) << fmt->Gloss);
96: *dst++ = (((*src & fmt->Bmask) >> fmt->Bshift) << fmt->Bloss);
97: }
98: }
99:
100: /**
101: * unpack 32-bit RGBA pixels to 24-bit RGB pixels
102: */
103: static inline void ScreenSnapShot_32to24Bits(Uint8 *dst, Uint8 *src, int w)
104: {
105: int x;
106: for (x = 0; x < w; x++, src += 4) {
107: #if SDL_BYTEORDER == SDL_BIG_ENDIAN
108: *dst++ = src[1];
109: *dst++ = src[2];
110: *dst++ = src[3];
111: #else
112: *dst++ = src[2];
113: *dst++ = src[1];
114: *dst++ = src[0];
115: #endif
116: }
117: }
118:
119: /**
120: * Save given SDL surface as PNG. Return zero for success.
121: */
122: static int ScreenSnapShot_SavePNG(SDL_Surface *surface, const char *filename)
123: {
124: int y, ret = -1;
125: int w = surface->w;
126: int h = surface->h;
127: Uint8 *src_ptr, *row_ptr;
128: Uint8 rowbuf[3*surface->w];
129: SDL_PixelFormat *fmt = surface->format;
130: png_colorp palette_ptr = NULL;
131: png_infop info_ptr = NULL;
132: png_structp png_ptr;
133: png_text pngtext;
134: char key[] = "Title";
135: char text[] = "Hatari screenshot";
136: FILE *fp = NULL;
137:
138: /* Create and initialize the png_struct with error handler functions. */
139: png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
140: if (!png_ptr)
141: {
142: return ret;
143: }
144:
145: /* Allocate/initialize the image information data. */
146: info_ptr = png_create_info_struct(png_ptr);
147: if (!info_ptr)
148: goto png_cleanup;
149:
150: /* libpng ugliness: Set error handling when not supplying own
151: * error handling functions in the png_create_write_struct() call.
152: */
153: if (setjmp(png_jmpbuf(png_ptr)))
154: goto png_cleanup;
155:
156: fp = fopen(filename, "wb");
157: if (!fp)
158: goto png_cleanup;
159:
160: /* initialize the png structure */
161: png_init_io(png_ptr, fp);
162:
163: /* image data properties */
164: png_set_IHDR(png_ptr, info_ptr, w, h, 8, PNG_COLOR_TYPE_RGB,
165: PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
166: PNG_FILTER_TYPE_DEFAULT);
167:
168: /* image info */
169: pngtext.key = key;
170: pngtext.text = text;
171: pngtext.compression = PNG_TEXT_COMPRESSION_NONE;
172: #ifdef PNG_iTXt_SUPPORTED
173: pngtext.lang = NULL;
174: #endif
175: png_set_text(png_ptr, info_ptr, &pngtext, 1);
176:
177: /* write the file header information */
178: png_write_info(png_ptr, info_ptr);
179:
180: /* write surface data row at the time */
181: src_ptr = surface->pixels;
182: for (y = 0; y < h; y++) {
183: switch (fmt->BytesPerPixel) {
184: case 1:
185: /* unpack 8-bit data with RGB palette */
186: row_ptr = rowbuf;
187: ScreenSnapShot_8to24Bits(row_ptr, src_ptr, w, fmt->palette->colors);
188: break;
189: case 2:
190: /* unpack 16-bit RGB pixels */
191: row_ptr = rowbuf;
192: ScreenSnapShot_16to24Bits(row_ptr, (Uint16*)src_ptr, w, fmt);
193: break;
194: case 3:
195: /* PNG can handle 24-bits */
196: row_ptr = src_ptr;
197: break;
198: case 4:
199: /* unpack 32-bit RGBA pixels */
200: row_ptr = rowbuf;
201: ScreenSnapShot_32to24Bits(row_ptr, src_ptr, w);
202: break;
203: }
204: src_ptr += surface->pitch;
205: SDL_UnlockSurface(surface);
206: png_write_row(png_ptr, rowbuf);
207: }
208:
209: /* write the additional chuncks to the PNG file */
210: png_write_end(png_ptr, info_ptr);
211:
212: ret = 0;
213: png_cleanup:
214: if (fp)
215: fclose(fp);
216: if (palette_ptr)
217: free(palette_ptr);
218: if (png_ptr)
219: png_destroy_write_struct(&png_ptr, NULL);
220: return ret;
221: }
222: #endif
223:
224:
225: /*-----------------------------------------------------------------------*/
226: /**
1.1.1.11! root 227: * Save screen shot file with filename like 'grab0000.[png|bmp]',
! 228: * 'grab0001.[png|bmp]', etc... Whether screen shots are saved as BMP
! 229: * or PNG depends on Hatari configuration.
1.1.1.8 root 230: */
1.1 root 231: void ScreenSnapShot_SaveScreen(void)
232: {
1.1.1.8 root 233: char *szFileName = malloc(FILENAME_MAX);
1.1.1.6 root 234:
1.1.1.8 root 235: if (!szFileName) return;
1.1.1.5 root 236:
1.1.1.8 root 237: ScreenSnapShot_GetNum();
238: /* Create our filename */
239: nScreenShots++;
1.1.1.9 root 240: #if HAVE_LIBPNG
241: /* try first PNG */
242: sprintf(szFileName,"%s/grab%4.4d.png", Paths_GetWorkingDir(), nScreenShots);
243: if (ScreenSnapShot_SavePNG(sdlscrn, szFileName) == 0)
244: {
245: fprintf(stderr, "Screen dump saved to: %s\n", szFileName);
246: free(szFileName);
247: return;
248: }
249: #endif
1.1.1.8 root 250: sprintf(szFileName,"%s/grab%4.4d.bmp", Paths_GetWorkingDir(), nScreenShots);
251: if (SDL_SaveBMP(sdlscrn, szFileName))
252: fprintf(stderr, "Screen dump failed!\n");
253: else
254: fprintf(stderr, "Screen dump saved to: %s\n", szFileName);
1.1.1.5 root 255:
1.1.1.8 root 256: free(szFileName);
1.1 root 257: }
258:
1.1.1.8 root 259:
1.1.1.2 root 260: /*-----------------------------------------------------------------------*/
1.1.1.8 root 261: /**
262: * Are we recording an animation?
263: */
1.1.1.9 root 264: bool ScreenSnapShot_AreWeRecording(void)
1.1 root 265: {
1.1.1.8 root 266: return bRecordingAnimation;
1.1 root 267: }
268:
1.1.1.8 root 269:
1.1 root 270: /*-----------------------------------------------------------------------*/
1.1.1.8 root 271: /**
272: * Start recording animation
273: */
1.1.1.9 root 274: void ScreenSnapShot_BeginRecording(bool bCaptureChange)
1.1 root 275: {
1.1.1.8 root 276: /* Set in globals */
277: bGrabWhenChange = bCaptureChange;
1.1.1.9 root 278:
1.1.1.8 root 279: /* Start animation */
1.1.1.11! root 280: bRecordingAnimation = true;
1.1.1.8 root 281:
282: /* And inform user */
283: Log_AlertDlg(LOG_INFO, "Screenshot recording started.");
1.1 root 284: }
285:
1.1.1.8 root 286:
1.1 root 287: /*-----------------------------------------------------------------------*/
1.1.1.8 root 288: /**
289: * Stop recording animation
290: */
1.1 root 291: void ScreenSnapShot_EndRecording()
292: {
1.1.1.8 root 293: /* Were we recording? */
294: if (bRecordingAnimation)
295: {
296: /* Stop animation */
1.1.1.11! root 297: bRecordingAnimation = false;
1.1.1.6 root 298:
1.1.1.8 root 299: /* And inform user */
300: Log_AlertDlg(LOG_INFO, "Screenshot recording stopped.");
301: }
1.1 root 302: }
303:
1.1.1.8 root 304:
1.1.1.2 root 305: /*-----------------------------------------------------------------------*/
1.1.1.8 root 306: /**
307: * Recording animation frame
308: */
1.1.1.9 root 309: void ScreenSnapShot_RecordFrame(bool bFrameChanged)
1.1 root 310: {
1.1.1.9 root 311: /* As we recording and do we really want to save this frame? */
312: if (bRecordingAnimation && (!bGrabWhenChange || bFrameChanged))
1.1.1.8 root 313: {
1.1.1.9 root 314: ScreenSnapShot_SaveScreen();
1.1.1.8 root 315: }
1.1 root 316: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.