~ubuntu-branches/debian/stretch/gource/stretch

« back to all changes in this revision

Viewing changes to src/core/tga.cpp

  • Committer: Package Import Robot
  • Author(s): Andrew Caudwell
  • Date: 2013-05-13 09:58:33 UTC
  • mfrom: (1.2.14)
  • Revision ID: package-import@ubuntu.com-20130513095833-1r8t89oflvhqxwny
Tags: 0.40-1
* New upstream release.
* Added dpkg-buildflags.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
    Copyright (c) 2012 Andrew Caudwell (acaudwell@gmail.com)
 
3
    All rights reserved.
 
4
 
 
5
    Redistribution and use in source and binary forms, with or without
 
6
    modification, are permitted provided that the following conditions
 
7
    are met:
 
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.
 
15
 
 
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.
 
26
*/
 
27
 
 
28
#include "tga.h"
 
29
#include "display.h"
 
30
 
 
31
#include <iostream>
 
32
 
 
33
TGAWriter::TGAWriter(int components)
 
34
    : components(components) {
 
35
    rle = true;
 
36
    out = 0;
 
37
 
 
38
    rle_count = 0;
 
39
    raw_count = 0;
 
40
}
 
41
 
 
42
void TGAWriter::writeRLE(int pixel_count, const char* pixel) {
 
43
 
 
44
    rle_count += pixel_count;
 
45
 
 
46
    while(pixel_count > 0) {
 
47
        int write_count = std::min(128, pixel_count);
 
48
 
 
49
        unsigned char counter_byte = (write_count-1) | 0x80;
 
50
        out->write((char*)&counter_byte, 1);
 
51
        out->write(pixel, components);
 
52
 
 
53
        pixel_count -= write_count;
 
54
    }
 
55
}
 
56
 
 
57
void TGAWriter::writeRaw(std::vector<char>& buffer, int start, int pixel_count) {
 
58
 
 
59
    raw_count += pixel_count;
 
60
 
 
61
    int written = 0;
 
62
 
 
63
    while(pixel_count > 0) {
 
64
        int write_count = std::min(128, pixel_count);
 
65
 
 
66
        char counter_byte = write_count-1;
 
67
 
 
68
        out->write((char*)&counter_byte, 1);
 
69
 
 
70
        for(int i=0; i < write_count; i++) {
 
71
            out->write(&(buffer[start+(i+written)*components]), components);
 
72
        }
 
73
 
 
74
        pixel_count -= write_count;
 
75
        written += write_count;
 
76
    }
 
77
}
 
78
 
 
79
bool TGAWriter::open(const std::string& filename) {
 
80
 
 
81
    out = new std::ofstream(filename.c_str(), std::ios::out | std::ios::binary);
 
82
 
 
83
    if(out->fail()) {
 
84
        delete out;
 
85
        out = 0;
 
86
        return false;
 
87
    }
 
88
 
 
89
    return true;
 
90
}
 
91
 
 
92
void TGAWriter::close() {
 
93
    ((std::fstream*)out)->close();
 
94
}
 
95
 
 
96
void TGAWriter::setOutputStream(std::ostream* out) {
 
97
    this->out = out;
 
98
}
 
99
 
 
100
void TGAWriter::screenshot(const std::string& filename) {
 
101
 
 
102
    if(!open(filename)) return;
 
103
 
 
104
    std::vector<char> buffer;
 
105
    buffer.resize(display.width * display.height * components);
 
106
 
 
107
    capture(buffer);
 
108
    writeTGA(buffer);
 
109
 
 
110
    close();
 
111
}
 
112
 
 
113
void TGAWriter::writeHeader() {
 
114
 
 
115
    char image_type = rle ? 10 : 2;
 
116
 
 
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;
 
121
 
 
122
    char bpp = components * 8;
 
123
 
 
124
    out->write(tga_header, 12);
 
125
    out->write((char*)&width,  sizeof(short));
 
126
    out->write((char*)&height, sizeof(short));
 
127
    out->write(&bpp, 1);
 
128
    out->write(&imagedescriptor, 1);
 
129
}
 
130
 
 
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]));
 
134
}
 
135
 
 
136
void TGAWriter::writeTGA(std::vector<char>& buffer) {
 
137
    writeHeader();
 
138
    writeScanlines(buffer, display.width, display.height);
 
139
}
 
