Devilution
Diablo devolved - magic behind the 1996 computer game
capture.cpp
Go to the documentation of this file.
1 
6 #include <fstream>
7 
8 #include "all.h"
9 #include "../3rdParty/Storm/Source/storm.h"
10 #include "file_util.h"
11 
13 
21 static BOOL CaptureHdr(short width, short height, std::ofstream *out)
22 {
23  DWORD lpNumBytes;
24  PCXHEADER Buffer;
25 
26  memset(&Buffer, 0, sizeof(Buffer));
27  Buffer.Manufacturer = 10;
28  Buffer.Version = 5;
29  Buffer.Encoding = 1;
30  Buffer.BitsPerPixel = 8;
31  Buffer.Xmax = SDL_SwapLE16(width - 1);
32  Buffer.Ymax = SDL_SwapLE16(height - 1);
33  Buffer.HDpi = SDL_SwapLE16(width);
34  Buffer.VDpi = SDL_SwapLE16(height);
35  Buffer.NPlanes = 1;
36  Buffer.BytesPerLine = SDL_SwapLE16(width);
37 
38  out->write(reinterpret_cast<const char*>(&Buffer), sizeof(Buffer));
39  return !out->fail();
40 }
41 
42 static BOOL CapturePal(SDL_Color *palette, std::ofstream *out)
43 {
44  BYTE pcx_palette[1 + 256 * 3];
45  int i;
46 
47  pcx_palette[0] = 12;
48  for (i = 0; i < 256; i++) {
49  pcx_palette[1 + 3 * i + 0] = palette[i].r;
50  pcx_palette[1 + 3 * i + 1] = palette[i].g;
51  pcx_palette[1 + 3 * i + 2] = palette[i].b;
52  }
53 
54  out->write(reinterpret_cast<const char *>(pcx_palette), sizeof(pcx_palette));
55  return !out->fail();
56 }
57 
58 static BYTE *CaptureEnc(BYTE *src, BYTE *dst, int width)
59 {
60  int rleLength;
61 
62  do {
63  BYTE rlePixel = *src;
64  *src++;
65  rleLength = 1;
66 
67  width--;
68 
69  while (rlePixel == *src) {
70  if (rleLength >= 63)
71  break;
72  if (!width)
73  break;
74  rleLength++;
75 
76  width--;
77  src++;
78  }
79 
80  if (rleLength > 1 || rlePixel > 0xBF) {
81  *dst = rleLength | 0xC0;
82  *dst++;
83  }
84 
85  *dst = rlePixel;
86  *dst++;
87  } while (width);
88 
89  return dst;
90 }
91 
92 static bool CapturePix(WORD width, WORD height, WORD stride, BYTE *pixels, std::ofstream *out)
93 {
94  int writeSize;
95  DWORD lpNumBytes;
96  BYTE *pBuffer, *pBufferEnd;
97 
98  pBuffer = (BYTE *)DiabloAllocPtr(2 * width);
99  while (height--) {
100  pBufferEnd = CaptureEnc(pixels, pBuffer, width);
101  pixels += stride;
102  writeSize = pBufferEnd - pBuffer;
103  out->write(reinterpret_cast<const char *>(pBuffer), writeSize);
104  if (out->fail()) return false;
105  }
106  mem_free_dbg(pBuffer);
107  return true;
108 }
109 
113 static std::ofstream *CaptureFile(char *dst_path)
114 {
115  char path[MAX_PATH];
116 
117  GetPrefPath(path, MAX_PATH);
118 
119  for (int i = 0; i <= 99; i++) {
120  snprintf(dst_path, MAX_PATH, "%sscreen%02d.PCX", path, i);
121  if (!FileExists(dst_path))
122  return new std::ofstream(dst_path, std::ios::binary | std::ios::trunc);
123  }
124 
125  return nullptr;
126 }
127 
131 static void RedPalette()
132 {
133  for (int i = 0; i < 255; i++) {
134  system_palette[i].g = 0;
135  system_palette[i].b = 0;
136  }
137  palette_update();
138  SDL_Rect SrcRect = {
139  SCREEN_X,
140  SCREEN_Y,
141  SCREEN_WIDTH,
143  };
144  BltFast(&SrcRect, NULL);
145  RenderPresent();
146 }
147 
149 {
150  SDL_Color palette[256];
151  char FileName[MAX_PATH];
152  BOOL success;
153 
154  std::ofstream *out = CaptureFile(FileName);
155  if (out == nullptr) return;
156  DrawAndBlit();
157  PaletteGetEntries(256, palette);
158  RedPalette();
159 
160  lock_buf(2);
161  success = CaptureHdr(SCREEN_WIDTH, SCREEN_HEIGHT, out);
162  if (success) {
164  }
165  if (success) {
166  success = CapturePal(palette, out);
167  }
168  unlock_buf(2);
169  out->close();
170 
171  if (!success) {
172  SDL_Log("Failed to save screenshot at %s", FileName);
173  RemoveFile(FileName);
174  } else {
175  SDL_Log("Screenshot saved at %s", FileName);
176  }
177  SDL_Delay(300);
178  for (int i = 0; i < 255; i++) {
179  system_palette[i] = palette[i];
180  }
181  palette_update();
182  force_redraw = 255;
183  delete out;
184 }
185 
gpBuffer
BYTE * gpBuffer
system_palette
SDL_Color system_palette[256]
Definition: palette.cpp:8
SCREENXY
#define SCREENXY(x, y)
Definition: defs.h:155
force_redraw
int force_redraw
Definition: diablo.cpp:30
_PcxHeader::BitsPerPixel
BYTE BitsPerPixel
Definition: structs.h:1560
SCREEN_Y
#define SCREEN_Y
Definition: defs.h:126
CaptureFile
static std::ofstream * CaptureFile(char *dst_path)
Returns a pointer because in GCC < 5 ofstream itself is not moveable due to a bug.
Definition: capture.cpp:113
RenderPresent
void RenderPresent()
CaptureScreen
void CaptureScreen()
Definition: capture.cpp:148
_PcxHeader::Manufacturer
BYTE Manufacturer
Definition: structs.h:1557
CapturePix
static bool CapturePix(WORD width, WORD height, WORD stride, BYTE *pixels, std::ofstream *out)
Definition: capture.cpp:92
CapturePal
static BOOL CapturePal(SDL_Color *palette, std::ofstream *out)
Definition: capture.cpp:42
all.h
_PcxHeader::Ymax
WORD Ymax
Definition: structs.h:1564
BltFast
void BltFast(SDL_Rect *src_rect, SDL_Rect *dst_rect)
DrawAndBlit
void DrawAndBlit()
Render the game.
Definition: scrollrt.cpp:1333
SCREEN_WIDTH
#define SCREEN_WIDTH
Definition: defs.h:105
palette_update
void palette_update()
Definition: palette.cpp:17
_PcxHeader::VDpi
WORD VDpi
Definition: structs.h:1566
_PcxHeader::BytesPerLine
WORD BytesPerLine
Definition: structs.h:1570
DEVILUTION_END_NAMESPACE
#define DEVILUTION_END_NAMESPACE
Definition: types.h:10
lock_buf
void lock_buf(BYTE idx)
RedPalette
static void RedPalette()
remove green and blue from the current palette
Definition: capture.cpp:131
_PcxHeader::NPlanes
BYTE NPlanes
Definition: structs.h:1569
unlock_buf
void unlock_buf(BYTE idx)
_PcxHeader
Definition: structs.h:1556
CaptureEnc
static BYTE * CaptureEnc(BYTE *src, BYTE *dst, int width)
Definition: capture.cpp:58
_PcxHeader::Xmax
WORD Xmax
Definition: structs.h:1563
_PcxHeader::HDpi
WORD HDpi
Definition: structs.h:1565
DiabloAllocPtr
BYTE * DiabloAllocPtr(DWORD dwBytes)
Multithreaded safe malloc.
Definition: engine.cpp:765
CaptureHdr
static DEVILUTION_BEGIN_NAMESPACE BOOL CaptureHdr(short width, short height, std::ofstream *out)
Write the PCX-file header.
Definition: capture.cpp:21
PaletteGetEntries
void PaletteGetEntries(DWORD dwNumEntries, SDL_Color *lpEntries)
mem_free_dbg
void mem_free_dbg(void *p)
Multithreaded safe memfree.
Definition: engine.cpp:786
BUFFER_WIDTH
#define BUFFER_WIDTH
Definition: defs.h:128
DEVILUTION_BEGIN_NAMESPACE
Definition: sha.cpp:10
SCREEN_X
#define SCREEN_X
Definition: defs.h:125
_PcxHeader::Version
BYTE Version
Definition: structs.h:1558
SCREEN_HEIGHT
#define SCREEN_HEIGHT
Definition: defs.h:106
_PcxHeader::Encoding
BYTE Encoding
Definition: structs.h:1559