-
Notifications
You must be signed in to change notification settings - Fork 814
/
Copy pathcapture.cpp
116 lines (103 loc) · 3.04 KB
/
capture.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
/**
* @file capture.cpp
*
* Implementation of the screenshot function.
*/
#include <cerrno>
#include <cstdint>
#include <cstdio>
#include <cstring>
#include <ctime>
#include <SDL.h>
#include <expected.hpp>
#include <fmt/format.h>
#define DEVILUTIONX_SCREENSHOT_FORMAT_PCX 0
#define DEVILUTIONX_SCREENSHOT_FORMAT_PNG 1
#if DEVILUTIONX_SCREENSHOT_FORMAT == DEVILUTIONX_SCREENSHOT_FORMAT_PCX
#include "utils/surface_to_pcx.hpp"
#endif
#if DEVILUTIONX_SCREENSHOT_FORMAT == DEVILUTIONX_SCREENSHOT_FORMAT_PNG
#include "utils/surface_to_png.hpp"
#endif
#include "engine/backbuffer_state.hpp"
#include "engine/dx.h"
#include "engine/palette.h"
#include "utils/file_util.h"
#include "utils/log.hpp"
#include "utils/paths.h"
#include "utils/str_cat.hpp"
namespace devilution {
namespace {
SDL_RWops *CaptureFile(std::string *dstPath)
{
const char *ext =
#if DEVILUTIONX_SCREENSHOT_FORMAT == DEVILUTIONX_SCREENSHOT_FORMAT_PCX
".pcx";
#elif DEVILUTIONX_SCREENSHOT_FORMAT == DEVILUTIONX_SCREENSHOT_FORMAT_PNG
".png";
#endif
const std::time_t tt = std::time(nullptr);
const std::tm *tm = std::localtime(&tt);
const std::string filename = tm != nullptr
? fmt::format("Screenshot from {:04}-{:02}-{:02} {:02}-{:02}-{:02}",
tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec)
: "Screenshot";
*dstPath = StrCat(paths::PrefPath(), filename, ext);
int i = 0;
while (FileExists(dstPath->c_str())) {
i++;
*dstPath = StrCat(paths::PrefPath(), filename, "-", i, ext);
}
return SDL_RWFromFile(dstPath->c_str(), "wb");
}
/**
* @brief Make a red version of the given palette and apply it to the screen.
*/
void RedPalette()
{
for (int i = 0; i < 256; i++) {
system_palette[i].g = 0;
system_palette[i].b = 0;
}
palette_update();
BltFast(nullptr, nullptr);
RenderPresent();
}
} // namespace
void CaptureScreen()
{
SDL_Color palette[256];
std::string fileName;
const uint32_t startTime = SDL_GetTicks();
SDL_RWops *outStream = CaptureFile(&fileName);
if (outStream == nullptr) {
LogError("Failed to open {} for writing: {}", fileName, SDL_GetError());
SDL_ClearError();
return;
}
DrawAndBlit();
PaletteGetEntries(256, palette);
RedPalette();
for (int i = 0; i < 256; i++) {
system_palette[i] = palette[i];
}
palette_update();
const tl::expected<void, std::string> result =
#if DEVILUTIONX_SCREENSHOT_FORMAT == DEVILUTIONX_SCREENSHOT_FORMAT_PCX
WriteSurfaceToFilePcx(GlobalBackBuffer(), outStream);
#elif DEVILUTIONX_SCREENSHOT_FORMAT == DEVILUTIONX_SCREENSHOT_FORMAT_PNG
WriteSurfaceToFilePng(GlobalBackBuffer(), outStream);
#endif
if (!result.has_value()) {
LogError("Failed to save screenshot at {}: ", fileName, result.error());
RemoveFile(fileName.c_str());
} else {
Log("Screenshot saved at {}", fileName);
}
const uint32_t timePassed = SDL_GetTicks() - startTime;
if (timePassed < 300) {
SDL_Delay(300 - timePassed);
}
RedrawEverything();
}
} // namespace devilution