readtex.c revision 32001f49
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 "gl_wrap.h" 11#include <assert.h> 12#include <stdio.h> 13#include <stdlib.h> 14#include <string.h> 15#include "readtex.h" 16 17 18#ifndef SEEK_SET 19# define SEEK_SET 0 20#endif 21 22 23/* 24** RGB Image Structure 25*/ 26 27typedef struct _TK_RGBImageRec { 28 GLint sizeX, sizeY; 29 GLint components; 30 unsigned char *data; 31} TK_RGBImageRec; 32 33 34 35/******************************************************************************/ 36 37typedef struct _rawImageRec { 38 unsigned short imagic; 39 unsigned short type; 40 unsigned short dim; 41 unsigned short sizeX, sizeY, sizeZ; 42 unsigned long min, max; 43 unsigned long wasteBytes; 44 char name[80]; 45 unsigned long colorMap; 46 FILE *file; 47 unsigned char *tmp, *tmpR, *tmpG, *tmpB, *tmpA; 48 unsigned long rleEnd; 49 GLuint *rowStart; 50 GLint *rowSize; 51} rawImageRec; 52 53/******************************************************************************/ 54 55static void ConvertShort(unsigned short *array, long length) 56{ 57 unsigned long b1, b2; 58 unsigned char *ptr; 59 60 ptr = (unsigned char *)array; 61 while (length--) { 62 b1 = *ptr++; 63 b2 = *ptr++; 64 *array++ = (unsigned short) ((b1 << 8) | (b2)); 65 } 66} 67 68static void ConvertLong(GLuint *array, long length) 69{ 70 unsigned long b1, b2, b3, b4; 71 unsigned char *ptr; 72 73 ptr = (unsigned char *)array; 74 while (length--) { 75 b1 = *ptr++; 76 b2 = *ptr++; 77 b3 = *ptr++; 78 b4 = *ptr++; 79 *array++ = (b1 << 24) | (b2 << 16) | (b3 << 8) | (b4); 80 } 81} 82 83static rawImageRec *RawImageOpen(const char *fileName) 84{ 85 union { 86 int testWord; 87 char testByte[4]; 88 } endianTest; 89 rawImageRec *raw; 90 GLenum swapFlag; 91 int x; 92 size_t result; 93 94 endianTest.testWord = 1; 95 if (endianTest.testByte[0] == 1) { 96 swapFlag = GL_TRUE; 97 } else { 98 swapFlag = GL_FALSE; 99 } 100 101 raw = (rawImageRec *)calloc(1, sizeof(rawImageRec)); 102 if (raw == NULL) { 103 fprintf(stderr, "Out of memory!\n"); 104 return NULL; 105 } 106 raw->file = fopen(fileName, "rb"); 107 if (raw->file == NULL) { 108 const char *baseName = strrchr(fileName, '/'); 109 if(baseName) 110 raw->file = fopen(baseName + 1, "rb"); 111 if(raw->file == NULL) { 112 perror(fileName); 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 179static 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 196static 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 237static 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 268static 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 293static 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 */ 306GLboolean 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 314GLboolean 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 */ 366GLubyte *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 413static 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 */ 459GLushort *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} 494 495