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