18 char _screenshot_format_name[8]; |
18 char _screenshot_format_name[8]; |
19 uint _num_screenshot_formats; |
19 uint _num_screenshot_formats; |
20 uint _cur_screenshot_format; |
20 uint _cur_screenshot_format; |
21 ScreenshotType current_screenshot_type; |
21 ScreenshotType current_screenshot_type; |
22 |
22 |
23 // called by the ScreenShot proc to generate screenshot lines. |
23 /* called by the ScreenShot proc to generate screenshot lines. */ |
24 typedef void ScreenshotCallback(void *userdata, Pixel *buf, uint y, uint pitch, uint n); |
24 typedef void ScreenshotCallback(void *userdata, Pixel *buf, uint y, uint pitch, uint n); |
25 typedef bool ScreenshotHandlerProc(const char *name, ScreenshotCallback *callb, void *userdata, uint w, uint h, int pixelformat, const Colour *palette); |
25 typedef bool ScreenshotHandlerProc(const char *name, ScreenshotCallback *callb, void *userdata, uint w, uint h, int pixelformat, const Colour *palette); |
26 |
26 |
27 struct ScreenshotFormat { |
27 struct ScreenshotFormat { |
28 const char *name; |
28 const char *name; |
60 struct RgbQuad { |
60 struct RgbQuad { |
61 byte blue, green, red, reserved; |
61 byte blue, green, red, reserved; |
62 }; |
62 }; |
63 assert_compile(sizeof(RgbQuad) == 4); |
63 assert_compile(sizeof(RgbQuad) == 4); |
64 |
64 |
65 // generic .BMP writer |
65 /* generic .BMP writer */ |
66 static bool MakeBmpImage(const char *name, ScreenshotCallback *callb, void *userdata, uint w, uint h, int pixelformat, const Colour *palette) |
66 static bool MakeBmpImage(const char *name, ScreenshotCallback *callb, void *userdata, uint w, uint h, int pixelformat, const Colour *palette) |
67 { |
67 { |
68 BitmapFileHeader bfh; |
68 BitmapFileHeader bfh; |
69 BitmapInfoHeader bih; |
69 BitmapInfoHeader bih; |
70 RgbQuad rq[256]; |
70 RgbQuad rq[256]; |
71 FILE *f; |
71 FILE *f; |
72 uint i, padw; |
72 uint i, padw; |
73 uint n, maxlines; |
73 uint n, maxlines; |
74 |
74 |
75 // only implemented for 8bit images so far. |
75 /* only implemented for 8bit images so far. */ |
76 if (pixelformat != 8) |
76 if (pixelformat != 8) |
77 return false; |
77 return false; |
78 |
78 |
79 f = fopen(name, "wb"); |
79 f = fopen(name, "wb"); |
80 if (f == NULL) return false; |
80 if (f == NULL) return false; |
81 |
81 |
82 // each scanline must be aligned on a 32bit boundary |
82 /* each scanline must be aligned on a 32bit boundary */ |
83 padw = ALIGN(w, 4); |
83 padw = ALIGN(w, 4); |
84 |
84 |
85 // setup the file header |
85 /* setup the file header */ |
86 bfh.type = TO_LE16('MB'); |
86 bfh.type = TO_LE16('MB'); |
87 bfh.size = TO_LE32(sizeof(bfh) + sizeof(bih) + sizeof(RgbQuad) * 256 + padw * h); |
87 bfh.size = TO_LE32(sizeof(bfh) + sizeof(bih) + sizeof(RgbQuad) * 256 + padw * h); |
88 bfh.reserved = 0; |
88 bfh.reserved = 0; |
89 bfh.off_bits = TO_LE32(sizeof(bfh) + sizeof(bih) + sizeof(RgbQuad) * 256); |
89 bfh.off_bits = TO_LE32(sizeof(bfh) + sizeof(bih) + sizeof(RgbQuad) * 256); |
90 |
90 |
91 // setup the info header |
91 /* setup the info header */ |
92 bih.size = TO_LE32(sizeof(BitmapInfoHeader)); |
92 bih.size = TO_LE32(sizeof(BitmapInfoHeader)); |
93 bih.width = TO_LE32(w); |
93 bih.width = TO_LE32(w); |
94 bih.height = TO_LE32(h); |
94 bih.height = TO_LE32(h); |
95 bih.planes = TO_LE16(1); |
95 bih.planes = TO_LE16(1); |
96 bih.bitcount = TO_LE16(8); |
96 bih.bitcount = TO_LE16(8); |
99 bih.xpels = 0; |
99 bih.xpels = 0; |
100 bih.ypels = 0; |
100 bih.ypels = 0; |
101 bih.clrused = 0; |
101 bih.clrused = 0; |
102 bih.clrimp = 0; |
102 bih.clrimp = 0; |
103 |
103 |
104 // convert the palette to the windows format |
104 /* convert the palette to the windows format */ |
105 for (i = 0; i != 256; i++) { |
105 for (i = 0; i != 256; i++) { |
106 rq[i].red = palette[i].r; |
106 rq[i].red = palette[i].r; |
107 rq[i].green = palette[i].g; |
107 rq[i].green = palette[i].g; |
108 rq[i].blue = palette[i].b; |
108 rq[i].blue = palette[i].b; |
109 rq[i].reserved = 0; |
109 rq[i].reserved = 0; |
110 } |
110 } |
111 |
111 |
112 // write file header and info header and palette |
112 /* write file header and info header and palette */ |
113 if (fwrite(&bfh, sizeof(bfh), 1, f) != 1) return false; |
113 if (fwrite(&bfh, sizeof(bfh), 1, f) != 1) return false; |
114 if (fwrite(&bih, sizeof(bih), 1, f) != 1) return false; |
114 if (fwrite(&bih, sizeof(bih), 1, f) != 1) return false; |
115 if (fwrite(rq, sizeof(rq), 1, f) != 1) return false; |
115 if (fwrite(rq, sizeof(rq), 1, f) != 1) return false; |
116 |
116 |
117 // use by default 64k temp memory |
117 /* use by default 64k temp memory */ |
118 maxlines = clamp(65536 / padw, 16, 128); |
118 maxlines = clamp(65536 / padw, 16, 128); |
119 |
119 |
120 // now generate the bitmap bits |
120 /* now generate the bitmap bits */ |
121 Pixel *buff = MallocT<Pixel>(padw * maxlines); // by default generate 128 lines at a time. |
121 Pixel *buff = MallocT<Pixel>(padw * maxlines); // by default generate 128 lines at a time. |
122 if (buff == NULL) { |
122 if (buff == NULL) { |
123 fclose(f); |
123 fclose(f); |
124 return false; |
124 return false; |
125 } |
125 } |
126 memset(buff, 0, padw * maxlines); // zero the buffer to have the padding bytes set to 0 |
126 memset(buff, 0, padw * maxlines); // zero the buffer to have the padding bytes set to 0 |
127 |
127 |
128 // start at the bottom, since bitmaps are stored bottom up. |
128 /* start at the bottom, since bitmaps are stored bottom up. */ |
129 do { |
129 do { |
130 // determine # lines |
130 /* determine # lines */ |
131 n = min(h, maxlines); |
131 n = min(h, maxlines); |
132 h -= n; |
132 h -= n; |
133 |
133 |
134 // render the pixels |
134 /* render the pixels */ |
135 callb(userdata, buff, h, padw, n); |
135 callb(userdata, buff, h, padw, n); |
136 |
136 |
137 // write each line |
137 /* write each line */ |
138 while (n) |
138 while (n) |
139 if (fwrite(buff + (--n) * padw, padw, 1, f) != 1) { |
139 if (fwrite(buff + (--n) * padw, padw, 1, f) != 1) { |
140 free(buff); |
140 free(buff); |
141 fclose(f); |
141 fclose(f); |
142 return false; |
142 return false; |
207 png_set_filter(png_ptr, 0, PNG_FILTER_NONE); |
207 png_set_filter(png_ptr, 0, PNG_FILTER_NONE); |
208 |
208 |
209 png_set_IHDR(png_ptr, info_ptr, w, h, pixelformat, PNG_COLOR_TYPE_PALETTE, |
209 png_set_IHDR(png_ptr, info_ptr, w, h, pixelformat, PNG_COLOR_TYPE_PALETTE, |
210 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); |
210 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); |
211 |
211 |
212 // convert the palette to the .PNG format. |
212 /* convert the palette to the .PNG format. */ |
213 for (i = 0; i != 256; i++) { |
213 for (i = 0; i != 256; i++) { |
214 rq[i].red = palette[i].r; |
214 rq[i].red = palette[i].r; |
215 rq[i].green = palette[i].g; |
215 rq[i].green = palette[i].g; |
216 rq[i].blue = palette[i].b; |
216 rq[i].blue = palette[i].b; |
217 } |
217 } |
218 |
218 |
219 png_set_PLTE(png_ptr, info_ptr, rq, 256); |
219 png_set_PLTE(png_ptr, info_ptr, rq, 256); |
220 png_write_info(png_ptr, info_ptr); |
220 png_write_info(png_ptr, info_ptr); |
221 png_set_flush(png_ptr, 512); |
221 png_set_flush(png_ptr, 512); |
222 |
222 |
223 // use by default 64k temp memory |
223 /* use by default 64k temp memory */ |
224 maxlines = clamp(65536 / w, 16, 128); |
224 maxlines = clamp(65536 / w, 16, 128); |
225 |
225 |
226 // now generate the bitmap bits |
226 /* now generate the bitmap bits */ |
227 Pixel *buff = MallocT<Pixel>(w * maxlines); // by default generate 128 lines at a time. |
227 Pixel *buff = MallocT<Pixel>(w * maxlines); // by default generate 128 lines at a time. |
228 if (buff == NULL) { |
228 if (buff == NULL) { |
229 png_destroy_write_struct(&png_ptr, &info_ptr); |
229 png_destroy_write_struct(&png_ptr, &info_ptr); |
230 fclose(f); |
230 fclose(f); |
231 return false; |
231 return false; |
232 } |
232 } |
233 memset(buff, 0, w * maxlines); // zero the buffer to have the padding bytes set to 0 |
233 memset(buff, 0, w * maxlines); // zero the buffer to have the padding bytes set to 0 |
234 |
234 |
235 y = 0; |
235 y = 0; |
236 do { |
236 do { |
237 // determine # lines to write |
237 /* determine # lines to write */ |
238 n = min(h - y, maxlines); |
238 n = min(h - y, maxlines); |
239 |
239 |
240 // render the pixels into the buffer |
240 /* render the pixels into the buffer */ |
241 callb(userdata, buff, y, w, n); |
241 callb(userdata, buff, y, w, n); |
242 y += n; |
242 y += n; |
243 |
243 |
244 // write them to png |
244 /* write them to png */ |
245 for (i = 0; i != n; i++) |
245 for (i = 0; i != n; i++) |
246 png_write_row(png_ptr, buff + i * w); |
246 png_write_row(png_ptr, buff + i * w); |
247 } while (y != h); |
247 } while (y != h); |
248 |
248 |
249 png_write_end(png_ptr, info_ptr); |
249 png_write_end(png_ptr, info_ptr); |
308 pcx.planes = 1; |
308 pcx.planes = 1; |
309 pcx.cpal = TO_LE16(1); |
309 pcx.cpal = TO_LE16(1); |
310 pcx.width = pcx.pitch = TO_LE16(w); |
310 pcx.width = pcx.pitch = TO_LE16(w); |
311 pcx.height = TO_LE16(h); |
311 pcx.height = TO_LE16(h); |
312 |
312 |
313 // write pcx header |
313 /* write pcx header */ |
314 if (fwrite(&pcx, sizeof(pcx), 1, f) != 1) { |
314 if (fwrite(&pcx, sizeof(pcx), 1, f) != 1) { |
315 fclose(f); |
315 fclose(f); |
316 return false; |
316 return false; |
317 } |
317 } |
318 |
318 |
319 // use by default 64k temp memory |
319 /* use by default 64k temp memory */ |
320 maxlines = clamp(65536 / w, 16, 128); |
320 maxlines = clamp(65536 / w, 16, 128); |
321 |
321 |
322 // now generate the bitmap bits |
322 /* now generate the bitmap bits */ |
323 Pixel *buff = MallocT<Pixel>(w * maxlines); // by default generate 128 lines at a time. |
323 Pixel *buff = MallocT<Pixel>(w * maxlines); // by default generate 128 lines at a time. |
324 if (buff == NULL) { |
324 if (buff == NULL) { |
325 fclose(f); |
325 fclose(f); |
326 return false; |
326 return false; |
327 } |
327 } |
328 memset(buff, 0, w * maxlines); // zero the buffer to have the padding bytes set to 0 |
328 memset(buff, 0, w * maxlines); // zero the buffer to have the padding bytes set to 0 |
329 |
329 |
330 y = 0; |
330 y = 0; |
331 do { |
331 do { |
332 // determine # lines to write |
332 /* determine # lines to write */ |
333 uint n = min(h - y, maxlines); |
333 uint n = min(h - y, maxlines); |
334 uint i; |
334 uint i; |
335 |
335 |
336 // render the pixels into the buffer |
336 /* render the pixels into the buffer */ |
337 callb(userdata, buff, y, w, n); |
337 callb(userdata, buff, y, w, n); |
338 y += n; |
338 y += n; |
339 |
339 |
340 // write them to pcx |
340 /* write them to pcx */ |
341 for (i = 0; i != n; i++) { |
341 for (i = 0; i != n; i++) { |
342 const Pixel* bufp = buff + i * w; |
342 const Pixel* bufp = buff + i * w; |
343 byte runchar = bufp[0]; |
343 byte runchar = bufp[0]; |
344 uint runcount = 1; |
344 uint runcount = 1; |
345 uint j; |
345 uint j; |
346 |
346 |
347 // for each pixel... |
347 /* for each pixel... */ |
348 for (j = 1; j < w; j++) { |
348 for (j = 1; j < w; j++) { |
349 Pixel ch = bufp[j]; |
349 Pixel ch = bufp[j]; |
350 |
350 |
351 if (ch != runchar || runcount >= 0x3f) { |
351 if (ch != runchar || runcount >= 0x3f) { |
352 if (runcount > 1 || (runchar & 0xC0) == 0xC0) |
352 if (runcount > 1 || (runchar & 0xC0) == 0xC0) |
443 { |
443 { |
444 _cur_screenshot_format = i; |
444 _cur_screenshot_format = i; |
445 strcpy(_screenshot_format_name, _screenshot_formats[i].extension); |
445 strcpy(_screenshot_format_name, _screenshot_formats[i].extension); |
446 } |
446 } |
447 |
447 |
448 // screenshot generator that dumps the current video buffer |
448 /* screenshot generator that dumps the current video buffer */ |
449 static void CurrentScreenCallback(void *userdata, Pixel *buf, uint y, uint pitch, uint n) |
449 static void CurrentScreenCallback(void *userdata, Pixel *buf, uint y, uint pitch, uint n) |
450 { |
450 { |
451 for (; n > 0; --n) { |
451 for (; n > 0; --n) { |
452 memcpy(buf, _screen.dst_ptr + y * _screen.pitch, _screen.width); |
452 memcpy(buf, _screen.dst_ptr + y * _screen.pitch, _screen.width); |
453 ++y; |
453 ++y; |
454 buf += pitch; |
454 buf += pitch; |
455 } |
455 } |
456 } |
456 } |
457 |
457 |
458 // generate a large piece of the world |
458 /* generate a large piece of the world */ |
459 static void LargeWorldCallback(void *userdata, Pixel *buf, uint y, uint pitch, uint n) |
459 static void LargeWorldCallback(void *userdata, Pixel *buf, uint y, uint pitch, uint n) |
460 { |
460 { |
461 ViewPort *vp = (ViewPort *)userdata; |
461 ViewPort *vp = (ViewPort *)userdata; |
462 DrawPixelInfo dpi, *old_dpi; |
462 DrawPixelInfo dpi, *old_dpi; |
463 int wx, left; |
463 int wx, left; |