1 #include "compat.h"
2 #include "build.h"
3 #include "editor.h"
4
5 #include "pngwrite.h"
6
7 #include "vfs.h"
8 #include "communityapi.h"
9
10 //
11 // screencapture
12 //
13
opennextfile(char * fn,char * zeros)14 buildvfs_FILE OutputFileCounter::opennextfile(char *fn, char *zeros)
15 {
16 do // JBF 2004022: So we don't overwrite existing screenshots
17 {
18 if (count > 9999) return nullptr;
19
20 zeros[0] = ((count/1000)%10)+'0';
21 zeros[1] = ((count/100)%10)+'0';
22 zeros[2] = ((count/10)%10)+'0';
23 zeros[3] = (count%10)+'0';
24 #ifdef USE_PHYSFS
25 buildvfs_FILE file;
26 if ((file = buildvfs_fopen_read(fn)) == nullptr) break;
27 buildvfs_fclose(file);
28 #else
29 struct Bstat st;
30 if (Bstat(fn, &st) == -1) break;
31 #endif
32 count++;
33 } while (1);
34
35 return buildvfs_fopen_write(fn);
36 }
37
opennextfile_withext(char * fn,const char * ext)38 buildvfs_FILE OutputFileCounter::opennextfile_withext(char *fn, const char *ext)
39 {
40 char *dot = strrchr(fn, '.');
41 strcpy(dot+1, ext);
42 return opennextfile(fn, dot-4);
43 }
44
45 static OutputFileCounter capturecounter;
46
screencapture_end(char * fn,buildvfs_FILE * filptr)47 static void screencapture_end(char *fn, buildvfs_FILE * filptr)
48 {
49 #ifdef VWSCREENSHOT
50 communityapiSendScreenshot(fn);
51 #endif
52 buildvfs_fclose(*filptr);
53 OSD_Printf("Saved screenshot to %s\n", fn);
54 Xfree(fn);
55 capturecounter.count++;
56 }
57
58 # ifdef USE_OPENGL
59 # define HICOLOR (videoGetRenderMode() >= REND_POLYMOST && in3dmode())
60 # else
61 # define HICOLOR 0
62 # endif
63
videoCaptureScreen(const char * filename,char inverseit)64 int videoCaptureScreen(const char *filename, char inverseit)
65 {
66 char *fn = Xstrdup(filename);
67 buildvfs_FILE fp = capturecounter.opennextfile_withext(fn, "png");
68
69 if (fp == nullptr)
70 {
71 Xfree(fn);
72 return -1;
73 }
74
75 uint8_t * const imgBuf = (uint8_t *) Xmalloc(xdim * ydim * (HICOLOR ? 3 : 1));
76
77 videoBeginDrawing(); //{{{
78
79 #ifdef USE_OPENGL
80 if (HICOLOR)
81 {
82 glReadPixels(0, 0, xdim, ydim, GL_RGB, GL_UNSIGNED_BYTE, imgBuf);
83 int const bytesPerLine = xdim * 3;
84
85 if (inverseit)
86 {
87 for (int i=0, j = ydim * bytesPerLine; i<j; i+=3)
88 swapchar(&imgBuf[i], &imgBuf[i+2]);
89 }
90
91 // flip rows
92 uint8_t* rowBuf = (uint8_t *) Xmalloc(bytesPerLine);
93
94 for (int i = 0, numRows = ydim >> 1; i < numRows; ++i)
95 {
96 Bmemcpy(rowBuf, imgBuf + i * bytesPerLine, bytesPerLine);
97 Bmemcpy(imgBuf + i * bytesPerLine, imgBuf + (ydim - i - 1) * bytesPerLine, bytesPerLine);
98 Bmemcpy(imgBuf + (ydim - i - 1) * bytesPerLine, rowBuf, bytesPerLine);
99 }
100
101 Xfree(rowBuf);
102 }
103 else
104 #endif
105 {
106 struct {
107 uint8_t r, g, b;
108 } palette[256];
109
110 if (inverseit)
111 {
112 for (bssize_t i = 0; i < 256; ++i)
113 {
114 palette[i].r = 255 - curpalettefaded[i].r;
115 palette[i].g = 255 - curpalettefaded[i].g;
116 palette[i].b = 255 - curpalettefaded[i].b;
117 }
118 }
119 else
120 {
121 for (bssize_t i = 0; i < 256; ++i)
122 Bmemcpy(&palette[i], &curpalettefaded[i], sizeof(palette[0]));
123 }
124
125 png_set_pal((uint8_t *)palette, 256);
126
127 for (int i = 0; i < ydim; ++i)
128 Bmemcpy(imgBuf + i * xdim, (uint8_t *)frameplace + ylookup[i], xdim);
129 }
130
131 videoEndDrawing(); //}}}
132
133 png_set_text("Software", osd->version.buf);
134 png_write(fp, xdim, ydim, HICOLOR ? PNG_TRUECOLOR : PNG_INDEXED, imgBuf);
135 Xfree(imgBuf);
136 screencapture_end(fn, &fp);
137
138 return 0;
139 }
140
videoCaptureScreenTGA(const char * filename,char inverseit)141 int videoCaptureScreenTGA(const char *filename, char inverseit)
142 {
143 int32_t i;
144 char head[18] = { 0,1,1,0,0,0,1,24,0,0,0,0,0/*wlo*/,0/*whi*/,0/*hlo*/,0/*hhi*/,8,0 };
145 //char palette[4*256];
146 char *fn = Xstrdup(filename);
147
148 buildvfs_FILE fil = capturecounter.opennextfile_withext(fn, "tga");
149 if (fil == nullptr)
150 {
151 Xfree(fn);
152 return -1;
153 }
154
155 #ifdef USE_OPENGL
156 if (HICOLOR)
157 {
158 head[1] = 0; // no colourmap
159 head[2] = 2; // uncompressed truecolour
160 head[3] = 0; // (low) first colourmap index
161 head[4] = 0; // (high) first colourmap index
162 head[5] = 0; // (low) number colourmap entries
163 head[6] = 0; // (high) number colourmap entries
164 head[7] = 0; // colourmap entry size
165 head[16] = 24; // 24 bits per pixel
166 }
167 #endif
168
169 head[12] = xdim & 0xff;
170 head[13] = (xdim >> 8) & 0xff;
171 head[14] = ydim & 0xff;
172 head[15] = (ydim >> 8) & 0xff;
173
174 buildvfs_fwrite(head, 18, 1, fil);
175
176 // palette first
177 #ifdef USE_OPENGL
178 if (!HICOLOR)
179 #endif
180 {
181 if (inverseit)
182 {
183 for (i=0; i<256; i++)
184 {
185 buildvfs_fputc(255 - curpalettefaded[i].b, fil);
186 buildvfs_fputc(255 - curpalettefaded[i].g, fil);
187 buildvfs_fputc(255 - curpalettefaded[i].r, fil);
188 }
189 }
190 else
191 {
192 for (i=0; i<256; i++)
193 {
194 buildvfs_fputc(curpalettefaded[i].b, fil);
195 buildvfs_fputc(curpalettefaded[i].g, fil);
196 buildvfs_fputc(curpalettefaded[i].r, fil);
197 }
198 }
199 }
200
201 videoBeginDrawing(); //{{{
202
203 # ifdef USE_OPENGL
204 if (HICOLOR)
205 {
206 // 24bit
207 int const size = xdim * ydim * 3;
208 uint8_t *inversebuf = (uint8_t *) Xmalloc(size);
209
210 glReadPixels(0, 0, xdim, ydim, GL_RGB, GL_UNSIGNED_BYTE, inversebuf);
211
212 for (i = 0; i < size; i += 3)
213 swapchar(&inversebuf[i], &inversebuf[i + 2]);
214
215 buildvfs_fwrite(inversebuf, xdim*ydim, 3, fil);
216 Xfree(inversebuf);
217 }
218 else
219 # endif
220 {
221 char * const ptr = (char *) frameplace;
222
223 for (i = ydim-1; i >= 0; i--)
224 buildvfs_fwrite(ptr + i * bytesperline, xdim, 1, fil);
225 }
226
227 videoEndDrawing(); //}}}
228
229 screencapture_end(fn, &fil);
230
231 return 0;
232 }
233 #undef HICOLOR
234
235