don't save alpha channel to screenshots when not needed
authorsheepluva
Wed, 17 Dec 2014 23:01:43 +0100
changeset 10692 a88647ead05c
parent 10691 97f45f1374be
child 10693 9819e69bc6db
don't save alpha channel to screenshots when not needed
hedgewars/uMisc.pas
--- a/hedgewars/uMisc.pas	Wed Dec 17 21:01:44 2014 +0100
+++ b/hedgewars/uMisc.pas	Wed Dec 17 23:01:43 2014 +0100
@@ -46,6 +46,7 @@
          filename: shortstring;
          width, height: LongInt;
          size: QWord;
+         alpha: boolean;
          end;
 
 var conversionFormat : PSDL_PixelFormat;
@@ -69,8 +70,20 @@
     info_ptr: ^png_info;
     f: File;
     image: PScreenshot;
+    bpp: Integer; // bytes per pixel
+    ctype: Integer; // png color type
 begin
 image:= PScreenshot(screenshot);
+if image^.alpha then
+    begin
+    bpp:= 4;
+    ctype:= PNG_COLOR_TYPE_RGBA;
+    end
+else
+    begin
+    bpp:= 3;
+    ctype:= PNG_COLOR_TYPE_RGB;
+    end;
 
 png_ptr := png_create_write_struct(png_get_libpng_ver(nil), nil, nil, nil);
 if png_ptr = nil then
@@ -97,12 +110,12 @@
     png_init_pascal_io(png_ptr,@f);
     png_set_IHDR(png_ptr, info_ptr, image^.width, image^.height,
                  8, // bit depth
-                 PNG_COLOR_TYPE_RGBA, PNG_INTERLACE_NONE,
+                 ctype, PNG_INTERLACE_NONE,
                  PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
     png_write_info(png_ptr, info_ptr);
     // glReadPixels and libpng number rows in different order
     for i:= image^.height-1 downto 0 do
-        png_write_row(png_ptr, image^.buffer + i*4*image^.width);
+        png_write_row(png_ptr, image^.buffer + i*bpp*image^.width);
     png_write_end(png_ptr, info_ptr);
     Close(f);
     end;
@@ -130,7 +143,7 @@
     0, 0, 0, 0,     // width
     0, 0, 0, 0,     // height
     1, 0,           // color planes
-    32, 0,          // bit depth
+    24, 0,          // bit depth
     0, 0, 0, 0,     // compression method (uncompressed)
     0, 0, 0, 0,     // image size
     96, 0, 0, 0,    // horizontal resolution
@@ -163,6 +176,9 @@
 head[$24]:= (size shr 16) and $ff;
 head[$25]:= (size shr 24) and $ff;
 
+if image^.alpha then
+    head[$1C]:= 32;
+
 {$IOCHECKS OFF}
 Assign(f, image^.filename);
 Rewrite(f, 1);
@@ -188,8 +204,8 @@
 
 {$IFDEF USE_VIDEO_RECORDING}
 // make image k times smaller (useful for saving thumbnails)
-procedure ReduceImage(img: PByte; width, height, k: LongInt);
-var i, j, i0, j0, w, h, r, g, b: LongInt;
+procedure ReduceImage(img: PByte; width, height, k: LongInt; bpp: Integer);
+    var i, j, i0, j0, w, h, r, g, b, off, ksqr: LongInt;
 begin
     w:= width  div k;
     h:= height div k;
@@ -197,6 +213,7 @@
     // rescale inplace
     if k <> 1 then
     begin
+        ksqr:= k*k;
         for i:= 0 to h-1 do
             for j:= 0 to w-1 do
             begin
@@ -206,14 +223,21 @@
                 for i0:= 0 to k-1 do
                     for j0:= 0 to k-1 do
                     begin
-                        inc(r, img[4*(width*(i*k+i0) + j*k+j0)+0]);
-                        inc(g, img[4*(width*(i*k+i0) + j*k+j0)+1]);
-                        inc(b, img[4*(width*(i*k+i0) + j*k+j0)+2]);
+                        off:= bpp*(width*(i*k+i0) + j*k+j0);
+                        inc(r, img[off]); inc(off);
+                        inc(g, img[off]); inc(off);
+                        inc(b, img[off]);
                     end;
-                img[4*(w*i + j)+0]:= r div (k*k);
-                img[4*(w*i + j)+1]:= g div (k*k);
-                img[4*(w*i + j)+2]:= b div (k*k);
-                img[4*(w*i + j)+3]:= 255;
+                off:= bpp*(w*i + j);
+                img[off]:= r div (ksqr); inc(off);
+                img[off]:= g div (ksqr); inc(off);
+                img[off]:= b div (ksqr);
+                // if there's an alpha channel set opacity to max
+                if bpp > 3 then
+                    begin
+                    inc(off);
+                    img[off]:= 255;
+                    end;
             end;
     end;
 end;
@@ -228,18 +252,33 @@
     format: GLenum;
     ext: string[4];
     x,y: LongWord;
+    hasA: boolean;
+    bpp: Integer;
 begin
+hasA:= (dump > 0);
+
+if hasA then
+    bpp:= 4
+else
+    bpp:= 3;
+
 {$IFDEF PNG_SCREENSHOTS}
-format:= GL_RGBA;
+if hasA then
+    format:= GL_RGBA
+else
+    format:= GL_RGB;
 ext:= '.png';
 {$ELSE}
-format:= GL_BGRA;
+if hasA then
+    format:= GL_BGRA
+else
+    format:= GL_BGR;
 ext:= '.bmp';
 {$ENDIF}
 
 if dump > 0 then
-     size:= LAND_WIDTH*LAND_HEIGHT*4
-else size:= toPowerOf2(cScreenWidth) * toPowerOf2(cScreenHeight) * 4;
+     size:= LAND_WIDTH*LAND_HEIGHT*bpp
+else size:= toPowerOf2(cScreenWidth) * toPowerOf2(cScreenHeight) * bpp;
 p:= GetMem(size); // will be freed in SaveScreenshot()
 
 // memory could not be allocated
@@ -277,7 +316,7 @@
     begin
     glReadPixels(0, 0, cScreenWidth, cScreenHeight, format, GL_UNSIGNED_BYTE, p);
 {$IFDEF USE_VIDEO_RECORDING}
-    ReduceImage(p, cScreenWidth, cScreenHeight, k)
+    ReduceImage(p, cScreenWidth, cScreenHeight, k, bpp)
 {$ENDIF}
     end;
 
@@ -301,6 +340,7 @@
     end;
 image^.size:= size;
 image^.buffer:= p;
+image^.alpha:= hasA;
 
 SDL_CreateThread(@SaveScreenshot{$IFDEF SDL2}, 'snapshot'{$ENDIF}, image);
 MakeScreenshot:= true; // possibly it is not true but we will not wait for thread to terminate