World of Might and Magic  0.2.0
Open reimplementation of Might and Magic 6 7 8 game engine
PCX.cpp
См. документацию.
1 #include "Engine/Graphics/PCX.h"
2 
3 #include <cstdint>
4 #include <cstdlib>
5 #include <cstring>
6 
7 #pragma pack(push, 1)
8 struct PCXHeader {
27 };
28 #pragma pack(pop)
29 
30 bool PCX::IsValid(const void *pcx_data) {
31  PCXHeader *header = (PCXHeader *)pcx_data;
32  return (header->bpp == 8) && (header->planes == 3);
33 }
34 
35 void PCX::GetSize(const void *pcx_data, unsigned int *width, unsigned int *height) {
36  PCXHeader *header = (PCXHeader *)pcx_data;
37  *width = header->right - header->left + 1;
38  *height = header->bottom - header->up + 1;
39 }
40 
41 bool PCX::Decode(const void *pcx_data, uint16_t *pOutPixels,
42  unsigned int *width, unsigned int *height) {
43  PCXHeader *header = (PCXHeader *)pcx_data;
44 
45  if (!IsValid(pcx_data)) {
46  return false;
47  }
48 
49  GetSize(pcx_data, width, height);
50 
51  memset(pOutPixels, 0, *width * *height * sizeof(int16_t));
52 
53  unsigned int r_mask = 0xF800;
54  unsigned int num_r_bits = 5;
55  unsigned int g_mask = 0x07E0;
56  unsigned int num_g_bits = 6;
57  unsigned int b_mask = 0x001F;
58  unsigned int num_b_bits = 5;
59 
60  unsigned char test_byte; // edx@3
61  unsigned int row_position; // edi@40
62  unsigned char value; // cl@63
63  char count; // [sp+50h] [bp-Ch]@43
64  unsigned short *dec_position;
65  unsigned short *temp_dec_position;
66 
67  uint8_t *input = (uint8_t*)pcx_data;
68 
69  // При сохранении изображения подряд идущие пиксели одинакового цвета
70  // объединяются и вместо указания цвета для каждого пикселя указывается цвет
71  // группы пикселей и их количество.
72  unsigned int read_offset = sizeof(PCXHeader);
73  unsigned short current_line = 0;
74  if (*height > 0) {
75  dec_position = pOutPixels;
76  do {
77  temp_dec_position = dec_position;
78  row_position = 0;
79  // decode red line
80  if (header->pitch) {
81  do {
82  test_byte = input[read_offset];
83  ++read_offset;
84  if ((test_byte & 0xC0) == 0xC0) { // имеется ли объединение
85  value = input[read_offset];
86  ++read_offset;
87 
88  if ((test_byte & 0x3F) > 0) {
89  count = test_byte &
90  0x3F; // количество одинаковых пикселей
91  do {
92  ++row_position;
93  *temp_dec_position |=
94  r_mask & ((uint8_t)value
95  << (num_g_bits + num_r_bits +
96  num_b_bits - 8));
97  temp_dec_position++;
98  if (row_position == header->pitch) break;
99  } while (count-- != 1);
100  }
101  } else {
102  ++row_position;
103  *temp_dec_position |=
104  r_mask &
105  ((uint8_t)test_byte
106  << (num_g_bits + num_r_bits + num_b_bits - 8));
107  temp_dec_position++;
108  }
109  } while (row_position < header->pitch);
110  }
111 
112  temp_dec_position = dec_position;
113  row_position = 0;
114  // decode green line
115  while (row_position < header->pitch) {
116  test_byte = *(input + read_offset);
117  ++read_offset;
118  if ((test_byte & 0xC0) == 0xC0) {
119  value = *(input + read_offset);
120  ++read_offset;
121  if ((test_byte & 0x3F) > 0) {
122  count = test_byte & 0x3F;
123  do {
124  *temp_dec_position |=
125  g_mask &
127  << (num_g_bits + num_b_bits - 8));
128 
129  temp_dec_position++;
130  ++row_position;
131  if (row_position == header->pitch) break;
132  } while (count-- != 1);
133  }
134  } else {
135  *temp_dec_position |=
136  g_mask & (uint16_t)((uint8_t)test_byte
137  << (num_g_bits + num_b_bits - 8));
138  temp_dec_position++;
139  ++row_position;
140  }
141  }
142 
143  temp_dec_position = dec_position;
144  row_position = 0;
145  // decode blue line
146  while (row_position < header->pitch) {
147  test_byte = *(input + read_offset);
148  read_offset++;
149  if ((test_byte & 0xC0) == 0xC0) {
150  value = *(input + read_offset);
151  ++read_offset;
152  if ((test_byte & 0x3F) > 0) {
153  count = test_byte & 0x3F;
154  do {
155  *temp_dec_position |= value >> (8 - num_b_bits);
156  temp_dec_position++;
157 
158  ++row_position;
159  if (row_position == header->pitch) break;
160  } while (count-- != 1);
161  }
162  } else {
163  *temp_dec_position |= test_byte >> (8 - num_b_bits);
164  temp_dec_position++;
165  ++row_position;
166  }
167  }
168  ++current_line;
169  dec_position += *width;
170  } while (current_line < *height);
171  }
172 
173  return true;
174 }
175 
176 void *WritePCXHeader(void *pcx_data, int width, int height) {
177  int pitch = width;
178  if (width & 1) {
179  pitch = width + 1;
180  }
181 
182  PCXHeader *header = (PCXHeader *)pcx_data;
183  memset(header, 0, sizeof(PCXHeader));
184  header->left = 0;
185  header->up = 0;
186  header->right = width - 1;
187  header->bottom = height - 1;
188  header->pitch = pitch;
189  header->manufacturer = 10;
190  header->version = 5;
191  header->encoding = 1;
192  header->bpp = 8;
193  header->hdpi = 75;
194  header->vdpi = 75;
195  header->planes = 3;
196  header->palette_info = 1;
197 
198  return (uint8_t *)pcx_data + sizeof(PCXHeader);
199 }
200 
201 void *EncodeOneLine(void *pcx_data, void *line, size_t line_size) {
202  uint8_t *input = (uint8_t *)line;
203  uint8_t *output = (uint8_t *)pcx_data;
204 
205  for (int i = 0; i < line_size; i++) {
206  uint8_t value = *input++;
207  uint8_t count = 1;
208  while ((count < 63) && (i < (line_size - 1)) && (input[1] == value)) {
209  input++;
210  count++;
211  i++;
212  }
213  if ((count > 1) || ((value & 0xC0) != 0)) {
214  *output++ = 0xC0 + count;
215  }
216  *output++ = value;
217  }
218 
219  return output;
220 }
221 
222 struct ColorFormat {
223  explicit ColorFormat(uint32_t m);
227 };
228 
230  shift = 0;
231  for (int i = 0; i < 16; i++) {
232  if (m & 1) {
233  break;
234  }
235  shift++;
236  m >>= 1;
237  }
238  mask = m;
239  bits = 0;
240  for (int i = 0; i < 16; i++) {
241  if (!(m & 1)) {
242  break;
243  }
244  bits++;
245  m >>= 1;
246  }
247 }
248 
249 struct Format {
250  Format(size_t bpp, uint32_t rm, uint32_t gm, uint32_t bm)
251  : bytes(bpp / 8), r(rm), g(gm), b(bm) {}
252  size_t bytes;
256 };
257 
258 void Encode(Format f, const void *picture_data, unsigned int width,
259  unsigned int height, void *pcx_data, int max_buff_size,
260  unsigned int *packed_size) {
261  uint8_t *output = (uint8_t *)WritePCXHeader(pcx_data, width, height);
262 
263  int pitch = width;
264  if (width & 1) {
265  pitch = width + 1;
266  }
267 
268  uint8_t *lineRGB = new uint8_t[3 * pitch];
269  uint8_t *lineR = (uint8_t *)lineRGB;
270  uint8_t *lineG = (uint8_t *)lineRGB + pitch;
271  uint8_t *lineB = (uint8_t *)lineRGB + 2 * pitch;
272  uint8_t *input = (uint8_t *)picture_data;
273 
274  for (int y = 0; y < height; y++) {
275  for (unsigned int x = 0; x < width; x++) {
276  uint32_t pixel;
277  memcpy(&pixel, input, f.bytes);
278  input += f.bytes;
279  lineR[x] = ((pixel >> f.r.shift) & f.r.mask) << (8 - f.r.bits);
280  lineG[x] = ((pixel >> f.g.shift) & f.g.mask) << (8 - f.g.bits);
281  lineB[x] = ((pixel >> f.b.shift) & f.b.mask) << (8 - f.b.bits);
282  }
283  uint8_t *line = lineRGB;
284  for (int p = 0; p < 3; p++) {
285  output = (uint8_t *)EncodeOneLine(output, line, pitch);
286  line += pitch;
287  }
288  }
289 
290  delete[] lineRGB;
291 
292  if (packed_size != nullptr) {
293  *packed_size = output - (uint8_t*)pcx_data;
294  }
295 }
296 
297 void PCX::Encode16(const void *picture_data, unsigned int width, unsigned int height,
298  void *pcx_data, int max_buff_size,
299  unsigned int *packed_size) {
300  Format f(16, 0xF800, 0x07E0, 0x001F);
301  Encode(f, picture_data, width, height, pcx_data, max_buff_size,
302  packed_size);
303 }
304 
305 void PCX::Encode32(const void *picture_data, unsigned int width, unsigned int height,
306  void *pcx_data, int max_buff_size,
307  unsigned int *packed_size) {
308  Format f(32, 0x00FF0000, 0x0000FF00, 0x000000FF);
309  Encode(f, picture_data, width, height, pcx_data, max_buff_size,
310  packed_size);
311 }
uint16_t
unsigned __int16 uint16_t
Definition: SDL_config.h:37
mask
GLenum GLint GLuint mask
Definition: SDL_opengl_glext.h:660
int16_t
signed __int16 int16_t
Definition: SDL_config.h:36
PCXHeader
Definition: PCX.cpp:8
PCX::Encode16
void Encode16(const void *picture_data, unsigned int width, unsigned int height, void *pcx_data, int max_buff_size, unsigned int *packed_size)
Definition: PCX.cpp:297
Format::bytes
size_t bytes
Definition: PCX.cpp:252
height
EGLSurface EGLint EGLint EGLint EGLint height
Definition: SDL_egl.h:1596
PCXHeader::left
int16_t left
Definition: PCX.cpp:13
PCX::Decode
bool Decode(const void *pcx_data, uint16_t *pOutPixels, unsigned int *width, unsigned int *height)
Definition: PCX.cpp:41
PCXHeader::palette_info
int16_t palette_info
Definition: PCX.cpp:23
count
GLuint GLuint GLsizei count
Definition: SDL_opengl.h:1571
PCXHeader::bottom
int16_t bottom
Definition: PCX.cpp:16
PCX.h
PCXHeader::color_map
int8_t color_map[48]
Definition: PCX.cpp:19
input
GLenum GLenum GLenum input
Definition: SDL_opengl_glext.h:9377
PCXHeader::up
int16_t up
Definition: PCX.cpp:14
Format::r
ColorFormat r
Definition: PCX.cpp:253
PCXHeader::pitch
int16_t pitch
Definition: PCX.cpp:22
y
EGLSurface EGLint EGLint y
Definition: SDL_egl.h:1596
ColorFormat::ColorFormat
ColorFormat(uint32_t m)
Definition: PCX.cpp:229
Format::b
ColorFormat b
Definition: PCX.cpp:255
PCXHeader::encoding
int8_t encoding
Definition: PCX.cpp:11
PCXHeader::vres
int16_t vres
Definition: PCX.cpp:25
p
GLfloat GLfloat p
Definition: SDL_opengl_glext.h:11093
PCX::Encode32
void Encode32(const void *picture_data, unsigned int width, unsigned int height, void *pcx_data, int max_buff_size, unsigned int *packed_size)
Definition: PCX.cpp:305
x
EGLSurface EGLint x
Definition: SDL_egl.h:1596
WritePCXHeader
void * WritePCXHeader(void *pcx_data, int width, int height)
Definition: PCX.cpp:176
Format::Format
Format(size_t bpp, uint32_t rm, uint32_t gm, uint32_t bm)
Definition: PCX.cpp:250
width
EGLSurface EGLint EGLint EGLint width
Definition: SDL_egl.h:1596
Format
Definition: PCX.cpp:249
PCXHeader::version
int8_t version
Definition: PCX.cpp:10
EncodeOneLine
void * EncodeOneLine(void *pcx_data, void *line, size_t line_size)
Definition: PCX.cpp:201
PCXHeader::reserved
int8_t reserved
Definition: PCX.cpp:20
f
GLfloat f
Definition: SDL_opengl_glext.h:1873
value
EGLSyncKHR EGLint EGLint * value
Definition: SDL_egl.h:899
PCX::IsValid
bool IsValid(const void *pcx_data)
Definition: PCX.cpp:30
PCXHeader::filler
int8_t filler[54]
Definition: PCX.cpp:26
ColorFormat
Definition: PCX.cpp:222
PCX::GetSize
void GetSize(const void *pcx_data, unsigned int *width, unsigned int *height)
Definition: PCX.cpp:35
uint8_t
unsigned __int8 uint8_t
Definition: SDL_config.h:35
b
GLboolean GLboolean GLboolean b
Definition: SDL_opengl_glext.h:1112
PCXHeader::hres
int16_t hres
Definition: PCX.cpp:24
r
GLdouble GLdouble GLdouble r
Definition: SDL_opengl.h:2079
ColorFormat::mask
uint32_t mask
Definition: PCX.cpp:224
m
const GLfloat * m
Definition: SDL_opengl_glext.h:6095
ColorFormat::shift
uint32_t shift
Definition: PCX.cpp:225
PCXHeader::planes
int8_t planes
Definition: PCX.cpp:21
bits
GLenum GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const void * bits
Definition: SDL_opengl_glext.h:6179
PCXHeader::hdpi
int16_t hdpi
Definition: PCX.cpp:17
PCXHeader::manufacturer
int8_t manufacturer
Definition: PCX.cpp:9
PCXHeader::bpp
int8_t bpp
Definition: PCX.cpp:12
PCXHeader::right
int16_t right
Definition: PCX.cpp:15
g
GLboolean GLboolean g
Definition: SDL_opengl_glext.h:1112
uint32_t
unsigned __int32 uint32_t
Definition: SDL_config.h:39
ColorFormat::bits
uint32_t bits
Definition: PCX.cpp:226
PCXHeader::vdpi
int16_t vdpi
Definition: PCX.cpp:18
int8_t
signed __int8 int8_t
Definition: SDL_config.h:34
Encode
void Encode(Format f, const void *picture_data, unsigned int width, unsigned int height, void *pcx_data, int max_buff_size, unsigned int *packed_size)
Definition: PCX.cpp:258
Format::g
ColorFormat g
Definition: PCX.cpp:254