71 lines
2.0 KiB
C++
71 lines
2.0 KiB
C++
|
|
||
|
#include "screenshot.h"
|
||
|
#include "file.h"
|
||
|
|
||
|
static void TO_LE16(uint8_t *dst, uint16_t value) {
|
||
|
for (int i = 0; i < 2; ++i) {
|
||
|
dst[i] = value & 255;
|
||
|
value >>= 8;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#define kTgaImageTypeUncompressedTrueColor 2
|
||
|
#define kTgaImageTypeRunLengthEncodedTrueColor 10
|
||
|
#define kTgaDirectionTop (1 << 5)
|
||
|
|
||
|
static const int TGA_HEADER_SIZE = 18;
|
||
|
|
||
|
void saveTGA(const char *filename, const uint8_t *rgba, int w, int h) {
|
||
|
|
||
|
static const uint8_t kImageType = kTgaImageTypeRunLengthEncodedTrueColor;
|
||
|
uint8_t buffer[TGA_HEADER_SIZE];
|
||
|
buffer[0] = 0; // ID Length
|
||
|
buffer[1] = 0; // ColorMap Type
|
||
|
buffer[2] = kImageType;
|
||
|
TO_LE16(buffer + 3, 0); // ColorMap Start
|
||
|
TO_LE16(buffer + 5, 0); // ColorMap Length
|
||
|
buffer[7] = 0; // ColorMap Bits
|
||
|
TO_LE16(buffer + 8, 0); // X-origin
|
||
|
TO_LE16(buffer + 10, 0); // Y-origin
|
||
|
TO_LE16(buffer + 12, w); // Image Width
|
||
|
TO_LE16(buffer + 14, h); // Image Height
|
||
|
buffer[16] = 24; // Pixel Depth
|
||
|
buffer[17] = kTgaDirectionTop; // Descriptor
|
||
|
|
||
|
File f;
|
||
|
if (f.open(filename, "wb", ".")) {
|
||
|
f.write(buffer, sizeof(buffer));
|
||
|
if (kImageType == kTgaImageTypeUncompressedTrueColor) {
|
||
|
for (int i = 0; i < w * h; ++i) {
|
||
|
f.writeByte(rgba[0]);
|
||
|
f.writeByte(rgba[1]);
|
||
|
f.writeByte(rgba[2]);
|
||
|
rgba += 4;
|
||
|
}
|
||
|
} else {
|
||
|
assert(kImageType == kTgaImageTypeRunLengthEncodedTrueColor);
|
||
|
int prevColor = rgba[2] + (rgba[1] << 8) + (rgba[0] << 16); rgba += 4;
|
||
|
int count = 0;
|
||
|
for (int i = 1; i < w * h; ++i) {
|
||
|
int color = rgba[2] + (rgba[1] << 8) + (rgba[0] << 16); rgba += 4;
|
||
|
if (prevColor == color && count < 127) {
|
||
|
++count;
|
||
|
continue;
|
||
|
}
|
||
|
f.writeByte(count | 0x80);
|
||
|
f.writeByte((prevColor >> 16) & 255);
|
||
|
f.writeByte((prevColor >> 8) & 255);
|
||
|
f.writeByte( prevColor & 255);
|
||
|
count = 0;
|
||
|
prevColor = color;
|
||
|
}
|
||
|
if (count != 0) {
|
||
|
f.writeByte(count | 0x80);
|
||
|
f.writeByte((prevColor >> 16) & 255);
|
||
|
f.writeByte((prevColor >> 8) & 255);
|
||
|
f.writeByte( prevColor & 255);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|