44 TScreenshot = record |
44 TScreenshot = record |
45 buffer: PByte; |
45 buffer: PByte; |
46 filename: shortstring; |
46 filename: shortstring; |
47 width, height: LongInt; |
47 width, height: LongInt; |
48 size: QWord; |
48 size: QWord; |
49 alpha: boolean; |
|
50 end; |
49 end; |
51 |
50 |
52 var conversionFormat : PSDL_PixelFormat; |
51 var conversionFormat : PSDL_PixelFormat; |
53 |
52 |
54 procedure movecursor(dx, dy: LongInt); |
53 procedure movecursor(dx, dy: LongInt); |
68 var i: LongInt; |
67 var i: LongInt; |
69 png_ptr: ^png_struct; |
68 png_ptr: ^png_struct; |
70 info_ptr: ^png_info; |
69 info_ptr: ^png_info; |
71 f: File; |
70 f: File; |
72 image: PScreenshot; |
71 image: PScreenshot; |
73 bpp: Integer; // bytes per pixel |
|
74 ctype: Integer; // png color type |
|
75 begin |
72 begin |
76 image:= PScreenshot(screenshot); |
73 image:= PScreenshot(screenshot); |
77 if image^.alpha then |
|
78 begin |
|
79 bpp:= 4; |
|
80 ctype:= PNG_COLOR_TYPE_RGBA; |
|
81 end |
|
82 else |
|
83 begin |
|
84 bpp:= 3; |
|
85 ctype:= PNG_COLOR_TYPE_RGB; |
|
86 end; |
|
87 |
74 |
88 png_ptr := png_create_write_struct(png_get_libpng_ver(nil), nil, nil, nil); |
75 png_ptr := png_create_write_struct(png_get_libpng_ver(nil), nil, nil, nil); |
89 if png_ptr = nil then |
76 if png_ptr = nil then |
90 begin |
77 begin |
91 // AddFileLog('Error: Could not create png write struct.'); |
78 // AddFileLog('Error: Could not create png write struct.'); |
108 if IOResult = 0 then |
95 if IOResult = 0 then |
109 begin |
96 begin |
110 png_init_pascal_io(png_ptr,@f); |
97 png_init_pascal_io(png_ptr,@f); |
111 png_set_IHDR(png_ptr, info_ptr, image^.width, image^.height, |
98 png_set_IHDR(png_ptr, info_ptr, image^.width, image^.height, |
112 8, // bit depth |
99 8, // bit depth |
113 ctype, PNG_INTERLACE_NONE, |
100 PNG_COLOR_TYPE_RGBA, PNG_INTERLACE_NONE, |
114 PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); |
101 PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); |
115 png_write_info(png_ptr, info_ptr); |
102 png_write_info(png_ptr, info_ptr); |
116 // glReadPixels and libpng number rows in different order |
103 // glReadPixels and libpng number rows in different order |
117 for i:= image^.height-1 downto 0 do |
104 for i:= image^.height-1 downto 0 do |
118 png_write_row(png_ptr, image^.buffer + i*bpp*image^.width); |
105 png_write_row(png_ptr, image^.buffer + i*4*image^.width); |
119 png_write_end(png_ptr, info_ptr); |
106 png_write_end(png_ptr, info_ptr); |
120 Close(f); |
107 Close(f); |
121 end; |
108 end; |
122 {$IOCHECKS ON} |
109 {$IOCHECKS ON} |
123 |
110 |
141 54, 0, 0, 0, // starting offset |
128 54, 0, 0, 0, // starting offset |
142 40, 0, 0, 0, // header size |
129 40, 0, 0, 0, // header size |
143 0, 0, 0, 0, // width |
130 0, 0, 0, 0, // width |
144 0, 0, 0, 0, // height |
131 0, 0, 0, 0, // height |
145 1, 0, // color planes |
132 1, 0, // color planes |
146 24, 0, // bit depth |
133 32, 0, // bit depth |
147 0, 0, 0, 0, // compression method (uncompressed) |
134 0, 0, 0, 0, // compression method (uncompressed) |
148 0, 0, 0, 0, // image size |
135 0, 0, 0, 0, // image size |
149 96, 0, 0, 0, // horizontal resolution |
136 96, 0, 0, 0, // horizontal resolution |
150 96, 0, 0, 0, // vertical resolution |
137 96, 0, 0, 0, // vertical resolution |
151 0, 0, 0, 0, // number of colors (all) |
138 0, 0, 0, 0, // number of colors (all) |
174 head[$22]:= size and $ff; |
161 head[$22]:= size and $ff; |
175 head[$23]:= (size shr 8) and $ff; |
162 head[$23]:= (size shr 8) and $ff; |
176 head[$24]:= (size shr 16) and $ff; |
163 head[$24]:= (size shr 16) and $ff; |
177 head[$25]:= (size shr 24) and $ff; |
164 head[$25]:= (size shr 24) and $ff; |
178 |
165 |
179 if image^.alpha then |
|
180 head[$1C]:= 32; |
|
181 |
|
182 {$IOCHECKS OFF} |
166 {$IOCHECKS OFF} |
183 Assign(f, image^.filename); |
167 Assign(f, image^.filename); |
184 Rewrite(f, 1); |
168 Rewrite(f, 1); |
185 if IOResult = 0 then |
169 if IOResult = 0 then |
186 begin |
170 begin |
202 |
186 |
203 {$ENDIF} // no PNG_SCREENSHOTS |
187 {$ENDIF} // no PNG_SCREENSHOTS |
204 |
188 |
205 {$IFDEF USE_VIDEO_RECORDING} |
189 {$IFDEF USE_VIDEO_RECORDING} |
206 // make image k times smaller (useful for saving thumbnails) |
190 // make image k times smaller (useful for saving thumbnails) |
207 procedure ReduceImage(img: PByte; width, height, k: LongInt; bpp: Integer); |
191 procedure ReduceImage(img: PByte; width, height, k: LongInt); |
208 var i, j, i0, j0, w, h, r, g, b, off, ksqr: LongInt; |
192 var i, j, i0, j0, w, h, r, g, b: LongInt; |
209 begin |
193 begin |
210 w:= width div k; |
194 w:= width div k; |
211 h:= height div k; |
195 h:= height div k; |
212 |
196 |
213 // rescale inplace |
197 // rescale inplace |
214 if k <> 1 then |
198 if k <> 1 then |
215 begin |
199 begin |
216 ksqr:= k*k; |
|
217 for i:= 0 to h-1 do |
200 for i:= 0 to h-1 do |
218 for j:= 0 to w-1 do |
201 for j:= 0 to w-1 do |
219 begin |
202 begin |
220 r:= 0; |
203 r:= 0; |
221 g:= 0; |
204 g:= 0; |
222 b:= 0; |
205 b:= 0; |
223 for i0:= 0 to k-1 do |
206 for i0:= 0 to k-1 do |
224 for j0:= 0 to k-1 do |
207 for j0:= 0 to k-1 do |
225 begin |
208 begin |
226 off:= bpp*(width*(i*k+i0) + j*k+j0); |
209 inc(r, img[4*(width*(i*k+i0) + j*k+j0)+0]); |
227 inc(r, img[off]); inc(off); |
210 inc(g, img[4*(width*(i*k+i0) + j*k+j0)+1]); |
228 inc(g, img[off]); inc(off); |
211 inc(b, img[4*(width*(i*k+i0) + j*k+j0)+2]); |
229 inc(b, img[off]); |
|
230 end; |
212 end; |
231 off:= bpp*(w*i + j); |
213 img[4*(w*i + j)+0]:= r div (k*k); |
232 img[off]:= r div (ksqr); inc(off); |
214 img[4*(w*i + j)+1]:= g div (k*k); |
233 img[off]:= g div (ksqr); inc(off); |
215 img[4*(w*i + j)+2]:= b div (k*k); |
234 img[off]:= b div (ksqr); |
216 img[4*(w*i + j)+3]:= 255; |
235 // if there's an alpha channel set opacity to max |
|
236 if bpp > 3 then |
|
237 begin |
|
238 inc(off); |
|
239 img[off]:= 255; |
|
240 end; |
|
241 end; |
217 end; |
242 end; |
218 end; |
243 end; |
219 end; |
244 {$ENDIF} |
220 {$ENDIF} |
245 |
221 |
250 size: QWord; |
226 size: QWord; |
251 image: PScreenshot; |
227 image: PScreenshot; |
252 format: GLenum; |
228 format: GLenum; |
253 ext: string[4]; |
229 ext: string[4]; |
254 x,y: LongWord; |
230 x,y: LongWord; |
255 hasA: boolean; |
231 begin |
256 bpp: Integer; |
|
257 begin |
|
258 hasA:= (dump > 0); |
|
259 |
|
260 if hasA then |
|
261 bpp:= 4 |
|
262 else |
|
263 bpp:= 3; |
|
264 |
|
265 {$IFDEF PNG_SCREENSHOTS} |
232 {$IFDEF PNG_SCREENSHOTS} |
266 if hasA then |
233 format:= GL_RGBA; |
267 format:= GL_RGBA |
|
268 else |
|
269 format:= GL_RGB; |
|
270 ext:= '.png'; |
234 ext:= '.png'; |
271 {$ELSE} |
235 {$ELSE} |
272 if hasA then |
236 format:= GL_BGRA; |
273 format:= GL_BGRA |
|
274 else |
|
275 format:= GL_BGR; |
|
276 ext:= '.bmp'; |
237 ext:= '.bmp'; |
277 {$ENDIF} |
238 {$ENDIF} |
278 |
239 |
279 if dump > 0 then |
240 if dump > 0 then |
280 size:= LAND_WIDTH*LAND_HEIGHT*bpp |
241 size:= LAND_WIDTH*LAND_HEIGHT*4 |
281 else size:= toPowerOf2(cScreenWidth) * toPowerOf2(cScreenHeight) * bpp; |
242 else size:= toPowerOf2(cScreenWidth) * toPowerOf2(cScreenHeight) * 4; |
282 p:= GetMem(size); // will be freed in SaveScreenshot() |
243 p:= GetMem(size); // will be freed in SaveScreenshot() |
283 |
244 |
284 // memory could not be allocated |
245 // memory could not be allocated |
285 if p = nil then |
246 if p = nil then |
286 begin |
247 begin |
314 end |
275 end |
315 else |
276 else |
316 begin |
277 begin |
317 glReadPixels(0, 0, cScreenWidth, cScreenHeight, format, GL_UNSIGNED_BYTE, p); |
278 glReadPixels(0, 0, cScreenWidth, cScreenHeight, format, GL_UNSIGNED_BYTE, p); |
318 {$IFDEF USE_VIDEO_RECORDING} |
279 {$IFDEF USE_VIDEO_RECORDING} |
319 ReduceImage(p, cScreenWidth, cScreenHeight, k, bpp) |
280 ReduceImage(p, cScreenWidth, cScreenHeight, k) |
320 {$ENDIF} |
281 {$ENDIF} |
321 end; |
282 end; |
322 |
283 |
323 // allocate and fill structure that will be passed to new thread |
284 // allocate and fill structure that will be passed to new thread |
324 New(image); // will be disposed in SaveScreenshot() |
285 New(image); // will be disposed in SaveScreenshot() |
338 image^.width:= cScreenWidth div k; |
299 image^.width:= cScreenWidth div k; |
339 image^.height:= cScreenHeight div k |
300 image^.height:= cScreenHeight div k |
340 end; |
301 end; |
341 image^.size:= size; |
302 image^.size:= size; |
342 image^.buffer:= p; |
303 image^.buffer:= p; |
343 image^.alpha:= hasA; |
|
344 |
304 |
345 SDL_CreateThread(@SaveScreenshot{$IFDEF SDL2}, 'snapshot'{$ENDIF}, image); |
305 SDL_CreateThread(@SaveScreenshot{$IFDEF SDL2}, 'snapshot'{$ENDIF}, image); |
346 MakeScreenshot:= true; // possibly it is not true but we will not wait for thread to terminate |
306 MakeScreenshot:= true; // possibly it is not true but we will not wait for thread to terminate |
347 end; |
307 end; |
348 |
308 |