blob: 779941692406bd9fa44dbd5da8eff29c844f1e84 [file] [log] [blame]
jtgafb833d1999-08-19 00:55:39 +00001/* readtex.c */
2
3/*
4 * Read an SGI .rgb image file and generate a mipmap texture set.
5 * Much of this code was borrowed from SGI's tk OpenGL toolkit.
6 */
7
8
9
10#include <GL/gl.h>
11#include <GL/glu.h>
12#include <stdio.h>
13#include <stdlib.h>
14#include <string.h>
15
16
17#ifndef SEEK_SET
18# define SEEK_SET 0
19#endif
20
21
22/*
23** RGB Image Structure
24*/
25
26typedef struct _TK_RGBImageRec {
27 GLint sizeX, sizeY;
28 GLint components;
29 unsigned char *data;
30} TK_RGBImageRec;
31
32
33
34/******************************************************************************/
35
36typedef struct _rawImageRec {
37 unsigned short imagic;
38 unsigned short type;
39 unsigned short dim;
40 unsigned short sizeX, sizeY, sizeZ;
41 unsigned long min, max;
42 unsigned long wasteBytes;
43 char name[80];
44 unsigned long colorMap;
45 FILE *file;
46 unsigned char *tmp, *tmpR, *tmpG, *tmpB, *tmpA;
47 unsigned long rleEnd;
48 GLuint *rowStart;
49 GLint *rowSize;
50} rawImageRec;
51
52/******************************************************************************/
53
54static void ConvertShort(unsigned short *array, long length)
55{
56 unsigned long b1, b2;
57 unsigned char *ptr;
58
59 ptr = (unsigned char *)array;
60 while (length--) {
61 b1 = *ptr++;
62 b2 = *ptr++;
63 *array++ = (unsigned short) ((b1 << 8) | (b2));
64 }
65}
66
67static void ConvertLong(GLuint *array, long length)
68{
69 unsigned long b1, b2, b3, b4;
70 unsigned char *ptr;
71
72 ptr = (unsigned char *)array;
73 while (length--) {
74 b1 = *ptr++;
75 b2 = *ptr++;
76 b3 = *ptr++;
77 b4 = *ptr++;
78 *array++ = (b1 << 24) | (b2 << 16) | (b3 << 8) | (b4);
79 }
80}
81
82static rawImageRec *RawImageOpen(const char *fileName)
83{
84 union {
85 int testWord;
86 char testByte[4];
87 } endianTest;
88 rawImageRec *raw;
89 GLenum swapFlag;
90 int x;
91
92 endianTest.testWord = 1;
93 if (endianTest.testByte[0] == 1) {
94 swapFlag = GL_TRUE;
95 } else {
96 swapFlag = GL_FALSE;
97 }
98
99 raw = (rawImageRec *)malloc(sizeof(rawImageRec));
100 if (raw == NULL) {
101 fprintf(stderr, "Out of memory!\n");
102 return NULL;
103 }
104 if ((raw->file = fopen(fileName, "rb")) == NULL) {
105 perror(fileName);
106 return NULL;
107 }
108
109 fread(raw, 1, 12, raw->file);
110
111 if (swapFlag) {
112 ConvertShort(&raw->imagic, 6);
113 }
114
115 raw->tmp = (unsigned char *)malloc(raw->sizeX*256);
116 raw->tmpR = (unsigned char *)malloc(raw->sizeX*256);
117 raw->tmpG = (unsigned char *)malloc(raw->sizeX*256);
118 raw->tmpB = (unsigned char *)malloc(raw->sizeX*256);
119 if (raw->sizeZ==4) {
120 raw->tmpA = (unsigned char *)malloc(raw->sizeX*256);
121 }
122 if (raw->tmp == NULL || raw->tmpR == NULL || raw->tmpG == NULL ||
123 raw->tmpB == NULL) {
124 fprintf(stderr, "Out of memory!\n");
125 return NULL;
126 }
127
128 if ((raw->type & 0xFF00) == 0x0100) {
129 x = raw->sizeY * raw->sizeZ * sizeof(GLuint);
130 raw->rowStart = (GLuint *)malloc(x);
131 raw->rowSize = (GLint *)malloc(x);
132 if (raw->rowStart == NULL || raw->rowSize == NULL) {
133 fprintf(stderr, "Out of memory!\n");
134 return NULL;
135 }
136 raw->rleEnd = 512 + (2 * x);
137 fseek(raw->file, 512, SEEK_SET);
138 fread(raw->rowStart, 1, x, raw->file);
139 fread(raw->rowSize, 1, x, raw->file);
140 if (swapFlag) {
141 ConvertLong(raw->rowStart, (long) (x/sizeof(GLuint)));
142 ConvertLong((GLuint *)raw->rowSize, (long) (x/sizeof(GLint)));
143 }
144 }
145 return raw;
146}
147
148static void RawImageClose(rawImageRec *raw)
149{
150
151 fclose(raw->file);
152 free(raw->tmp);
153 free(raw->tmpR);
154 free(raw->tmpG);
155 free(raw->tmpB);
156 if (raw->sizeZ>3) {
157 free(raw->tmpA);
158 }
159 free(raw);
160}
161
162static void RawImageGetRow(rawImageRec *raw, unsigned char *buf, int y, int z)
163{
164 unsigned char *iPtr, *oPtr, pixel;
165 int count, done = 0;
166
167 if ((raw->type & 0xFF00) == 0x0100) {
168 fseek(raw->file, (long) raw->rowStart[y+z*raw->sizeY], SEEK_SET);
169 fread(raw->tmp, 1, (unsigned int)raw->rowSize[y+z*raw->sizeY],
170 raw->file);
171
172 iPtr = raw->tmp;
173 oPtr = buf;
174 while (!done) {
175 pixel = *iPtr++;
176 count = (int)(pixel & 0x7F);
177 if (!count) {
178 done = 1;
179 return;
180 }
181 if (pixel & 0x80) {
182 while (count--) {
183 *oPtr++ = *iPtr++;
184 }
185 } else {
186 pixel = *iPtr++;
187 while (count--) {
188 *oPtr++ = pixel;
189 }
190 }
191 }
192 } else {
193 fseek(raw->file, 512+(y*raw->sizeX)+(z*raw->sizeX*raw->sizeY),
194 SEEK_SET);
195 fread(buf, 1, raw->sizeX, raw->file);
196 }
197}
198
199
200static void RawImageGetData(rawImageRec *raw, TK_RGBImageRec *final)
201{
202 unsigned char *ptr;
203 int i, j;
204
205 final->data = (unsigned char *)malloc((raw->sizeX+1)*(raw->sizeY+1)*4);
206 if (final->data == NULL) {
207 fprintf(stderr, "Out of memory!\n");
208 }
209
210 ptr = final->data;
211 for (i = 0; i < (int)(raw->sizeY); i++) {
212 RawImageGetRow(raw, raw->tmpR, i, 0);
213 RawImageGetRow(raw, raw->tmpG, i, 1);
214 RawImageGetRow(raw, raw->tmpB, i, 2);
215 if (raw->sizeZ>3) {
216 RawImageGetRow(raw, raw->tmpA, i, 3);
217 }
218 for (j = 0; j < (int)(raw->sizeX); j++) {
219 *ptr++ = *(raw->tmpR + j);
220 *ptr++ = *(raw->tmpG + j);
221 *ptr++ = *(raw->tmpB + j);
222 if (raw->sizeZ>3) {
223 *ptr++ = *(raw->tmpA + j);
224 }
225 }
226 }
227}
228
229
230static TK_RGBImageRec *tkRGBImageLoad(const char *fileName)
231{
232 rawImageRec *raw;
233 TK_RGBImageRec *final;
234
235 raw = RawImageOpen(fileName);
236 if (!raw) {
237 fprintf(stderr, "File not found\n");
238 return NULL;
239 }
240 final = (TK_RGBImageRec *)malloc(sizeof(TK_RGBImageRec));
241 if (final == NULL) {
242 fprintf(stderr, "Out of memory!\n");
243 return NULL;
244 }
245 final->sizeX = raw->sizeX;
246 final->sizeY = raw->sizeY;
247 final->components = raw->sizeZ;
248 RawImageGetData(raw, final);
249 RawImageClose(raw);
250 return final;
251}
252
253
254static void FreeImage( TK_RGBImageRec *image )
255{
256 free(image->data);
257 free(image);
258}
259
260
261/*
262 * Load an SGI .rgb file and generate a set of 2-D mipmaps from it.
263 * Input: imageFile - name of .rgb to read
264 * intFormat - internal texture format to use, or number of components
265 * Return: GL_TRUE if success, GL_FALSE if error.
266 */
267GLboolean LoadRGBMipmaps( const char *imageFile, GLint intFormat )
268{
269 GLint error;
270 GLenum format;
271 TK_RGBImageRec *image;
272
273 image = tkRGBImageLoad( imageFile );
274 if (!image) {
275 return GL_FALSE;
276 }
277
278 if (image->components==3) {
279 format = GL_RGB;
280 }
281 else if (image->components==4) {
282 format = GL_RGBA;
283 }
284 else {
285 /* not implemented */
286 fprintf(stderr,
287 "Error in LoadRGBMipmaps %d-component images not implemented\n",
288 image->components );
289 return GL_FALSE;
290 }
291
292 error = gluBuild2DMipmaps( GL_TEXTURE_2D,
293 intFormat,
294 image->sizeX, image->sizeY,
295 format,
296 GL_UNSIGNED_BYTE,
297 image->data );
298
299 FreeImage(image);
300 return error ? GL_FALSE : GL_TRUE;
301}
302
303
304
305/*
306 * Load an SGI .rgb file and return a pointer to the image data.
307 * Input: imageFile - name of .rgb to read
308 * Output: width - width of image
309 * height - height of image
310 * format - format of image (GL_RGB or GL_RGBA)
311 * Return: pointer to image data or NULL if error
312 */
313GLubyte *LoadRGBImage( const char *imageFile, GLint *width, GLint *height,
314 GLenum *format )
315{
316 TK_RGBImageRec *image;
317 GLint bytes;
318 GLubyte *buffer;
319
320 image = tkRGBImageLoad( imageFile );
321 if (!image) {
322 return NULL;
323 }
324
325 if (image->components==3) {
326 *format = GL_RGB;
327 }
328 else if (image->components==4) {
329 *format = GL_RGBA;
330 }
331 else {
332 /* not implemented */
333 fprintf(stderr,
334 "Error in LoadRGBImage %d-component images not implemented\n",
335 image->components );
336 return NULL;
337 }
338
339 *width = image->sizeX;
340 *height = image->sizeY;
341
342 bytes = image->sizeX * image->sizeY * image->components;
343 buffer = (GLubyte *) malloc(bytes);
344 if (!buffer)
345 return NULL;
346
347 memcpy( (void *) buffer, (void *) image->data, bytes );
348
349 FreeImage(image);
350
351 return buffer;
352}
353