Project::OSiRiON - Git repositories
Project::OSiRiON
News . About . Screenshots . Downloads . Forum . Wiki . Tracker . Git
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/render/tga.cc104
1 files changed, 94 insertions, 10 deletions
diff --git a/src/render/tga.cc b/src/render/tga.cc
index c7f4fc1..d8e2216 100644
--- a/src/render/tga.cc
+++ b/src/render/tga.cc
@@ -65,7 +65,7 @@ Image *TGA::load(const char *filename)
return 0;
}
- // byte 0 - image ID field lenght
+ // byte 0 - image ID field length
unsigned int tga_idlength = header[0];
// byte 1 - color map type
@@ -233,10 +233,10 @@ void TGA::save(const char *filename, Image & image)
unsigned char header[18];
memset(header, 0, sizeof(header));
- // byte 0 - image ID field lenght = 0 (no image ID field present)
+ // byte 0 - image ID field length = 0 (no image ID field present)
// byte 1 - color map type = 0 (no palette present)
- // byte 2 - image type = 2 (truecolor without RLE)
- header[2] = TGA_TRUECOLOR;
+ // byte 2 - image type = 10 (truecolor RLE encoded)
+ header[2] = TGA_TRUECOLOR_RLE;
// byte 3-11 - palette data (not used)
// byte 12+13 - image width
header[12] = (image.width() & 0xff);
@@ -254,20 +254,104 @@ void TGA::save(const char *filename, Image & image)
// write image data
// TGA has the R and B channels switched
- unsigned char buf[image.channels()];
+ unsigned char pixel_data[image.channels()];
+ unsigned char block_data[image.channels()*128];
+ unsigned char rle_packet;
+ bool compress = false;
+ size_t block_length = 0;
+
for (int y = image.height()-1; y >= 0; y--) {
for (size_t x = 0; x < image.width(); x++) {
- buf[0] = *image[y*image.width()*image.channels()+x*image.channels()+2];
- buf[1] = *image[y*image.width()*image.channels()+x*image.channels()+1];
- buf[2] = *image[y*image.width()*image.channels()+x*image.channels()];
+ size_t index = y*image.width()*image.channels() + x * image.channels();
+ pixel_data[0] = *image[index+2];
+ pixel_data[1] = *image[index+1];
+ pixel_data[2] = *image[index];
if (image.channels() == 4)
- buf[3] = *image[y*image.width()*image.channels()+x*image.channels()+3];
+ pixel_data[3] = *image[index+3];
+
+ if (block_length == 0) {
+ memcpy(block_data, pixel_data, image.channels());
+ block_length++;
+ compress = false;
+ } else {
+ if (!compress) {
+
+ // uncompressed block and pixel_data differs from the last pixel
+ if (memcmp(&block_data[(block_length-1)*image.channels()], pixel_data, image.channels()) != 0) {
+ // append pixel
+ memcpy(&block_data[block_length*image.channels()], pixel_data, image.channels());
+
+ block_length++;
+ } else {
+
+ // uncompressed block and pixel data is identical
+ if (block_length > 1 ) {
+ // write the uncompressed block
+ rle_packet = block_length - 2;
+ ofs.write((char *)&rle_packet, 1);
+ ofs.write((char *)block_data, (block_length-1) * image.channels());
+ block_length = 1;
+ }
+ memcpy(block_data, pixel_data, image.channels());
+ block_length++;
+ compress = true;
+ }
+
+ } else {
+
+ // compressed block and pixel data is identical
+ if (memcmp(block_data, pixel_data, image.channels()) == 0) {
+ block_length++;
+
+ } else {
+
+ // compressed block and pixel data differs
+ if (block_length > 1) {
+ // write the compressed block
+ rle_packet = block_length + 127;
+ ofs.write((char *)&rle_packet, 1);
+ ofs.write((char *)block_data, image.channels());
+ block_length = 0;
+ }
+ memcpy(&block_data[block_length * image.channels()], pixel_data, image.channels());
+ block_length++;
+ compress = false;
+ }
+ }
+ }
+
+ if (block_length == 128) {
+ rle_packet = block_length - 1;
+ if (!compress) {
+ ofs.write((char *)&rle_packet, 1);
+ ofs.write((char *)block_data, 128 * image.channels());
+ } else {
+ rle_packet += 128;
+ ofs.write((char *)&rle_packet, 1);
+ ofs.write((char *)block_data, image.channels());
+ }
- ofs.write((char *)buf, image.channels());
+ block_length = 0;
+ compress = false;
+ }
+ }
+ }
+
+ // write remaining bytes
+ if (block_length) {
+ rle_packet = block_length - 1;
+ if (!compress) {
+ ofs.write((char *)&rle_packet, 1);
+ ofs.write((char *)block_data, block_length * image.channels());
+ } else {
+ rle_packet += 128;
+ ofs.write((char *)&rle_packet, 1);
+ ofs.write((char *)block_data, image.channels());
}
}
+
// write footer (optional, but the specification recommends it)
char footer[26];
memset(footer, 0, sizeof(footer));