140
 
 
141
void TGAWriter::writeScanlines(std::vector<char>& buffer, int width, int height) {
 
142
 
 
143
    if(!rle) {
 
144
        out->write(&(buffer[0]), buffer.size());
 
145
    } else {
 
146
 
 
147
        for(int y=0; y<height; y++) {
 
148
 
 
149
            int match_count  = 0;
 
150
            int last_written = -1;
 
151
 
 
152
            char* last_pixel;
 
153
 
 
154
            for(int x=0; x<width; x++) {
 
155
 
 
156
                char* pixel = &(buffer[(x + y*width)*components]);
 
157
 
 
158
                // nothing to compare to
 
159
                if(x == 0) {
 
160
                    last_pixel = pixel;
 
161
                    continue;
 
162
                }
 
163
 
 
164
                bool match =
 
165
                    (components == 4) ?
 
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]);
 
168
 
 
169
                if(match) {
 
170
 
 
171
                    match_count++;
 
172
 
 
173
                    // write any skipped pixels before the previous pixel
 
174
                    if(match_count > 0) {
 
175
 
 
176
                        int skipped = (x-(match_count)) - (last_written+1);
 
177
 
 
178
                        if(skipped > 0) {
 
179
                            writeRaw(buffer, (last_written + 1 + y*width)*components, skipped);
 
180
                            last_written = x-1;
 
181
                        }
 
182
                    }
 
183
 
 
184
                } else if(match_count > 0) {
 
185
 
 
186
                    writeRLE(match_count+1, last_pixel);
 
187
                    last_written = x-1;
 
188
 
 
189
                    match_count = 0;
 
190
                }
 
191
 
 
192
                last_pixel = pixel;
 
193
            }
 
194
 
 
195
            if(match_count > 0) {
 
196
 
 
197
                writeRLE(match_count+1, last_pixel);
 
198
 
 
199
            } else {
 
200
 
 
201
                int skipped = width - (last_written+1);
 
202
 
 
203
                if(skipped > 0) {
 
204
                    writeRaw(buffer, (last_written + 1 + y*width)*components, skipped);
 
205
                }
 
206
            }
 
207
        }
 
208
    }
 
209
}
 
210
 
 
211
// TGAExporter
 
212
 
 
213
TGAExporter::TGAExporter(const std::string& filename) {
 
214
 
 
215
    buffer1.resize(display.width * display.height * 3);
 
216
    buffer2.resize(display.width * display.height * 3);
 
217
 
 
218
    buffer_shared_ptr = 0;
 
219
 
 
220
    thread_state = TGA_EXPORTER_WAIT;
 
221
 
 
222
    cond   = SDL_CreateCond();
 
223
    mutex  = SDL_CreateMutex();
 
224
 
 
225
    if(filename == "-") {
 
226
        writer.setOutputStream(&std::cout);
 
227
    } else {
 
228
       this->filename = filename;
 
229
 
 
230
       if(!writer.open(filename)) {
 
231
            throw TGAExporterException(filename);
 
232
        }
 
233
    }
 
234
 
 
235
#if SDL_VERSION_ATLEAST(1,3,0)
 
236
    thread = SDL_CreateThread( TGAExporter::startThread, "tga_exporter", this );
 
237
#else
 
238
    thread = SDL_CreateThread( TGAExporter::startThread, this );
 
239
#endif
 
240
}
 
241
 
 
242
TGAExporter::~TGAExporter() {
 
243
 
 
244
    stop();
 
245
 
 
246
    SDL_KillThread(thread);
 
247
    SDL_DestroyCond(cond);
 
248
    SDL_DestroyMutex(mutex);
 
249
 
 
250
    buffer_shared_ptr = 0;
 
251
 
 
252
    if(!filename.empty()) {
 
253
        writer.close();
 
254
    }
 
255
}
 
256
 
 
257
int TGAExporter::startThread(void *exporter) {
 
258
    (static_cast<TGAExporter*>(exporter))->run();
 
259
    return 0;
 
260
}
 
261
 
 
262
void TGAExporter::run() {
 
263
 
 
264
    SDL_mutexP(mutex);
 
265
 
 
266
    while(thread_state != TGA_EXPORTER_EXIT) {
 
267
 
 
268
        thread_state = TGA_EXPORTER_WAIT;
 
269
 
 
270
        while (thread_state == TGA_EXPORTER_WAIT) {
 
271
            SDL_CondWait(cond, mutex);
 
272
        }
 
273
 
 
274
        if (thread_state != TGA_EXPORTER_WRITE) break;
 
275
 
 
276
        if (buffer_shared_ptr != 0) {
 
277
            writer.writeTGA(*buffer_shared_ptr);
 
278
        }
 
279
    }
 
280
 
 
281
    thread_state = TGA_EXPORTER_STOPPED;
 
282
 
 
283
    SDL_mutexV(mutex);
 
284
}
 
285
 
 
286
void TGAExporter::stop() {
 
287
 
 
288
    if(thread_state == TGA_EXPORTER_STOPPED || thread_state == TGA_EXPORTER_EXIT) return;
 
289
 
 
290
    SDL_mutexP(mutex);
 
291
 
 
292
        thread_state = TGA_EXPORTER_EXIT;
 
293
 
 
294
        SDL_CondSignal(cond);
 
295
 
 
296
    SDL_mutexV(mutex);
 
297
 
 
298
    while(thread_state != TGA_EXPORTER_STOPPED)
 
299
        SDL_Delay(100);
 
300
}
 
301
 
 
302
void TGAExporter::capture() {
 
303
 
 
304
    std::vector<char>* next_pixel_ptr = (buffer_shared_ptr == &buffer1) ?
 
305
        &buffer2 : &buffer1;
 
306
 
 
307
    writer.capture(*next_pixel_ptr);
 
308
 
 
309
    SDL_mutexP(mutex);
 
310
 
 
311
        buffer_shared_ptr = next_pixel_ptr;
 
312
        thread_state      = TGA_EXPORTER_WRITE;
 
313
 
 
314
    SDL_CondSignal(cond);
 
315
    SDL_mutexV(mutex);
 
316
}