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