1 /*
2  * TextureLoader.cxx
3  * Daniel Nelson - 9/14/0
4  *
5  * Copyright (C) 2000  Daniel Nelson
6  * Copyright (C) 2004  Andrew Sayman
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21  *
22  * Daniel Nelson - aluminumangel.org
23  * 174 W. 18th Ave.
24  * Columbus, OH  43210
25  *
26  * Loads textures from uncompressed TGA files.
27  */
28 
29 #include <GL/glut.h>
30 #include <fstream>
31 #include <iostream>
32 #include <cstring>
33 #include <sys/stat.h>
34 
35 #ifndef _WIN32
36 #  include <unistd.h>
37 #endif
38 
39 #include "glext.h"
40 
41 using namespace std;
42 
43 #include "TextureLoader.h"
44 #include "Game.h"
45 
46 // the header of an uncompressed TGA file
47 const GLubyte header_image[11] = { 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
48 
loadAlphaTGA(const char * tga_file_name,int _height,int _width)49 GLubyte *TextureLoader::loadAlphaTGA ( const char *tga_file_name, int _height,
50  int _width )
51 {
52   GLubyte *full_texture = loadTGA(tga_file_name, _height, _width);
53 
54   int texture_size = _width * _height;
55 
56   GLubyte *alpha_texture = new GLubyte[texture_size];
57 
58   for (int n = 0; n < texture_size; n++)
59     alpha_texture[n] = full_texture[4 * n + 3];
60 
61   if (full_texture != null) {
62     delete [] full_texture;
63     full_texture = null;
64   }
65 
66   return alpha_texture;
67 }
68 
loadNoAlphaTGA(const char * tga_file_name,int _height,int _width)69 GLubyte *TextureLoader::loadNoAlphaTGA ( const char *tga_file_name, int _height,
70  int _width )
71 {
72   GLubyte *full_texture = loadTGA(tga_file_name, _height, _width);
73 
74   int texture_size = _width * _height;
75 
76   GLubyte *no_alpha_texture = new GLubyte[texture_size * 3];
77 
78   for (int n = 0; n < texture_size; n++) {
79     float alpha = full_texture[4 * n + 3] * (1.0f / 255.0f);
80     no_alpha_texture[3 * n + 0] = (GLubyte) (alpha * full_texture[4 * n + 0]);
81     no_alpha_texture[3 * n + 1] = (GLubyte) (alpha * full_texture[4 * n + 1]);
82     no_alpha_texture[3 * n + 2] = (GLubyte) (alpha * full_texture[4 * n + 2]);
83   }
84 
85   if (full_texture != null) {
86     delete [] full_texture;
87     full_texture = null;
88   }
89 
90   return no_alpha_texture;
91 }
92 
loadTGA(const char * tga_file_name,int _height,int _width,int _color_depth)93 GLubyte *TextureLoader::loadTGA ( const char *tga_file_name, int _height,
94  int _width, int _color_depth )
95 {
96 #ifndef _WIN32
97   ifstream file(tga_file_name);
98 #else
99   ifstream file(tga_file_name, ios::binary);
100 #endif
101   if (file.fail()) {
102     cerr << "Error opening texture file '" << tga_file_name << "'." << endl;
103     exit(1);
104   }
105 
106   GLubyte id_length;
107   file.read((char *) &id_length, 1);
108 
109   GLubyte static_header[11];
110   file.read((char *) static_header, sizeof(static_header));
111   if (memcmp(static_header, header_image, sizeof(static_header)) != 0) {
112     cerr << "Texture file '" << tga_file_name << "' is not in uncompressed "
113      "TGA format." << endl;
114     exit(1);
115   }
116 
117   GLubyte header[6];
118   file.read((char *) header, sizeof(header));
119 
120   int width = header[1] * 256 + header[0];
121   int height = header[3] * 256 + header[2];
122 
123   if (width != _width || height != _height) {
124     cerr << "Texture file '" << tga_file_name << "' does not have the expected "
125      "height and width.  [" << height << 'x' << width << "] vs expected ["
126      << _height << 'x' << _width << "]." << endl;
127     exit(1);
128   }
129 
130   int color_depth = header[4];
131   if (color_depth != 24 && color_depth != 32) {
132     cerr << "Texture file '" << tga_file_name << "' has an unsupported color "
133      "depth." << endl;
134     exit(1);
135   }
136   if (_color_depth != 0 && _color_depth != color_depth) {
137     cerr << "Texture file '" << tga_file_name << "' does not have the expected "
138      "color depth." << endl;
139     exit(1);
140   }
141 
142   GLubyte b;
143   while (id_length--)
144     file.read((char *) &b, 1);
145 
146   int texture_size = width * height * color_depth / 8;
147 
148   GLubyte *texture = new GLubyte[texture_size];
149 
150   file.read((char *) texture, texture_size);
151 
152   // tga is BGR
153   for (int n = 0; n < texture_size; n += color_depth / 8) {
154     GLubyte swap = texture[n];
155     texture[n] = texture[n + 2];
156     texture[n + 2] = swap;
157   }
158 
159   return texture;
160 }
161 
createTGA(const char * tga_file_name,GLubyte * texture,int _height,int _width,const char * tga_id)162 void TextureLoader::createTGA ( const char *tga_file_name, GLubyte *texture,
163  int _height, int _width, const char *tga_id )
164 {
165 #ifndef _WIN32
166   ofstream file(tga_file_name);
167 #else
168   ofstream file(tga_file_name, ios::binary);
169 #endif
170   if (file.fail()) {
171     cerr << "Error creating texture file '" << tga_file_name << "'." << endl;
172     exit(1);
173   }
174 
175   GLubyte tga_id_length = strlen(tga_id);
176   file.write((char *) &tga_id_length, 1);
177 
178   file.write((char *) header_image, sizeof(header_image));
179 
180   GLubyte header[6];
181   header[1] = _width / 256;
182   header[0] = _width - 256 * header[1];
183   header[3] = _height / 256;
184   header[2] = _height - 256 * header[3];
185   header[4] = 32;
186   header[5] = 40;
187   file.write((char *) header, sizeof(header));
188 
189   file.write((char *) tga_id, tga_id_length);
190 
191   // tga is BGR
192   for (int n = 0; n < _width * _height * 4; n += 4) {
193     GLubyte swap = texture[n];
194     texture[n] = texture[n + 2];
195     texture[n + 2] = swap;
196   }
197 
198   file.write((char *) texture, _width * _height * 4);
199 
200   for (int n = 0; n < _width * _height * 4; n += 4) {
201     GLubyte swap = texture[n];
202     texture[n] = texture[n + 2];
203     texture[n + 2] = swap;
204   }
205 }
206 
fileExists(const char * file_name)207 bool TextureLoader::fileExists ( const char *file_name )
208 {
209   struct stat file_stats;
210 
211 #ifndef _WIN32
212 #else // stat fails to find directories with trailing delimiters in _WIN32
213   if (file_name[strlen(file_name) - 1] == GC_DD[0]) {
214     char truncated_file_name[256];
215     strncpy(truncated_file_name, file_name, 256);
216     truncated_file_name[strlen(file_name) - 1] = '\0';
217     return !stat(truncated_file_name, &file_stats);
218   }
219 #endif
220   return !stat(file_name, &file_stats);
221 }
222 
determineTGACheckSum(const char * tga_file_name,int _height,int _width)223 unsigned long TextureLoader::determineTGACheckSum ( const char *tga_file_name,
224  int _height, int _width )
225 {
226   GLubyte *texture = loadTGA(tga_file_name, _height, _width);
227 
228   unsigned long check_sum = 0;
229   for (int n = _width * _height * 4; n--; )
230     check_sum += texture[n];
231 
232   if (texture != null) {
233     delete [] texture;
234     texture = null;
235   }
236 
237   return check_sum;
238 }
239 
determineTGASize(const char * tga_file_name,int & height,int & width)240 void TextureLoader::determineTGASize ( const char *tga_file_name, int &height,
241  int &width )
242 {
243 #ifndef _WIN32
244   ifstream file(tga_file_name);
245 #else
246   ifstream file(tga_file_name, ios::binary);
247 #endif
248   if (file.fail()) {
249     cerr << "Error opening texture file '" << tga_file_name << "'." << endl;
250     exit(1);
251   }
252 
253   GLubyte id_length;
254   file.read((char *) &id_length, 1);
255 
256   GLubyte static_header[11];
257   file.read((char *) static_header, sizeof(static_header));
258   if (memcmp(static_header, header_image, sizeof(static_header)) != 0) {
259     cerr << "Texture file '" << tga_file_name << "' is not in uncompressed "
260      "TGA format." << endl;
261     exit(1);
262   }
263 
264   GLubyte header[6];
265   file.read((char *) header, sizeof(header));
266 
267   width = header[1] * 256 + header[0];
268   height = header[3] * 256 + header[2];
269 }
270