-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtgaloader.cpp
325 lines (275 loc) · 20 KB
/
tgaloader.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
/********************************************************************************
/Name: TGA.cpp *
/Header: tga.h *
/Purpose: Load Compressed and Uncompressed TGA files *
/Functions: LoadTGA(Texture * texture, char * filename) *
/ LoadCompressedTGA(Texture * texture, char * filename, FILE * fTGA) *
/ LoadUncompressedTGA(Texture * texture, char * filename, FILE * fTGA)*
/*******************************************************************************/
#include "tga.h"
#include "macro.h"
#include <string>
extern std::string LogFile;
/********************************************************************************
/name : LoadTGA(Texture * texture, char * filename) *
/function: Open and test the file to make sure it is a valid TGA file *
/parems: texture, pointer to a Texture structure *
/ filename, string pointing to file to open *
/********************************************************************************/
bool LoadTGA(Texture * texture, char * filename) // Load a TGA file
{
FILE * fTGA; // File pointer to texture file
fTGA = fopen(filename, "rb"); // Open file for reading
if(fTGA == NULL) // If it didn't open....
{
WriteLogF("ERROR: Could not open texture file"); // Display an error message
return false; // Exit function
}
if(fread(&tgaheader, sizeof(TGAHeader), 1, fTGA) == 0) // Attempt to read 12 byte header from file
{
WriteLogF("ERROR: Could not read file header"); // If it fails, display an error message
if(fTGA != NULL) // Check to seeiffile is still open
{
fclose(fTGA); // If it is, close it
}
return false; // Exit function
}
if(memcmp(uTGAcompare, &tgaheader, sizeof(tgaheader)) == 0) // See if header matches the predefined header of
{ // an Uncompressed TGA image
LoadUncompressedTGA(texture, filename, fTGA); // If so, jump to Uncompressed TGA loading code
}
else if(memcmp(cTGAcompare, &tgaheader, sizeof(tgaheader)) == 0) // See if header matches the predefined header of
{ // an RLE compressed TGA image
LoadCompressedTGA(texture, filename, fTGA); // If so, jump to Compressed TGA loading code
}
else // If header matches neither type
{
WriteLogF("Invalid Image: TGA file be type 2 or type 10 "); // Display an error
fclose(fTGA);
return false; // Exit function
}
return true; // All went well, continue on
}
bool LoadUncompressedTGA(Texture * texture, char * filename, FILE * fTGA) // Load an uncompressed TGA (note, much of this code is based on NeHe's
{ // TGA Loading code nehe.gamedev.net)
if(fread(tga.header, sizeof(tga.header), 1, fTGA) == 0) // Read TGA header
{
WriteLogF("ERROR: Could not read info header"); // Display error
if(fTGA != NULL) // if file is still open
{
fclose(fTGA); // Close it
}
return false; // Return failular
}
texture->width = tga.header[1] * 256 + tga.header[0]; // Determine The TGA Width (highbyte*256+lowbyte)
texture->height = tga.header[3] * 256 + tga.header[2]; // Determine The TGA Height (highbyte*256+lowbyte)
texture->bpp = tga.header[4]; // Determine the bits per pixel
tga.Width = texture->width; // Copy width into local structure
tga.Height = texture->height; // Copy height into local structure
tga.Bpp = texture->bpp; // Copy BPP into local structure
if((texture->width == 0) || (texture->height == 0) || ((texture->bpp != 24) && (texture->bpp !=32))) // Make sure all information is valid
{
WriteLogF("ERROR: Invalid texture information");
if(fTGA != NULL) // Check if file is still open
{
fclose(fTGA); // If so, close it
}
return false; // Return failed
}
if(texture->bpp == 24) // If the BPP of the image is 24...
texture->type = GL_RGB; // Set Image type to GL_RGB
else // Else if its 32 BPP
texture->type = GL_RGBA; // Set image type to GL_RGBA
tga.bytesPerPixel = (tga.Bpp / 8); // Compute the number of BYTES per pixel
tga.imageSize = (tga.bytesPerPixel * tga.Width * tga.Height); // Compute the total amout ofmemory needed to store data
texture->imageData = (GLubyte *)malloc(tga.imageSize); // Allocate that much memory
if(texture->imageData == NULL) // If no space was allocated
{
WriteLogF("ERROR: Could not allocate memory for image");
fclose(fTGA); // Close the file
return false; // Return failed
}
if(fread(texture->imageData, 1, tga.imageSize, fTGA) != tga.imageSize) // Attempt to read image data
{
WriteLogF("ERROR: Could not read image data");
if(texture->imageData != NULL) // If imagedata has data in it
{
free(texture->imageData); // Delete data from memory
}
fclose(fTGA); // Close file
return false; // Return failed
}
// Byte Swapping Optimized By Steve Thomas
for(GLuint cswap = 0; cswap <= (int)tga.imageSize; cswap += tga.bytesPerPixel)
{
texture->imageData[cswap] ^= texture->imageData[cswap+2] ^=
texture->imageData[cswap] ^= texture->imageData[cswap+2];
}
fclose(fTGA); // Close file
return true; // Return success
}
bool LoadCompressedTGA(Texture * texture, char * filename, FILE * fTGA) // Load COMPRESSED TGAs
{
if(fread(tga.header, sizeof(tga.header), 1, fTGA) == 0) // Attempt to read header
{
WriteLogF("ERROR: Could not read info header");
if(fTGA != NULL) // If file is open
{
fclose(fTGA); // Close it
}
return false; // Return failed
}
texture->width = tga.header[1] * 256 + tga.header[0]; // Determine The TGA Width (highbyte*256+lowbyte)
texture->height = tga.header[3] * 256 + tga.header[2]; // Determine The TGA Height (highbyte*256+lowbyte)
texture->bpp = tga.header[4]; // Determine Bits Per Pixel
tga.Width = texture->width; // Copy width to local structure
tga.Height = texture->height; // Copy width to local structure
tga.Bpp = texture->bpp; // Copy width to local structure
if((texture->width == 0) || (texture->height == 0) || ((texture->bpp != 24) && (texture->bpp !=32))) //Make sure all texture info is ok
{
WriteLogF("ERROR: Invalid texture information");
if(fTGA != NULL) // Check if file is open
{
fclose(fTGA); // Ifit is, close it
}
return false; // Return failed
}
if(texture->bpp == 24) // If the BPP of the image is 24...
texture->type = GL_RGB; // Set Image type to GL_RGB
else // Else if its 32 BPP
texture->type = GL_RGBA; // Set image type to GL_RGBA
tga.bytesPerPixel = (tga.Bpp / 8); // Compute BYTES per pixel
tga.imageSize = (tga.bytesPerPixel * tga.Width * tga.Height); // Compute amout of memory needed to store image
texture->imageData = (GLubyte *)malloc(tga.imageSize); // Allocate that much memory
if(texture->imageData == NULL) // If it wasnt allocated correctly..
{
WriteLogF("ERROR: Could not allocate memory for image");
fclose(fTGA); // Close file
return false; // Return failed
}
GLuint pixelcount = tga.Height * tga.Width; // Nuber of pixels in the image
GLuint currentpixel = 0; // Current pixel being read
GLuint currentbyte = 0; // Current byte
GLubyte * colorbuffer = (GLubyte *)malloc(tga.bytesPerPixel); // Storage for 1 pixel
do
{
GLubyte chunkheader = 0; // Storage for "chunk" header
if(fread(&chunkheader, sizeof(GLubyte), 1, fTGA) == 0) // Read in the 1 byte header
{
WriteLogF("ERROR: Could not read RLE header");
if(fTGA != NULL) // If file is open
{
fclose(fTGA); // Close file
}
if(texture->imageData != NULL) // If there is stored image data
{
free(texture->imageData); // Delete image data
}
return false; // Return failed
}
if(chunkheader <= 128) // If the ehader is 128, it means the that is the number of RAW color packets minus 1
{ // that follow the header
chunkheader++; // add 1 to get number of following color values
for(short counter = 0; counter < chunkheader; counter++) // Read RAW color values
{
if(fread(colorbuffer, 1, tga.bytesPerPixel, fTGA) != tga.bytesPerPixel) // Try to read 1 pixel
{
WriteLogF("ERROR: Could not read image data");
if(fTGA != NULL) // See if file is open
{
fclose(fTGA); // If so, close file
}
if(colorbuffer != NULL) // See if colorbuffer has data in it
{
free(colorbuffer); // If so, delete it
}
if(texture->imageData != NULL) // See if there is stored Image data
{
free(texture->imageData); // If so, delete it too
}
return false; // Return failed
}
// write to memory
texture->imageData[currentbyte ] = colorbuffer[2]; // Flip R and B vcolor values around in the process
texture->imageData[currentbyte + 1 ] = colorbuffer[1];
texture->imageData[currentbyte + 2 ] = colorbuffer[0];
if(tga.bytesPerPixel == 4) // if its a 32 bpp image
{
texture->imageData[currentbyte + 3] = colorbuffer[3]; // copy the 4th byte
}
currentbyte += tga.bytesPerPixel; // Increase thecurrent byte by the number of bytes per pixel
currentpixel++; // Increase current pixel by 1
if(currentpixel > pixelcount) // Make sure we havent read too many pixels
{
WriteLogF("ERROR: Too many pixels read");
if(fTGA != NULL) // If there is a file open
{
fclose(fTGA); // Close file
}
if(colorbuffer != NULL) // If there is data in colorbuffer
{
free(colorbuffer); // Delete it
}
if(texture->imageData != NULL) // If there is Image data
{
free(texture->imageData); // delete it
}
return false; // Return failed
}
}
}
else // chunkheader > 128 RLE data, next color reapeated chunkheader - 127 times
{
chunkheader -= 127; // Subteact 127 to get rid of the ID bit
if(fread(colorbuffer, 1, tga.bytesPerPixel, fTGA) != tga.bytesPerPixel) // Attempt to read following color values
{
WriteLogF("ERROR: Could not read from file");
if(fTGA != NULL) // If thereis a file open
{
fclose(fTGA); // Close it
}
if(colorbuffer != NULL) // If there is data in the colorbuffer
{
free(colorbuffer); // delete it
}
if(texture->imageData != NULL) // If thereis image data
{
free(texture->imageData); // delete it
}
return false; // return failed
}
for(short counter = 0; counter < chunkheader; counter++) // copy the color into the image data as many times as dictated
{ // by the header
texture->imageData[currentbyte ] = colorbuffer[2]; // switch R and B bytes areound while copying
texture->imageData[currentbyte + 1 ] = colorbuffer[1];
texture->imageData[currentbyte + 2 ] = colorbuffer[0];
if(tga.bytesPerPixel == 4) // If TGA images is 32 bpp
{
texture->imageData[currentbyte + 3] = colorbuffer[3]; // Copy 4th byte
}
currentbyte += tga.bytesPerPixel; // Increase current byte by the number of bytes per pixel
currentpixel++; // Increase pixel count by 1
if(currentpixel > pixelcount) // Make sure we havent written too many pixels
{
WriteLogF("ERROR: Too many pixels read");
if(fTGA != NULL) // If there is a file open
{
fclose(fTGA); // Close file
}
if(colorbuffer != NULL) // If there is data in colorbuffer
{
free(colorbuffer); // Delete it
}
if(texture->imageData != NULL) // If there is Image data
{
free(texture->imageData); // delete it
}
return false; // Return failed
}
}
}
}
while(currentpixel < pixelcount); // Loop while there are still pixels left
fclose(fTGA); // Close the file
return true; // return success
}