Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
4349 | Serge | 1 | /* 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 |
||
11 | #include |
||
12 | #include |
||
13 | #include |
||
14 | #include |
||
15 | #include |
||
16 | #include "readtex.h" |
||
17 | |||
18 | |||
19 | #ifndef SEEK_SET |
||
20 | # define SEEK_SET 0 |
||
21 | #endif |
||
22 | |||
23 | |||
24 | /* |
||
25 | ** RGB Image Structure |
||
26 | */ |
||
27 | |||
28 | typedef struct _TK_RGBImageRec { |
||
29 | GLint sizeX, sizeY; |
||
30 | GLint components; |
||
31 | unsigned char *data; |
||
32 | } TK_RGBImageRec; |
||
33 | |||
34 | |||
35 | |||
36 | /******************************************************************************/ |
||
37 | |||
38 | typedef struct _rawImageRec { |
||
39 | unsigned short imagic; |
||
40 | unsigned short type; |
||
41 | unsigned short dim; |
||
42 | unsigned short sizeX, sizeY, sizeZ; |
||
43 | unsigned long min, max; |
||
44 | unsigned long wasteBytes; |
||
45 | char name[80]; |
||
46 | unsigned long colorMap; |
||
47 | FILE *file; |
||
48 | unsigned char *tmp, *tmpR, *tmpG, *tmpB, *tmpA; |
||
49 | unsigned long rleEnd; |
||
50 | GLuint *rowStart; |
||
51 | GLint *rowSize; |
||
52 | } rawImageRec; |
||
53 | |||
54 | /******************************************************************************/ |
||
55 | |||
56 | static void ConvertShort(unsigned short *array, long length) |
||
57 | { |
||
58 | unsigned long b1, b2; |
||
59 | unsigned char *ptr; |
||
60 | |||
61 | ptr = (unsigned char *)array; |
||
62 | while (length--) { |
||
63 | b1 = *ptr++; |
||
64 | b2 = *ptr++; |
||
65 | *array++ = (unsigned short) ((b1 << 8) | (b2)); |
||
66 | } |
||
67 | } |
||
68 | |||
69 | static void ConvertLong(GLuint *array, long length) |
||
70 | { |
||
71 | unsigned long b1, b2, b3, b4; |
||
72 | unsigned char *ptr; |
||
73 | |||
74 | ptr = (unsigned char *)array; |
||
75 | while (length--) { |
||
76 | b1 = *ptr++; |
||
77 | b2 = *ptr++; |
||
78 | b3 = *ptr++; |
||
79 | b4 = *ptr++; |
||
80 | *array++ = (b1 << 24) | (b2 << 16) | (b3 << 8) | (b4); |
||
81 | } |
||
82 | } |
||
83 | |||
84 | static rawImageRec *RawImageOpen(const char *fileName) |
||
85 | { |
||
86 | union { |
||
87 | int testWord; |
||
88 | char testByte[4]; |
||
89 | } endianTest; |
||
90 | rawImageRec *raw; |
||
91 | GLenum swapFlag; |
||
92 | int x; |
||
93 | size_t result; |
||
94 | |||
95 | endianTest.testWord = 1; |
||
96 | if (endianTest.testByte[0] == 1) { |
||
97 | swapFlag = GL_TRUE; |
||
98 | } else { |
||
99 | swapFlag = GL_FALSE; |
||
100 | } |
||
101 | |||
102 | raw = (rawImageRec *)calloc(1, sizeof(rawImageRec)); |
||
103 | if (raw == NULL) { |
||
104 | fprintf(stderr, "Out of memory!\n"); |
||
105 | return NULL; |
||
106 | } |
||
107 | raw->file = fopen(fileName, "rb"); |
||
108 | if (raw->file == NULL) { |
||
109 | const char *baseName = strrchr(fileName, '/'); |
||
110 | if(baseName) |
||
111 | raw->file = fopen(baseName + 1, "rb"); |
||
112 | if(raw->file == NULL) { |
||
113 | free(raw); |
||
114 | return NULL; |
||
115 | } |
||
116 | } |
||
117 | |||
118 | result = fread(raw, 1, 12, raw->file); |
||
119 | assert(result == 12); |
||
120 | |||
121 | if (swapFlag) { |
||
122 | ConvertShort(&raw->imagic, 1); |
||
123 | ConvertShort(&raw->type, 1); |
||
124 | ConvertShort(&raw->dim, 1); |
||
125 | ConvertShort(&raw->sizeX, 1); |
||
126 | ConvertShort(&raw->sizeY, 1); |
||
127 | ConvertShort(&raw->sizeZ, 1); |
||
128 | } |
||
129 | |||
130 | raw->tmp = (unsigned char *)malloc(raw->sizeX*256); |
||
131 | raw->tmpR = (unsigned char *)malloc(raw->sizeX*256); |
||
132 | raw->tmpG = (unsigned char *)malloc(raw->sizeX*256); |
||
133 | raw->tmpB = (unsigned char *)malloc(raw->sizeX*256); |
||
134 | if (raw->sizeZ==4) { |
||
135 | raw->tmpA = (unsigned char *)malloc(raw->sizeX*256); |
||
136 | } |
||
137 | if (raw->tmp == NULL || raw->tmpR == NULL || raw->tmpG == NULL || |
||
138 | raw->tmpB == NULL) { |
||
139 | fprintf(stderr, "Out of memory!\n"); |
||
140 | free(raw->tmp); |
||
141 | free(raw->tmpR); |
||
142 | free(raw->tmpG); |
||
143 | free(raw->tmpB); |
||
144 | free(raw->tmpA); |
||
145 | free(raw); |
||
146 | return NULL; |
||
147 | } |
||
148 | |||
149 | if ((raw->type & 0xFF00) == 0x0100) { |
||
150 | x = raw->sizeY * raw->sizeZ * sizeof(GLuint); |
||
151 | raw->rowStart = (GLuint *)malloc(x); |
||
152 | raw->rowSize = (GLint *)malloc(x); |
||
153 | if (raw->rowStart == NULL || raw->rowSize == NULL) { |
||
154 | fprintf(stderr, "Out of memory!\n"); |
||
155 | free(raw->tmp); |
||
156 | free(raw->tmpR); |
||
157 | free(raw->tmpG); |
||
158 | free(raw->tmpB); |
||
159 | free(raw->tmpA); |
||
160 | free(raw->rowStart); |
||
161 | free(raw->rowSize); |
||
162 | free(raw); |
||
163 | return NULL; |
||
164 | } |
||
165 | raw->rleEnd = 512 + (2 * x); |
||
166 | fseek(raw->file, 512, SEEK_SET); |
||
167 | result = fread(raw->rowStart, 1, x, raw->file); |
||
168 | assert(result == x); |
||
169 | result = fread(raw->rowSize, 1, x, raw->file); |
||
170 | assert(result == x); |
||
171 | if (swapFlag) { |
||
172 | ConvertLong(raw->rowStart, (long) (x/sizeof(GLuint))); |
||
173 | ConvertLong((GLuint *)raw->rowSize, (long) (x/sizeof(GLint))); |
||
174 | } |
||
175 | } |
||
176 | return raw; |
||
177 | } |
||
178 | |||
179 | static void RawImageClose(rawImageRec *raw) |
||
180 | { |
||
181 | fclose(raw->file); |
||
182 | free(raw->tmp); |
||
183 | free(raw->tmpR); |
||
184 | free(raw->tmpG); |
||
185 | free(raw->tmpB); |
||
186 | if (raw->rowStart) |
||
187 | free(raw->rowStart); |
||
188 | if (raw->rowSize) |
||
189 | free(raw->rowSize); |
||
190 | if (raw->sizeZ>3) { |
||
191 | free(raw->tmpA); |
||
192 | } |
||
193 | free(raw); |
||
194 | } |
||
195 | |||
196 | static void RawImageGetRow(rawImageRec *raw, unsigned char *buf, int y, int z) |
||
197 | { |
||
198 | unsigned char *iPtr, *oPtr, pixel; |
||
199 | int count, done = 0; |
||
200 | size_t result; |
||
201 | |||
202 | if ((raw->type & 0xFF00) == 0x0100) { |
||
203 | fseek(raw->file, (long) raw->rowStart[y+z*raw->sizeY], SEEK_SET); |
||
204 | result = fread(raw->tmp, 1, (unsigned int)raw->rowSize[y+z*raw->sizeY], |
||
205 | raw->file); |
||
206 | assert(result == (unsigned int)raw->rowSize[y+z*raw->sizeY]); |
||
207 | |||
208 | iPtr = raw->tmp; |
||
209 | oPtr = buf; |
||
210 | while (!done) { |
||
211 | pixel = *iPtr++; |
||
212 | count = (int)(pixel & 0x7F); |
||
213 | if (!count) { |
||
214 | done = 1; |
||
215 | return; |
||
216 | } |
||
217 | if (pixel & 0x80) { |
||
218 | while (count--) { |
||
219 | *oPtr++ = *iPtr++; |
||
220 | } |
||
221 | } else { |
||
222 | pixel = *iPtr++; |
||
223 | while (count--) { |
||
224 | *oPtr++ = pixel; |
||
225 | } |
||
226 | } |
||
227 | } |
||
228 | } else { |
||
229 | fseek(raw->file, 512+(y*raw->sizeX)+(z*raw->sizeX*raw->sizeY), |
||
230 | SEEK_SET); |
||
231 | result = fread(buf, 1, raw->sizeX, raw->file); |
||
232 | assert(result == raw->sizeX); |
||
233 | } |
||
234 | } |
||
235 | |||
236 | |||
237 | static void RawImageGetData(rawImageRec *raw, TK_RGBImageRec *final) |
||
238 | { |
||
239 | unsigned char *ptr; |
||
240 | int i, j; |
||
241 | |||
242 | final->data = (unsigned char *)malloc((raw->sizeX+1)*(raw->sizeY+1)*4); |
||
243 | if (final->data == NULL) { |
||
244 | fprintf(stderr, "Out of memory!\n"); |
||
245 | return; |
||
246 | } |
||
247 | |||
248 | ptr = final->data; |
||
249 | for (i = 0; i < (int)(raw->sizeY); i++) { |
||
250 | RawImageGetRow(raw, raw->tmpR, i, 0); |
||
251 | RawImageGetRow(raw, raw->tmpG, i, 1); |
||
252 | RawImageGetRow(raw, raw->tmpB, i, 2); |
||
253 | if (raw->sizeZ>3) { |
||
254 | RawImageGetRow(raw, raw->tmpA, i, 3); |
||
255 | } |
||
256 | for (j = 0; j < (int)(raw->sizeX); j++) { |
||
257 | *ptr++ = *(raw->tmpR + j); |
||
258 | *ptr++ = *(raw->tmpG + j); |
||
259 | *ptr++ = *(raw->tmpB + j); |
||
260 | if (raw->sizeZ>3) { |
||
261 | *ptr++ = *(raw->tmpA + j); |
||
262 | } |
||
263 | } |
||
264 | } |
||
265 | } |
||
266 | |||
267 | |||
268 | static TK_RGBImageRec *tkRGBImageLoad(const char *fileName) |
||
269 | { |
||
270 | rawImageRec *raw; |
||
271 | TK_RGBImageRec *final; |
||
272 | |||
273 | raw = RawImageOpen(fileName); |
||
274 | if (!raw) { |
||
275 | fprintf(stderr, "File not found\n"); |
||
276 | return NULL; |
||
277 | } |
||
278 | final = (TK_RGBImageRec *)malloc(sizeof(TK_RGBImageRec)); |
||
279 | if (final == NULL) { |
||
280 | fprintf(stderr, "Out of memory!\n"); |
||
281 | RawImageClose(raw); |
||
282 | return NULL; |
||
283 | } |
||
284 | final->sizeX = raw->sizeX; |
||
285 | final->sizeY = raw->sizeY; |
||
286 | final->components = raw->sizeZ; |
||
287 | RawImageGetData(raw, final); |
||
288 | RawImageClose(raw); |
||
289 | return final; |
||
290 | } |
||
291 | |||
292 | |||
293 | static void FreeImage( TK_RGBImageRec *image ) |
||
294 | { |
||
295 | free(image->data); |
||
296 | free(image); |
||
297 | } |
||
298 | |||
299 | |||
300 | /* |
||
301 | * Load an SGI .rgb file and generate a set of 2-D mipmaps from it. |
||
302 | * Input: imageFile - name of .rgb to read |
||
303 | * intFormat - internal texture format to use, or number of components |
||
304 | * Return: GL_TRUE if success, GL_FALSE if error. |
||
305 | */ |
||
306 | GLboolean LoadRGBMipmaps( const char *imageFile, GLint intFormat ) |
||
307 | { |
||
308 | GLint w, h; |
||
309 | return LoadRGBMipmaps2( imageFile, GL_TEXTURE_2D, intFormat, &w, &h ); |
||
310 | } |
||
311 | |||
312 | |||
313 | |||
314 | GLboolean LoadRGBMipmaps2( const char *imageFile, GLenum target, |
||
315 | GLint intFormat, GLint *width, GLint *height ) |
||
316 | { |
||
317 | GLint error; |
||
318 | GLenum format; |
||
319 | TK_RGBImageRec *image; |
||
320 | |||
321 | image = tkRGBImageLoad( imageFile ); |
||
322 | if (!image) { |
||
323 | return GL_FALSE; |
||
324 | } |
||
325 | |||
326 | if (image->components==3) { |
||
327 | format = GL_RGB; |
||
328 | } |
||
329 | else if (image->components==4) { |
||
330 | format = GL_RGBA; |
||
331 | } |
||
332 | else { |
||
333 | /* not implemented */ |
||
334 | fprintf(stderr, |
||
335 | "Error in LoadRGBMipmaps %d-component images not implemented\n", |
||
336 | image->components ); |
||
337 | FreeImage(image); |
||
338 | return GL_FALSE; |
||
339 | } |
||
340 | |||
341 | error = gluBuild2DMipmaps( target, |
||
342 | intFormat, |
||
343 | image->sizeX, image->sizeY, |
||
344 | format, |
||
345 | GL_UNSIGNED_BYTE, |
||
346 | image->data ); |
||
347 | |||
348 | *width = image->sizeX; |
||
349 | *height = image->sizeY; |
||
350 | |||
351 | FreeImage(image); |
||
352 | |||
353 | return error ? GL_FALSE : GL_TRUE; |
||
354 | } |
||
355 | |||
356 | |||
357 | |||
358 | /* |
||
359 | * Load an SGI .rgb file and return a pointer to the image data. |
||
360 | * Input: imageFile - name of .rgb to read |
||
361 | * Output: width - width of image |
||
362 | * height - height of image |
||
363 | * format - format of image (GL_RGB or GL_RGBA) |
||
364 | * Return: pointer to image data or NULL if error |
||
365 | */ |
||
366 | GLubyte *LoadRGBImage( const char *imageFile, GLint *width, GLint *height, |
||
367 | GLenum *format ) |
||
368 | { |
||
369 | TK_RGBImageRec *image; |
||
370 | GLint bytes; |
||
371 | GLubyte *buffer; |
||
372 | |||
373 | image = tkRGBImageLoad( imageFile ); |
||
374 | if (!image) { |
||
375 | return NULL; |
||
376 | } |
||
377 | |||
378 | if (image->components==3) { |
||
379 | *format = GL_RGB; |
||
380 | } |
||
381 | else if (image->components==4) { |
||
382 | *format = GL_RGBA; |
||
383 | } |
||
384 | else { |
||
385 | /* not implemented */ |
||
386 | fprintf(stderr, |
||
387 | "Error in LoadRGBImage %d-component images not implemented\n", |
||
388 | image->components ); |
||
389 | FreeImage(image); |
||
390 | return NULL; |
||
391 | } |
||
392 | |||
393 | *width = image->sizeX; |
||
394 | *height = image->sizeY; |
||
395 | |||
396 | bytes = image->sizeX * image->sizeY * image->components; |
||
397 | buffer = (GLubyte *) malloc(bytes); |
||
398 | if (!buffer) { |
||
399 | FreeImage(image); |
||
400 | return NULL; |
||
401 | } |
||
402 | |||
403 | memcpy( (void *) buffer, (void *) image->data, bytes ); |
||
404 | |||
405 | FreeImage(image); |
||
406 | |||
407 | return buffer; |
||
408 | } |
||
409 | |||
410 | #define CLAMP( X, MIN, MAX ) ( (X)<(MIN) ? (MIN) : ((X)>(MAX) ? (MAX) : (X)) ) |
||
411 | |||
412 | |||
413 | static void ConvertRGBtoYUV(GLint w, GLint h, GLint texel_bytes, |
||
414 | const GLubyte *src, |
||
415 | GLushort *dest) |
||
416 | { |
||
417 | GLint i, j; |
||
418 | |||
419 | for (i = 0; i < h; i++) { |
||
420 | for (j = 0; j < w; j++) { |
||
421 | const GLfloat r = (src[0]) / 255.0; |
||
422 | const GLfloat g = (src[1]) / 255.0; |
||
423 | const GLfloat b = (src[2]) / 255.0; |
||
424 | GLfloat y, cr, cb; |
||
425 | GLint iy, icr, icb; |
||
426 | |||
427 | y = r * 65.481 + g * 128.553 + b * 24.966 + 16; |
||
428 | cb = r * -37.797 + g * -74.203 + b * 112.0 + 128; |
||
429 | cr = r * 112.0 + g * -93.786 + b * -18.214 + 128; |
||
430 | /*printf("%f %f %f -> %f %f %f\n", r, g, b, y, cb, cr);*/ |
||
431 | iy = (GLint) CLAMP(y, 0, 254); |
||
432 | icb = (GLint) CLAMP(cb, 0, 254); |
||
433 | icr = (GLint) CLAMP(cr, 0, 254); |
||
434 | |||
435 | if (j & 1) { |
||
436 | /* odd */ |
||
437 | *dest = (iy << 8) | icr; |
||
438 | } |
||
439 | else { |
||
440 | /* even */ |
||
441 | *dest = (iy << 8) | icb; |
||
442 | } |
||
443 | dest++; |
||
444 | src += texel_bytes; |
||
445 | } |
||
446 | } |
||
447 | } |
||
448 | |||
449 | |||
450 | /* |
||
451 | * Load an SGI .rgb file and return a pointer to the image data, converted |
||
452 | * to 422 yuv. |
||
453 | * |
||
454 | * Input: imageFile - name of .rgb to read |
||
455 | * Output: width - width of image |
||
456 | * height - height of image |
||
457 | * Return: pointer to image data or NULL if error |
||
458 | */ |
||
459 | GLushort *LoadYUVImage( const char *imageFile, GLint *width, GLint *height ) |
||
460 | { |
||
461 | TK_RGBImageRec *image; |
||
462 | GLushort *buffer; |
||
463 | |||
464 | image = tkRGBImageLoad( imageFile ); |
||
465 | if (!image) { |
||
466 | return NULL; |
||
467 | } |
||
468 | |||
469 | if (image->components != 3 && image->components !=4 ) { |
||
470 | /* not implemented */ |
||
471 | fprintf(stderr, |
||
472 | "Error in LoadYUVImage %d-component images not implemented\n", |
||
473 | image->components ); |
||
474 | FreeImage(image); |
||
475 | return NULL; |
||
476 | } |
||
477 | |||
478 | *width = image->sizeX; |
||
479 | *height = image->sizeY; |
||
480 | |||
481 | buffer = (GLushort *) malloc( image->sizeX * image->sizeY * 2 ); |
||
482 | |||
483 | if (buffer) |
||
484 | ConvertRGBtoYUV( image->sizeX, |
||
485 | image->sizeY, |
||
486 | image->components, |
||
487 | image->data, |
||
488 | buffer ); |
||
489 | |||
490 | |||
491 | FreeImage(image); |
||
492 | return buffer; |
||
493 | }><>><>>>(MIN)>>>><>><>><>><> |
||
494 |