From 5b51e670447ea175fb9b0b7035403b274e16972e Mon Sep 17 00:00:00 2001 From: Simon Robertshaw Date: Fri, 17 Aug 2012 23:09:48 +0100 Subject: [PATCH] PPM screen recording --- src/Format.cpp | 27 +++++++++++++++ src/Format.h | 1 + src/game/GameController.h | 1 + src/game/GameView.cpp | 69 +++++++++++++++++++++++++++++++++++++-- src/game/GameView.h | 9 +++++ 5 files changed, 105 insertions(+), 2 deletions(-) diff --git a/src/Format.cpp b/src/Format.cpp index ef0050dfb..c290e71d0 100644 --- a/src/Format.cpp +++ b/src/Format.cpp @@ -2,7 +2,10 @@ #include #include #include +#include +#include #include +#include #include "Format.h" #include "graphics/Graphics.h" @@ -37,6 +40,30 @@ std::string format::UnixtimeToDateMini(time_t unixtime) } } +std::vector format::VideoBufferToPPM(const VideoBuffer & vidBuf) +{ + std::vector data; + char buffer[256]; + sprintf(buffer, "P6\n%d %d\n255\n", vidBuf.Width, vidBuf.Height); + data.insert(data.end(), buffer, buffer+strlen(buffer)); + + unsigned char * currentRow = new unsigned char[vidBuf.Width*3]; + for(int y = 0; y < vidBuf.Height; y++) + { + int rowPos = 0; + for(int x = 0; x < vidBuf.Width; x++) + { + currentRow[rowPos++] = PIXR(vidBuf.Buffer[(y*vidBuf.Width)+x]); + currentRow[rowPos++] = PIXG(vidBuf.Buffer[(y*vidBuf.Width)+x]); + currentRow[rowPos++] = PIXB(vidBuf.Buffer[(y*vidBuf.Width)+x]); + } + data.insert(data.end(), currentRow, currentRow+(vidBuf.Width*3)); + } + delete currentRow; + + return data; +} + struct PNGChunk { int Length; diff --git a/src/Format.h b/src/Format.h index 532f952a4..91f2a7ef0 100644 --- a/src/Format.h +++ b/src/Format.h @@ -24,5 +24,6 @@ namespace format std::string UnixtimeToDate(time_t unixtime, std::string dateFomat = "%d %b %Y"); std::string UnixtimeToDateMini(time_t unixtime); std::vector VideoBufferToPNG(const VideoBuffer & vidBuf); + std::vector VideoBufferToPPM(const VideoBuffer & vidBuf); unsigned long CalculateCRC(unsigned char * data, int length); } \ No newline at end of file diff --git a/src/game/GameController.h b/src/game/GameController.h index 625ab60f3..ea24bb207 100644 --- a/src/game/GameController.h +++ b/src/game/GameController.h @@ -31,6 +31,7 @@ class GameController: public ClientListener { private: //Simulation * sim; + int screenshotIndex; PreviewController * activePreview; GameView * gameView; GameModel * gameModel; diff --git a/src/game/GameView.cpp b/src/game/GameView.cpp index 5b6629b36..f743d5a4e 100644 --- a/src/game/GameView.cpp +++ b/src/game/GameView.cpp @@ -175,7 +175,11 @@ GameView::GameView(): showDebug(false), introText(2048), introTextMessage(introTextData), - wallBrush(false) + wallBrush(false), + doScreenshot(false), + recording(false), + screenshotIndex(0), + recordingIndex(0) { int currentX = 1; @@ -927,6 +931,35 @@ void GameView::NotifyBrushChanged(GameModel * sender) activeBrush = sender->GetBrush(); } +void GameView::screenshot() +{ + doScreenshot = true; +} + +void GameView::record() +{ + if(recording) + { + recording = false; + } + else + { + class RecordingConfirmation: public ConfirmDialogueCallback { + public: + GameView * v; + RecordingConfirmation(GameView * v): v(v) {} + virtual void ConfirmCallback(ConfirmPrompt::DialogueResult result) { + if (result == ConfirmPrompt::ResultOkay) + { + v->recording = true; + } + } + virtual ~RecordingConfirmation() { } + }; + new ConfirmPrompt("Recording", "You're about to start recording all drawn frames. This may use a load of hard disk space.", new RecordingConfirmation(this)); + } +} + void GameView::setToolButtonOffset(int offset) { int offset_ = offset; @@ -1246,6 +1279,12 @@ void GameView::OnKeyPress(int key, Uint16 character, bool shift, bool ctrl, bool case '`': c->ShowConsole(); break; + case 'p': + screenshot(); + break; + case 'r': + record(); + break; case 'e': c->OpenElementSearch(); break; @@ -1782,6 +1821,22 @@ void GameView::OnDraw() } ren->RenderEnd(); + if(doScreenshot) + { + VideoBuffer screenshot(ren->DumpFrame()); + std::vector data = format::VideoBufferToPNG(screenshot); + Client::Ref().WriteFile(data, "screenshot_" + format::NumberToString(screenshotIndex++) + ".png"); + doScreenshot = false; + } + + if(recording) + { + VideoBuffer screenshot(ren->DumpFrame()); + std::vector data = format::VideoBufferToPPM(screenshot); + Client::Ref().WriteFile(data, "frame_" + format::NumberToString(recordingIndex++) + ".ppm"); + } + + if(selectMode!=SelectNone) { if(selectMode==PlaceSave) @@ -1856,7 +1911,17 @@ void GameView::OnDraw() } } - if(showHud && !introText) + if(recording) + { + std::stringstream sampleInfo; + sampleInfo << recordingIndex; + sampleInfo << ". \x8E REC"; + + int textWidth = Graphics::textwidth((char*)sampleInfo.str().c_str()); + g->fillrect(XRES-20-textWidth, 12, textWidth+8, 15, 0, 0, 0, 255*0.5); + g->drawtext(XRES-16-textWidth, 16, (const char*)sampleInfo.str().c_str(), 255, 50, 20, 255); + } + else if(showHud && !introText) { //Draw info about simulation under cursor int wavelengthGfx = 0; diff --git a/src/game/GameView.h b/src/game/GameView.h index 71a6e9314..c449ba256 100644 --- a/src/game/GameView.h +++ b/src/game/GameView.h @@ -35,6 +35,12 @@ class GameView: public ui::Window { private: DrawMode drawMode; + + bool doScreenshot; + bool recording; + int screenshotIndex; + int recordingIndex; + bool isMouseDown; bool zoomEnabled; bool zoomCursorFixed; @@ -114,6 +120,9 @@ private: virtual ui::Point lineSnapCoords(ui::Point point1, ui::Point point2); virtual ui::Point rectSnapCoords(ui::Point point1, ui::Point point2); + void screenshot(); + void record(); + void enableShiftBehaviour(); void disableShiftBehaviour(); void enableCtrlBehaviour();