2
Copyright (c) 2012 Andrew Caudwell (acaudwell@gmail.com)
5
Redistribution and use in source and binary forms, with or without
6
modification, are permitted provided that the following conditions
8
1. Redistributions of source code must retain the above copyright
9
notice, this list of conditions and the following disclaimer.
10
2. Redistributions in binary form must reproduce the above copyright
11
notice, this list of conditions and the following disclaimer in the
12
documentation and/or other materials provided with the distribution.
13
3. The name of the author may not be used to endorse or promote products
14
derived from this software without specific prior written permission.
16
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33
TGAWriter::TGAWriter(int components)
34
: components(components) {
42
void TGAWriter::writeRLE(int pixel_count, const char* pixel) {
44
rle_count += pixel_count;
46
while(pixel_count > 0) {
47
int write_count = std::min(128, pixel_count);
49
unsigned char counter_byte = (write_count-1) | 0x80;
50
out->write((char*)&counter_byte, 1);
51
out->write(pixel, components);
53
pixel_count -= write_count;
57
void TGAWriter::writeRaw(std::vector<char>& buffer, int start, int pixel_count) {
59
raw_count += pixel_count;
63
while(pixel_count > 0) {
64
int write_count = std::min(128, pixel_count);
66
char counter_byte = write_count-1;
68
out->write((char*)&counter_byte, 1);
70
for(int i=0; i < write_count; i++) {
71
out->write(&(buffer[start+(i+written)*components]), components);
74
pixel_count -= write_count;
75
written += write_count;
79
bool TGAWriter::open(const std::string& filename) {
81
out = new std::ofstream(filename.c_str(), std::ios::out | std::ios::binary);
92
void TGAWriter::close() {
93
((std::fstream*)out)->close();
96
void TGAWriter::setOutputStream(std::ostream* out) {
100
void TGAWriter::screenshot(const std::string& filename) {
102
if(!open(filename)) return;
104
std::vector<char> buffer;
105
buffer.resize(display.width * display.height * components);
113
void TGAWriter::writeHeader() {
115
char image_type = rle ? 10 : 2;
117
const char tga_header[12] = { 0, 0, image_type, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
118
short width = display.width;
119
short height = display.height;
120
char imagedescriptor = components==4 ? 8 : 0;
122
char bpp = components * 8;
124
out->write(tga_header, 12);
125
out->write((char*)&width, sizeof(short));
126
out->write((char*)&height, sizeof(short));
128
out->write(&imagedescriptor, 1);
131
void TGAWriter::capture(std::vector<char>& buffer) {
132
GLenum pixel_format = components == 4 ? GL_BGRA : GL_BGR;
133
glReadPixels(0, 0, display.width, display.height, pixel_format, GL_UNSIGNED_BYTE, &(buffer[0]));
136
void TGAWriter::writeTGA(std::vector<char>& buffer) {
138
writeScanlines(buffer, display.width, display.height);
141
void TGAWriter::writeScanlines(std::vector<char>& buffer, int width, int height) {
144
out->write(&(buffer[0]), buffer.size());
147
for(int y=0; y<height; y++) {
150
int last_written = -1;
154
for(int x=0; x<width; x++) {
156
char* pixel = &(buffer[(x + y*width)*components]);
158
// nothing to compare to
166
(pixel[0] == last_pixel[0] && pixel[1] == last_pixel[1] && pixel[2] == last_pixel[2] && pixel[3] == last_pixel[3])
167
: (pixel[0] == last_pixel[0] && pixel[1] == last_pixel[1] && pixel[2] == last_pixel[2]);
173
// write any skipped pixels before the previous pixel
174
if(match_count > 0) {
176
int skipped = (x-(match_count)) - (last_written+1);
179
writeRaw(buffer, (last_written + 1 + y*width)*components, skipped);
184
} else if(match_count > 0) {
186
writeRLE(match_count+1, last_pixel);
195
if(match_count > 0) {
197
writeRLE(match_count+1, last_pixel);
201
int skipped = width - (last_written+1);
204
writeRaw(buffer, (last_written + 1 + y*width)*components, skipped);
213
TGAExporter::TGAExporter(const std::string& filename) {
215
buffer1.resize(display.width * display.height * 3);
216
buffer2.resize(display.width * display.height * 3);
218
buffer_shared_ptr = 0;
220
thread_state = TGA_EXPORTER_WAIT;
222
cond = SDL_CreateCond();
223
mutex = SDL_CreateMutex();
225
if(filename == "-") {
226
writer.setOutputStream(&std::cout);
228
this->filename = filename;
230
if(!writer.open(filename)) {
231
throw TGAExporterException(filename);
235
#if SDL_VERSION_ATLEAST(1,3,0)
236
thread = SDL_CreateThread( TGAExporter::startThread, "tga_exporter", this );
238
thread = SDL_CreateThread( TGAExporter::startThread, this );
242
TGAExporter::~TGAExporter() {
246
SDL_KillThread(thread);
247
SDL_DestroyCond(cond);
248
SDL_DestroyMutex(mutex);
250
buffer_shared_ptr = 0;
252
if(!filename.empty()) {
257
int TGAExporter::startThread(void *exporter) {
258
(static_cast<TGAExporter*>(exporter))->run();
262
void TGAExporter::run() {
266
while(thread_state != TGA_EXPORTER_EXIT) {
268
thread_state = TGA_EXPORTER_WAIT;
270
while (thread_state == TGA_EXPORTER_WAIT) {
271
SDL_CondWait(cond, mutex);
274
if (thread_state != TGA_EXPORTER_WRITE) break;
276
if (buffer_shared_ptr != 0) {
277
writer.writeTGA(*buffer_shared_ptr);
281
thread_state = TGA_EXPORTER_STOPPED;
286
void TGAExporter::stop() {
288
if(thread_state == TGA_EXPORTER_STOPPED || thread_state == TGA_EXPORTER_EXIT) return;
292
thread_state = TGA_EXPORTER_EXIT;
294
SDL_CondSignal(cond);
298
while(thread_state != TGA_EXPORTER_STOPPED)
302
void TGAExporter::capture() {
304
std::vector<char>* next_pixel_ptr = (buffer_shared_ptr == &buffer1) ?
307
writer.capture(*next_pixel_ptr);
311
buffer_shared_ptr = next_pixel_ptr;
312
thread_state = TGA_EXPORTER_WRITE;
314
SDL_CondSignal(cond);