1 /*
2  * TGALoader.cpp
3  * Copyright (C) 2007 by Bryan Duff <duff0097@gmail.com>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
18  * USA
19  */
20 #include "TGALoader.h"
21 
LoadTGA(char * filename)22 TGAImageRec *LoadTGA(char *filename)
23 {
24   GLubyte TGAheader[12] = { 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0 };       // Uncompressed TGA Header
25   GLubyte TGAcompare[12];       // Used To Compare TGA Header
26   GLubyte header[6];            // First 6 Useful Bytes From The Header
27   GLuint bytesPerPixel;         // Holds Number Of Bytes Per Pixel Used In The TGA File
28   GLuint imageSize;             // Used To Store The Image Size When Setting Aside Ram
29   GLuint temp;                  // Temporary Variable
30   TGAImageRec *texture;
31   FILE *file;
32 
33   // Open The TGA File
34   file = cfh_fopen(filename, "rb");
35 
36   if((file == NULL) ||          // Does File Even Exist?
37      (fread(TGAcompare, 1, sizeof (TGAcompare), file) != sizeof (TGAcompare)) ||        // Are There 12 Bytes To Read?
38      (memcmp(TGAheader, TGAcompare, sizeof (TGAheader)) != 0) ||        // Does The Header Match What We Want?
39      (fread(header, 1, sizeof (header), file) != sizeof (header)))      // If So Read Next 6 Header Bytes
40   {
41     // If anything failed then close the file and return false
42     fclose(file);
43     return NULL;
44   }
45   // Create a new RGBAImageRec
46   texture = (TGAImageRec *) malloc(sizeof (TGAImageRec));
47 
48   // Determine the TGA width (highbyte*256+lowbyte) and height (highbyte*256+lowbyte)
49   texture->sizeX = header[1] * 256 + header[0];
50   texture->sizeY = header[3] * 256 + header[2];
51 
52   // Make sure the height, width, and bit depth are valid
53   if((texture->sizeX <= 0) || (texture->sizeY <= 0)
54      || ((header[4] != 24) && (header[4] != 32))) {
55     // If anything failed then close the file, free up memory for the image, and return NULL
56     fclose(file);
57     free(texture);
58     return NULL;
59   }
60   // Grab The TGA's Bits Per Pixel (24 or 32)
61   texture->bpp = header[4];
62   bytesPerPixel = texture->bpp / 8;     // Divide By 8 To Get The Bytes Per Pixel
63 
64   // Calculate The Memory Required For The TGA Data
65   imageSize = texture->sizeX * texture->sizeY * bytesPerPixel;
66 
67   // Reserve Memory To Hold The TGA Data
68   texture->data = (GLubyte *) malloc(imageSize);
69 
70   // Make sure the right amount of memory was allocated
71   if((texture->data == NULL)
72      || (fread(texture->data, 1, imageSize, file) != imageSize)) {
73     // Free up the image data if there was any
74     if(texture->data != NULL)
75       free(texture->data);
76 
77     // If anything failed then close the file, free up memory for the image, and return NULL
78     fclose(file);
79     free(texture);
80     return NULL;
81   }
82   // Loop Through The Image Data
83   for(GLuint i = 0; i < (imageSize); i += bytesPerPixel) {
84     // Swaps The 1st And 3rd Bytes ('R'ed and 'B'lue)
85     temp = texture->data[i];    // Temporarily Store The Value At Image Data 'i'
86     texture->data[i] = texture->data[i + 2];    // Set The 1st Byte To The Value Of The 3rd Byte
87     texture->data[i + 2] = temp;        // Set The 3rd Byte To The Value In 'temp' (1st Byte Value)
88   }
89 
90   // Close The File
91   fclose(file);
92 
93   return texture;
94 }
95 
WriteTGA(const char * filename,TGAImageRec * image,unsigned int size)96 void WriteTGA(const char *filename, TGAImageRec *image, unsigned int size)
97 {
98   //TGA header is 18 bytes
99   // True color image with no color map, uncompressed = 2 (3rd byte)
100   GLubyte TGAheader[12] = { 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
101   GLubyte header[6];     // First 6 Useful Bytes From The Header
102   int bytes_written = 0;
103   FILE* file;
104   unsigned char width[4];
105   unsigned char height[4];
106 
107   file = fopen(filename, "w");
108   if(!file) {
109     perror("WriteTGA");
110   }
111 
112   //defaults
113   memcpy(width, &image->sizeX, 4);
114   memcpy(height, &image->sizeY, 4);
115   //endian issues
116   header[0] = (GLubyte)width[0];
117   header[1] = (GLubyte)width[1];
118   header[2] = (GLubyte)height[0];
119   header[3] = (GLubyte)height[1];
120   header[4] = (GLubyte)24; //forced bpp
121   header[5] = 0; //no alpha
122 
123   //write header
124   fwrite(TGAheader, sizeof(TGAheader), 1, file);
125   fwrite(header, sizeof(header), 1, file);
126 
127   //write data
128   while(size != 0) {
129     bytes_written = fwrite(image->data, 1, size, file);
130     size -= bytes_written;
131   }
132   fclose(file);
133 }
134