foxygit / doom Log in
commit 002822dfa2bd78f946b7e4730004220919d4ddb9
Author:     Fabian Greffrath <fabian@greffrath.com>
AuthorDate: Mon Mar 17 16:42:49 2014 +0100
Commit:     Fabian Greffrath <fabian@greffrath.com>
CommitDate: Mon Mar 17 16:42:49 2014 +0100

    Allow for PNG screenshots.
---
 configure.ac         |  8 +++++
 src/doom/g_game.c    |  2 +-
 src/heretic/g_game.c |  2 +-
 src/hexen/g_game.c   |  2 +-
 src/i_video.c        |  5 +++
 src/m_config.c       |  6 ++++
 src/setup/display.c  |  2 ++
 src/strife/g_game.c  |  2 +-
 src/v_video.c        | 98 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 9 files changed, 122 insertions(+), 5 deletions(-)

diff --git a/configure.ac b/configure.ac
index 90c2752a..04ad2865 100644
--- a/configure.ac
+++ b/configure.ac
@@ -80,6 +80,14 @@ AC_SDL_MAIN_WORKAROUND([
     [
         AC_CHECK_LIB(samplerate, src_new)
     ])
+    # Check for libpng.
+    AC_ARG_WITH([libpng],
+    AS_HELP_STRING([--without-libpng],
+        [Build without libpng @<:@default=check@:>@]),
+    [],
+    [
+        AC_CHECK_LIB(png, png_get_io_ptr)
+    ])
     AC_CHECK_LIB(m, log)

     AC_CHECK_HEADERS([linux/kd.h dev/isa/spkrio.h dev/speaker/speaker.h])
diff --git a/src/doom/g_game.c b/src/doom/g_game.c
index f2be98f8..a36267ca 100644
--- a/src/doom/g_game.c
+++ b/src/doom/g_game.c
@@ -870,7 +870,7 @@ void G_Ticker (void)
 	    G_DoWorldDone ();
 	    break;
 	  case ga_screenshot:
-	    V_ScreenShot("DOOM%02i.pcx");
+	    V_ScreenShot("DOOM%02i.%s");
             players[consoleplayer].message = DEH_String("screen shot");
 	    gameaction = ga_nothing;
 	    break;
diff --git a/src/heretic/g_game.c b/src/heretic/g_game.c
index 48e68a2a..2ad9f4b3 100644
--- a/src/heretic/g_game.c
+++ b/src/heretic/g_game.c
@@ -930,7 +930,7 @@ void G_Ticker(void)
                 G_DoPlayDemo();
                 break;
             case ga_screenshot:
-                V_ScreenShot("HTIC%02i.pcx");
+                V_ScreenShot("HTIC%02i.%s");
                 gameaction = ga_nothing;
                 break;
             case ga_completed:
diff --git a/src/hexen/g_game.c b/src/hexen/g_game.c
index cb6d7130..4e40f578 100644
--- a/src/hexen/g_game.c
+++ b/src/hexen/g_game.c
@@ -934,7 +934,7 @@ void G_Ticker(void)
                 G_DoPlayDemo();
                 break;
             case ga_screenshot:
-                V_ScreenShot("HEXEN%02i.pcx");
+                V_ScreenShot("HEXEN%02i.%s");
                 P_SetMessage(&players[consoleplayer], "SCREEN SHOT", false);
                 gameaction = ga_nothing;
                 break;
diff --git a/src/i_video.c b/src/i_video.c
index 1add5312..d3f674d4 100644
--- a/src/i_video.c
+++ b/src/i_video.c
@@ -178,6 +178,10 @@ static unsigned int mouse_button_state = 0;

 int novert = 0;

+// Save screenshots in PNG format.
+
+int png_screenshots = 0;
+
 // if true, I_VideoBuffer is screen->pixels

 static boolean native_surface;
@@ -2220,6 +2224,7 @@ void I_BindVideoVariables(void)
     M_BindVariable("usegamma",                  &usegamma);
     M_BindVariable("vanilla_keyboard_mapping",  &vanilla_keyboard_mapping);
     M_BindVariable("novert",                    &novert);
+    M_BindVariable("png_screenshots",           &png_screenshots);

     // Windows Vista or later?  Set screen color depth to
     // 32 bits per pixel, as 8-bit palettized screen modes
diff --git a/src/m_config.c b/src/m_config.c
index dd15f1af..2bce54bc 100644
--- a/src/m_config.c
+++ b/src/m_config.c
@@ -1434,6 +1434,12 @@ static default_t extra_defaults_list[] =
     //

     CONFIG_VARIABLE_KEY(key_multi_msgplayer8),
+
+    //!
+    // If non-zero, save screenshots in PNG format.
+    //
+
+    CONFIG_VARIABLE_INT(png_screenshots),
 };

 static default_collection_t extra_defaults =
diff --git a/src/setup/display.c b/src/setup/display.c
index 494d732a..99c3d8aa 100644
--- a/src/setup/display.c
+++ b/src/setup/display.c
@@ -110,6 +110,7 @@ static int usegamma = 0;

 int graphical_startup = 1;
 int show_endoom = 1;
