From: Christoph Sommer Date: Mon, 9 Apr 2007 00:24:45 +0000 (+0000) Subject: "Print Screen"-Key takes screenshots X-Git-Url: https://git.verplant.org/?a=commitdiff_plain;h=a93bdf2bb864dc6ba7f9722b151e432fcab57240;p=supertux.git "Print Screen"-Key takes screenshots SVN-Revision: 4972 --- diff --git a/src/mainloop.cpp b/src/mainloop.cpp index 07d853619..0a2daebde 100644 --- a/src/mainloop.cpp +++ b/src/mainloop.cpp @@ -49,7 +49,7 @@ static const int MAX_FRAME_SKIP = 2; MainLoop* main_loop = NULL; MainLoop::MainLoop() - : speed(1.0), nextpop(false), nextpush(false), fps(0) + : speed(1.0), nextpop(false), nextpush(false), fps(0), screenshot_requested(false) { using namespace Scripting; TimeScheduler::instance = new TimeScheduler(); @@ -135,6 +135,11 @@ MainLoop::draw(DrawingContext& context) if(config->show_fps) draw_fps(context, fps); + // if a screenshot was requested, pass request on to drawing_context + if (screenshot_requested) { + context.take_screenshot(); + screenshot_requested = false; + } context.do_drawing(); /* Calculate frames per second */ @@ -177,6 +182,9 @@ MainLoop::process_events() config->use_fullscreen = !config->use_fullscreen; init_video(); } + else if (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_PRINT) { + take_screenshot(); + } } } @@ -262,3 +270,10 @@ MainLoop::run() SDL_Delay(0); } } + +void +MainLoop::take_screenshot() +{ + screenshot_requested = true; +} + diff --git a/src/mainloop.hpp b/src/mainloop.hpp index cb5bbeda2..244c63f9f 100644 --- a/src/mainloop.hpp +++ b/src/mainloop.hpp @@ -39,6 +39,11 @@ public: void quit(ScreenFade* fade = NULL); void set_speed(float speed); + /** + * requests that a screenshot be taken after the next frame has been rendered + */ + void take_screenshot(); + // push new screen on screen_stack void push_screen(Screen* screen, ScreenFade* fade = NULL); void set_screen_fade(ScreenFade* fade); @@ -64,6 +69,7 @@ private: std::auto_ptr console; std::auto_ptr screen_fade; std::vector screen_stack; + bool screenshot_requested; /**< true if a screenshot should be taken after the next frame has been rendered */ }; extern MainLoop* main_loop; diff --git a/src/video/drawing_context.cpp b/src/video/drawing_context.cpp index 89a92f247..60faef5b7 100644 --- a/src/video/drawing_context.cpp +++ b/src/video/drawing_context.cpp @@ -24,6 +24,9 @@ #include #include #include +#include +#include +#include #include "drawing_context.hpp" #include "surface.hpp" @@ -106,7 +109,7 @@ static inline int next_po2(int val) } DrawingContext::DrawingContext() - : ambient_color(1.0f, 1.0f, 1.0f, 1.0f), target(NORMAL) + : ambient_color(1.0f, 1.0f, 1.0f, 1.0f), target(NORMAL), screenshot_requested(false) { screen = SDL_GetVideoSurface(); @@ -495,6 +498,12 @@ DrawingContext::do_drawing() obstack_init(&obst); assert_gl("drawing"); + // if a screenshot was requested, take one + if (screenshot_requested) { + do_take_screenshot(); + screenshot_requested = false; + } + SDL_GL_SwapBuffers(); } @@ -626,3 +635,69 @@ DrawingContext::set_ambient_color( Color new_color ) { ambient_color = new_color; } + +void +DrawingContext::do_take_screenshot() +{ + // [Christoph] TODO: Yes, this method also takes care of the actual disk I/O. Split it? + + // create surface to hold screenshot + #if SDL_BYTEORDER == SDL_BIG_ENDIAN + SDL_Surface* shot_surf = SDL_CreateRGBSurface(SDL_SWSURFACE, SCREEN_WIDTH, SCREEN_HEIGHT, 24, 0x00FF0000, 0x0000FF00, 0x000000FF, 0); + #else + SDL_Surface* shot_surf = SDL_CreateRGBSurface(SDL_SWSURFACE, SCREEN_WIDTH, SCREEN_HEIGHT, 24, 0x000000FF, 0x0000FF00, 0x00FF0000, 0); + #endif + if (!shot_surf) { + log_warning << "Could not create RGB Surface to contain screenshot" << std::endl; + return; + } + + // read pixels into array + char* pixels = new char[3 * SCREEN_WIDTH * SCREEN_HEIGHT]; + if (!pixels) { + log_warning << "Could not allocate memory to store screenshot" << std::endl; + SDL_FreeSurface(shot_surf); + return; + } + glReadPixels(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, GL_RGB, GL_UNSIGNED_BYTE, pixels); + + // copy array line-by-line + for (int i = 0; i < SCREEN_HEIGHT; i++) { + char* src = pixels + (3 * SCREEN_WIDTH * (SCREEN_HEIGHT - i - 1)); + char* dst = ((char*)shot_surf->pixels) + i * shot_surf->pitch; + memcpy(dst, src, 3 * SCREEN_WIDTH); + } + + // free array + delete[](pixels); + + // save screenshot + static const std::string writeDir = PHYSFS_getWriteDir(); + static const std::string dirSep = PHYSFS_getDirSeparator(); + static const std::string baseName = "screenshot"; + static const std::string fileExt = ".bmp"; + std::string fullFilename; + for (int num = 0; num < 1000; num++) { + std::ostringstream oss; + oss << baseName; + oss << std::setw(3) << std::setfill('0') << num; + oss << fileExt; + std::string fileName = oss.str(); + fullFilename = writeDir + dirSep + fileName; + if (!PHYSFS_exists(fileName.c_str())) { + SDL_SaveBMP(shot_surf, fullFilename.c_str()); + log_debug << "Wrote screenshot to \"" << fullFilename << "\"" << std::endl; + SDL_FreeSurface(shot_surf); + return; + } + } + log_warning << "Did not save screenshot, because all files up to \"" << fullFilename << "\" already existed" << std::endl; + SDL_FreeSurface(shot_surf); +} + +void +DrawingContext::take_screenshot() +{ + screenshot_requested = true; +} + diff --git a/src/video/drawing_context.hpp b/src/video/drawing_context.hpp index de882a739..b742b3726 100644 --- a/src/video/drawing_context.hpp +++ b/src/video/drawing_context.hpp @@ -138,6 +138,11 @@ public: void set_ambient_color( Color new_color ); + /** + * requests that a screenshot be taken after the next frame has been rendered + */ + void take_screenshot(); + private: class Transform { @@ -174,6 +179,7 @@ private: void draw_filled_rect(const DrawingRequest& request) const; void draw_lightmap(const DrawingRequest& request) const; void get_light(const DrawingRequest& request) const; + void do_take_screenshot(); DrawingRequests drawing_requests; DrawingRequests lightmap_requests; @@ -190,6 +196,8 @@ private: /* obstack holding the memory of the drawing requests */ struct obstack obst; + + bool screenshot_requested; /**< true if a screenshot should be taken after the next frame has been rendered */ }; #endif