hedgewars/uMisc.pas
changeset 10693 9819e69bc6db
parent 10692 a88647ead05c
child 10748 dc587913987c
child 11041 598fa14a3a1a
equal deleted inserted replaced
10692:a88647ead05c 10693:9819e69bc6db
    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