+int png_screenshots = 0;

 // These are the last screen width/height values that were chosen by the
 // user.  These are used when finding the "nearest" mode, so when
@@ -710,6 +711,7 @@ void BindDisplayVariables(void)
     M_BindVariable("video_driver",              &video_driver);
     M_BindVariable("window_position",           &window_position);
     M_BindVariable("usegamma",                  &usegamma);
+    M_BindVariable("png_screenshots",           &png_screenshots);


     if (gamemission == doom || gamemission == heretic
diff --git a/src/strife/g_game.c b/src/strife/g_game.c
index 19f3e1fe..dc9ee351 100644
--- a/src/strife/g_game.c
+++ b/src/strife/g_game.c
@@ -937,7 +937,7 @@ void G_Ticker (void)
             G_DoWorldDone ();
             break;
         case ga_screenshot:
-            V_ScreenShot("STRIFE%02i.pcx"); // [STRIFE] file name, message
+            V_ScreenShot("STRIFE%02i.%s"); // [STRIFE] file name, message
             players[consoleplayer].message = DEH_String("STRIFE  by Rogue entertainment");
             gameaction = ga_nothing;
             break;
diff --git a/src/v_video.c b/src/v_video.c
index 0cf64926..60817086 100644
--- a/src/v_video.c
+++ b/src/v_video.c
@@ -44,6 +44,11 @@
 #include "w_wad.h"
 #include "z_zone.h"

+#include "config.h"
+#ifdef HAVE_LIBPNG
+#include <png.h>
+#endif
+
 // TODO: There are separate RANGECHECK defines for different games, but this
 // is common code. Fix this.
 #define RANGECHECK
@@ -706,6 +711,81 @@ void WritePCXfile(char *filename, byte *data,
     Z_Free (pcx);
 }

+#ifdef HAVE_LIBPNG
+//
+// WritePNGfile
+//
+
+static void error_fn(png_structp p, png_const_charp s)
+{
+    printf("libpng error: %s\n", s);
+}
+
+static void warning_fn(png_structp p, png_const_charp s)
+{
+    printf("libpng warning: %s\n", s);
+}
+
+void WritePNGfile(char *filename, byte *data,
+                  int width, int height,
+                  byte *palette)
+{
+    png_structp ppng;
+    png_infop pinfo;
+    png_colorp pcolor;
+    FILE *handle;
+    int i;
+
+    handle = fopen(filename, "wb");
+    if (!handle)
+        return;
+
+    ppng = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL,
+                                   error_fn, warning_fn);
+    if (!ppng)
+        return;
+
+    pinfo = png_create_info_struct(ppng);
+    if (!pinfo)
+    {
+        png_destroy_write_struct(&ppng, NULL);
+        return;
+    }
+
+    png_init_io(ppng, handle);
+
+    png_set_IHDR(ppng, pinfo, width, height,
+                 8, PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE,
+                 PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
+
+    pcolor = malloc(sizeof(*pcolor) * 256);
+    if (!pcolor)
+    {
+        png_destroy_write_struct(&ppng, &pinfo);
+        return;
+    }
+
+    for (i = 0; i < 256; i++)
+    {
+        pcolor[i].red   = *(palette + 3 * i + 0);
+        pcolor[i].green = *(palette + 3 * i + 1);
+        pcolor[i].blue  = *(palette + 3 * i + 2);
+    }
+
+    png_set_PLTE(ppng, pinfo, pcolor, 256);
+    free(pcolor);
+
+    png_write_info(ppng, pinfo);
+
+    for (i = 0; i < SCREENHEIGHT; i++)
+        png_write_row(ppng, data + i*SCREENWIDTH);
+
+    png_write_end(ppng, pinfo);
+    png_destroy_write_struct(&ppng, &pinfo);
+    fclose(handle);
+}
+#endif
+
 //
 // V_ScreenShot
 //
@@ -714,12 +794,21 @@ void V_ScreenShot(char *format)
 {
     int i;
     char lbmname[16]; // haleyjd 20110213: BUG FIX - 12 is too small!
+    char *ext;
+    extern int png_screenshots;

     // find a file name to save it to

+#ifdef HAVE_LIBPNG
+    if (png_screenshots)
+        ext = "png";
+    else
+#endif
+        ext = "pcx";
+
     for (i=0; i<=99; i++)
     {
-        sprintf(lbmname, format, i);
+        sprintf(lbmname, format, i, ext);

         if (!M_FileExists(lbmname))
         {
@@ -732,6 +821,13 @@ void V_ScreenShot(char *format)
         I_Error ("V_ScreenShot: Couldn't create a PCX");
     }

+#ifdef HAVE_LIBPNG
+    if (png_screenshots)
+    WritePNGfile(lbmname, I_VideoBuffer,
+                 SCREENWIDTH, SCREENHEIGHT,
+                 W_CacheLumpName (DEH_String("PLAYPAL"), PU_CACHE));
+    else
+#endif
     // save the pcx file
     WritePCXfile(lbmname, I_VideoBuffer,
                  SCREENWIDTH, SCREENHEIGHT,