From 9946bbb8c1f21b678ef577ad741d16595db75849 Mon Sep 17 00:00:00 2001
From: jsalmon3 <>
Date: Fri, 31 May 2002 06:10:28 +0000
Subject: [PATCH] Implemented task #38320: Making screen shots

---
 src/game/intro.cpp      |  10 ++--
 src/include/interface.h |   1 +
 src/include/video.h     |   3 ++
 src/ui/interface.cpp    |  25 ++++++++++
 src/video/png.cpp       | 101 ++++++++++++++++++++++++++++++++++++++++
 src/video/sdl.cpp       |   3 ++
 6 files changed, 139 insertions(+), 4 deletions(-)

diff --git a/src/game/intro.cpp b/src/game/intro.cpp
index 3e3a71e75..3354304f0 100644
--- a/src/game/intro.cpp
+++ b/src/game/intro.cpp
@@ -114,9 +114,10 @@ local void IntroCallbackButton2(unsigned button)
 /**
 **	Callback for input.
 */
-local void IntroCallbackKey1(unsigned key __attribute__((unused)),
-	unsigned keychar)
+local void IntroCallbackKey1(unsigned key, unsigned keychar)
 {
+    HandleKeyModifiersDown(key,keychar);
+
     if (UseContinueButton) {
 	if (keychar == 'c' || keychar == '\r') {
 	    ContinueButtonFlags |= MenuButtonClicked;
@@ -129,9 +130,10 @@ local void IntroCallbackKey1(unsigned key __attribute__((unused)),
 /**
 **	Callback for input.
 */
-local void IntroCallbackKey2(unsigned key,
-	unsigned keychar __attribute__((unused)))
+local void IntroCallbackKey2(unsigned key, unsigned keychar)
 {
+    HandleKeyModifiersDown(key,keychar);
+
     if( UseContinueButton ) {
 	if( (key =='c' || key =='\r') &&
 	    (ContinueButtonFlags&MenuButtonClicked) ) {
diff --git a/src/include/interface.h b/src/include/interface.h
index a423a5196..7f1345bed 100644
--- a/src/include/interface.h
+++ b/src/include/interface.h
@@ -130,6 +130,7 @@ enum _key_codes_ {
     KeyCodeAlt,				/// internal keycode: alt modifier
     KeyCodeSuper,			/// internal keycode: super modifier
     KeyCodeHyper,			/// internal keycode: hyper modifier
+    KeyCodePrint,			/// internal keycode: print screen
 };
 
     /// Key modifier
diff --git a/src/include/video.h b/src/include/video.h
index 824b0e4d5..0ed2cd198 100644
--- a/src/include/video.h
+++ b/src/include/video.h
@@ -1137,6 +1137,9 @@ extern void WaitEventsOneFrame(const EventCallback* callbacks);
     ///	Load graphic from PNG file
 extern Graphic* LoadGraphicPNG(const char* name);
 
+    ///	Save a screenshot to a PNG file
+extern void SaveScreenshotPNG(const char* name);
+
     /// New graphic
 extern Graphic* NewGraphic(unsigned d,unsigned w,unsigned h);
 
diff --git a/src/ui/interface.cpp b/src/ui/interface.cpp
index 65dc4a65b..dba44266f 100644
--- a/src/ui/interface.cpp
+++ b/src/ui/interface.cpp
@@ -51,6 +51,7 @@
 #include "font.h"
 #include "campaign.h"
 #include "video.h"
+#include "iolib.h"
 
 /*----------------------------------------------------------------------------
 --	Declaration
@@ -984,6 +985,27 @@ local int InputKey(int key)
     return 0;
 }
 
+
+/**
+**	Save a screenshot.
+*/
+local void Screenshot()
+{
+    CLFile *fd;
+    char filename[1024];
+    int i;
+
+    for( i=1; i<99; ++i ) {
+	sprintf(filename, "screen%02d.png", i);
+	if( !(fd = CLopen(filename)) ) {
+	    break;
+	}
+	CLclose(fd);
+    }
+    SaveScreenshotPNG(filename);
+}
+
+
 /**
 **	Update KeyModifiers if a key is pressed.
 **
@@ -1012,6 +1034,9 @@ global int HandleKeyModifiersDown(unsigned key,
 	case KeyCodeHyper:
 	    KeyModifiers|=ModifierHyper;
 	    return 1;
+	case KeyCodePrint:
+	    Screenshot();
+	    return 1;
 	default:
 	    break;
     }
diff --git a/src/video/png.cpp b/src/video/png.cpp
index 27242de94..19a65aa5b 100644
--- a/src/video/png.cpp
+++ b/src/video/png.cpp
@@ -209,4 +209,105 @@ global Graphic* LoadGraphicPNG(const char* name)
     return graphic;
 }
 
+/**
+**	Save a screenshot to a PNG file.
+**
+**	@param name	PNG filename to save.
+*/
+global void SaveScreenshotPNG(const char* name)
+{
+    FILE *fp;
+    png_structp png_ptr;
+    png_infop info_ptr;
+    unsigned char* row;
+    int i, j;
+
+    fp = fopen(name, "wb");
+    if (fp == NULL)
+	return;
+
+    png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
+    if (png_ptr == NULL) {
+	fclose(fp);
+	return;
+    }
+
+    info_ptr = png_create_info_struct(png_ptr);
+    if (info_ptr == NULL) {
+	fclose(fp);
+	png_destroy_write_struct(&png_ptr,  png_infopp_NULL);
+	return;
+    }
+
+    if (setjmp(png_jmpbuf(png_ptr)))
+    {
+	/* If we get here, we had a problem reading the file */
+	fclose(fp);
+	png_destroy_write_struct(&png_ptr, &info_ptr);
+	return;
+    }
+
+    /* set up the output control if you are using standard C streams */
+    png_init_io(png_ptr, fp);
+
+    png_set_IHDR(png_ptr, info_ptr, VideoWidth, VideoHeight, 8,
+	PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
+	PNG_FILTER_TYPE_DEFAULT);
+
+    png_set_bgr(png_ptr);
+
+    VideoLockScreen();
+
+    row = (char*)malloc(VideoWidth*3);
+
+    png_write_info(png_ptr, info_ptr);
+
+    for (i=0; i<VideoHeight; ++i) {
+	switch (VideoBpp) {
+	case 8:
+	    // FIXME: Finish
+	    break;
+	case 15:
+	    for (j=0; j<VideoWidth; ++j) {
+		VMemType16 c = VideoMemory16[i*VideoWidth+j];
+		row[j*3+0] = (((c >> 0) & 0x1f) * 0xff) / 0x1f;
+		row[j*3+1] = (((c >> 5) & 0x1f) * 0xff) / 0x1f;
+		row[j*3+2] = (((c >> 10) & 0x1f) * 0xff) / 0x1f;
+	    }
+	    break;
+	case 16:
+	    for (j=0; j<VideoWidth; ++j) {
+		VMemType16 c = VideoMemory16[i*VideoWidth+j];
+		row[j*3+0] = (((c >> 0) & 0x1f) * 0xff) / 0x1f;
+		row[j*3+1] = (((c >> 5) & 0x3f) * 0xff) / 0x3f;
+		row[j*3+2] = (((c >> 11) & 0x1f) * 0xff) / 0x1f;
+	    }
+	    break;
+	case 24:
+	    memcpy(row, VideoMemory24+i*VideoWidth, VideoWidth*3);
+	    break;
+	case 32:
+	    for (j=0; j<VideoWidth; ++j) {
+		VMemType32 c = VideoMemory32[i*VideoWidth+j];
+		row[j*3+0] = ((c >> 0) & 0xff);
+		row[j*3+1] = ((c >> 8) & 0xff);
+		row[j*3+2] = ((c >> 16) & 0xff);
+	    }
+	    break;
+	}
+	png_write_row(png_ptr, row);
+    }
+
+    png_write_end(png_ptr, info_ptr);
+
+    VideoUnlockScreen();
+
+    /* clean up after the write, and free any memory allocated */
+    png_destroy_write_struct(&png_ptr, &info_ptr);
+
+    free(row);
+
+    fclose(fp);
+}
+
 //@}
diff --git a/src/video/sdl.cpp b/src/video/sdl.cpp
index 3926e9098..f58b8155f 100644
--- a/src/video/sdl.cpp
+++ b/src/video/sdl.cpp
@@ -372,6 +372,9 @@ local int Sdl2InternalKeycode(const SDL_keysym * code, int *keychar)
 	case SDLK_KP_MINUS:
 	    icode = KeyCodeKPMinus;
 	    break;
+	case SDLK_SYSREQ:
+	    icode = KeyCodePrint;
+	    break;
 
 	    // We need these because if you only hit a modifier key,
 	    // the *ots from SDL don't report correct modifiers