132001f49Smrg/* readtex.c */
232001f49Smrg
332001f49Smrg/*
432001f49Smrg * Read an SGI .rgb image file and generate a mipmap texture set.
532001f49Smrg * Much of this code was borrowed from SGI's tk OpenGL toolkit.
632001f49Smrg */
732001f49Smrg
832001f49Smrg
932001f49Smrg
1032001f49Smrg#include "gl_wrap.h"
1132001f49Smrg#include <assert.h>
1232001f49Smrg#include <stdio.h>
1332001f49Smrg#include <stdlib.h>
1432001f49Smrg#include <string.h>
1532001f49Smrg#include "readtex.h"
1632001f49Smrg
1732001f49Smrg
1832001f49Smrg#ifndef SEEK_SET
1932001f49Smrg#  define SEEK_SET 0
2032001f49Smrg#endif
2132001f49Smrg
2232001f49Smrg
2332001f49Smrg/*
2432001f49Smrg** RGB Image Structure
2532001f49Smrg*/
2632001f49Smrg
2732001f49Smrgtypedef struct _TK_RGBImageRec {
2832001f49Smrg   GLint sizeX, sizeY;
2932001f49Smrg   GLint components;
3032001f49Smrg   unsigned char *data;
3132001f49Smrg} TK_RGBImageRec;
3232001f49Smrg
3332001f49Smrg
3432001f49Smrg
3532001f49Smrg/******************************************************************************/
3632001f49Smrg
3732001f49Smrgtypedef struct _rawImageRec {
3832001f49Smrg    unsigned short imagic;
3932001f49Smrg    unsigned short type;
4032001f49Smrg    unsigned short dim;
4132001f49Smrg    unsigned short sizeX, sizeY, sizeZ;
4232001f49Smrg    unsigned long min, max;
4332001f49Smrg    unsigned long wasteBytes;
4432001f49Smrg    char name[80];
4532001f49Smrg    unsigned long colorMap;
4632001f49Smrg    FILE *file;
4732001f49Smrg    unsigned char *tmp, *tmpR, *tmpG, *tmpB, *tmpA;
4832001f49Smrg    unsigned long rleEnd;
4932001f49Smrg    GLuint *rowStart;
5032001f49Smrg    GLint *rowSize;
5132001f49Smrg} rawImageRec;
5232001f49Smrg
5332001f49Smrg/******************************************************************************/
5432001f49Smrg
5532001f49Smrgstatic void ConvertShort(unsigned short *array, long length)
5632001f49Smrg{
5732001f49Smrg   unsigned long b1, b2;
5832001f49Smrg   unsigned char *ptr;
5932001f49Smrg
6032001f49Smrg   ptr = (unsigned char *)array;
6132001f49Smrg   while (length--) {
6232001f49Smrg      b1 = *ptr++;
6332001f49Smrg      b2 = *ptr++;
6432001f49Smrg      *array++ = (unsigned short) ((b1 << 8) | (b2));
6532001f49Smrg   }
6632001f49Smrg}
6732001f49Smrg
6832001f49Smrgstatic void ConvertLong(GLuint *array, long length)
6932001f49Smrg{
7032001f49Smrg   unsigned long b1, b2, b3, b4;
7132001f49Smrg   unsigned char *ptr;
7232001f49Smrg
7332001f49Smrg   ptr = (unsigned char *)array;
7432001f49Smrg   while (length--) {
7532001f49Smrg      b1 = *ptr++;
7632001f49Smrg      b2 = *ptr++;
7732001f49Smrg      b3 = *ptr++;
7832001f49Smrg      b4 = *ptr++;
7932001f49Smrg      *array++ = (b1 << 24) | (b2 << 16) | (b3 << 8) | (b4);
8032001f49Smrg   }
8132001f49Smrg}
8232001f49Smrg
8332001f49Smrgstatic rawImageRec *RawImageOpen(const char *fileName)
8432001f49Smrg{
8532001f49Smrg   union {
8632001f49Smrg      int testWord;
8732001f49Smrg      char testByte[4];
8832001f49Smrg   } endianTest;
8932001f49Smrg   rawImageRec *raw;
9032001f49Smrg   GLenum swapFlag;
9132001f49Smrg   int x;
9232001f49Smrg   size_t result;
9332001f49Smrg
9432001f49Smrg   endianTest.testWord = 1;
9532001f49Smrg   if (endianTest.testByte[0] == 1) {
9632001f49Smrg      swapFlag = GL_TRUE;
9732001f49Smrg   } else {
9832001f49Smrg      swapFlag = GL_FALSE;
9932001f49Smrg   }
10032001f49Smrg
10132001f49Smrg   raw = (rawImageRec *)calloc(1, sizeof(rawImageRec));
10232001f49Smrg   if (raw == NULL) {
10332001f49Smrg      fprintf(stderr, "Out of memory!\n");
10432001f49Smrg      return NULL;
10532001f49Smrg   }
10632001f49Smrg   raw->file = fopen(fileName, "rb");
10732001f49Smrg   if (raw->file == NULL) {
10832001f49Smrg      const char *baseName = strrchr(fileName, '/');
10932001f49Smrg      if(baseName)
11032001f49Smrg         raw->file = fopen(baseName + 1, "rb");
11132001f49Smrg      if(raw->file == NULL) {
11232001f49Smrg         perror(fileName);
11332001f49Smrg         free(raw);
11432001f49Smrg         return NULL;
11532001f49Smrg      }
11632001f49Smrg   }
11732001f49Smrg
11832001f49Smrg   result = fread(raw, 1, 12, raw->file);
11932001f49Smrg   assert(result == 12);
12032001f49Smrg
12132001f49Smrg   if (swapFlag) {
12232001f49Smrg      ConvertShort(&raw->imagic, 1);
12332001f49Smrg      ConvertShort(&raw->type, 1);
12432001f49Smrg      ConvertShort(&raw->dim, 1);
12532001f49Smrg      ConvertShort(&raw->sizeX, 1);
12632001f49Smrg      ConvertShort(&raw->sizeY, 1);
12732001f49Smrg      ConvertShort(&raw->sizeZ, 1);
12832001f49Smrg   }
12932001f49Smrg
13032001f49Smrg   raw->tmp = (unsigned char *)malloc(raw->sizeX*256);
13132001f49Smrg   raw->tmpR = (unsigned char *)malloc(raw->sizeX*256);
13232001f49Smrg   raw->tmpG = (unsigned char *)malloc(raw->sizeX*256);
13332001f49Smrg   raw->tmpB = (unsigned char *)malloc(raw->sizeX*256);
13432001f49Smrg   if (raw->sizeZ==4) {
13532001f49Smrg      raw->tmpA = (unsigned char *)malloc(raw->sizeX*256);
13632001f49Smrg   }
13732001f49Smrg   if (raw->tmp == NULL || raw->tmpR == NULL || raw->tmpG == NULL ||
13832001f49Smrg       raw->tmpB == NULL) {
13932001f49Smrg      fprintf(stderr, "Out of memory!\n");
14032001f49Smrg      free(raw->tmp);
14132001f49Smrg      free(raw->tmpR);
14232001f49Smrg      free(raw->tmpG);
14332001f49Smrg      free(raw->tmpB);
14432001f49Smrg      free(raw->tmpA);
14532001f49Smrg      free(raw);
14632001f49Smrg      return NULL;
14732001f49Smrg   }
14832001f49Smrg
14932001f49Smrg   if ((raw->type & 0xFF00) == 0x0100) {
15032001f49Smrg      x = raw->sizeY * raw->sizeZ * sizeof(GLuint);
15132001f49Smrg      raw->rowStart = (GLuint *)malloc(x);
15232001f49Smrg      raw->rowSize = (GLint *)malloc(x);
15332001f49Smrg      if (raw->rowStart == NULL || raw->rowSize == NULL) {
15432001f49Smrg         fprintf(stderr, "Out of memory!\n");
15532001f49Smrg         free(raw->tmp);
15632001f49Smrg         free(raw->tmpR);
15732001f49Smrg         free(raw->tmpG);
15832001f49Smrg         free(raw->tmpB);
15932001f49Smrg         free(raw->tmpA);
16032001f49Smrg         free(raw->rowStart);
16132001f49Smrg         free(raw->rowSize);
16232001f49Smrg         free(raw);
16332001f49Smrg         return NULL;
16432001f49Smrg      }
16532001f49Smrg      raw->rleEnd = 512 + (2 * x);
16632001f49Smrg      fseek(raw->file, 512, SEEK_SET);
16732001f49Smrg      result = fread(raw->rowStart, 1, x, raw->file);
16832001f49Smrg      assert(result == x);
16932001f49Smrg      result = fread(raw->rowSize, 1, x, raw->file);
17032001f49Smrg      assert(result == x);
17132001f49Smrg      if (swapFlag) {
17232001f49Smrg         ConvertLong(raw->rowStart, (long) (x/sizeof(GLuint)));
17332001f49Smrg         ConvertLong((GLuint *)raw->rowSize, (long) (x/sizeof(GLint)));
17432001f49Smrg      }
17532001f49Smrg   }
17632001f49Smrg   return raw;
17732001f49Smrg}
17832001f49Smrg
17932001f49Smrgstatic void RawImageClose(rawImageRec *raw)
18032001f49Smrg{
18132001f49Smrg   fclose(raw->file);
18232001f49Smrg   free(raw->tmp);
18332001f49Smrg   free(raw->tmpR);
18432001f49Smrg   free(raw->tmpG);
18532001f49Smrg   free(raw->tmpB);
18632001f49Smrg   if (raw->rowStart)
18732001f49Smrg      free(raw->rowStart);
18832001f49Smrg   if (raw->rowSize)
18932001f49Smrg      free(raw->rowSize);
19032001f49Smrg   if (raw->sizeZ>3) {
19132001f49Smrg      free(raw->tmpA);
19232001f49Smrg   }
19332001f49Smrg   free(raw);
19432001f49Smrg}
19532001f49Smrg
19632001f49Smrgstatic void RawImageGetRow(rawImageRec *raw, unsigned char *buf, int y, int z)
19732001f49Smrg{
19832001f49Smrg   unsigned char *iPtr, *oPtr, pixel;
19932001f49Smrg   int count, done = 0;
20032001f49Smrg   size_t result;
20132001f49Smrg
20232001f49Smrg   if ((raw->type & 0xFF00) == 0x0100) {
20332001f49Smrg      fseek(raw->file, (long) raw->rowStart[y+z*raw->sizeY], SEEK_SET);
20432001f49Smrg      result = fread(raw->tmp, 1, (unsigned int)raw->rowSize[y+z*raw->sizeY],
20532001f49Smrg                     raw->file);
20632001f49Smrg      assert(result == (unsigned int)raw->rowSize[y+z*raw->sizeY]);
20732001f49Smrg
20832001f49Smrg      iPtr = raw->tmp;
20932001f49Smrg      oPtr = buf;
21032001f49Smrg      while (!done) {
21132001f49Smrg         pixel = *iPtr++;
21232001f49Smrg         count = (int)(pixel & 0x7F);
21332001f49Smrg         if (!count) {
21432001f49Smrg			 done = 1;
21532001f49Smrg            return;
21632001f49Smrg         }
21732001f49Smrg         if (pixel & 0x80) {
21832001f49Smrg            while (count--) {
21932001f49Smrg               *oPtr++ = *iPtr++;
22032001f49Smrg            }
22132001f49Smrg         } else {
22232001f49Smrg            pixel = *iPtr++;
22332001f49Smrg            while (count--) {
22432001f49Smrg               *oPtr++ = pixel;
22532001f49Smrg            }
22632001f49Smrg         }
22732001f49Smrg      }
22832001f49Smrg   } else {
22932001f49Smrg      fseek(raw->file, 512+(y*raw->sizeX)+(z*raw->sizeX*raw->sizeY),
23032001f49Smrg            SEEK_SET);
23132001f49Smrg      result = fread(buf, 1, raw->sizeX, raw->file);
23232001f49Smrg      assert(result == raw->sizeX);
23332001f49Smrg   }
23432001f49Smrg}
23532001f49Smrg
23632001f49Smrg
23732001f49Smrgstatic void RawImageGetData(rawImageRec *raw, TK_RGBImageRec *final)
23832001f49Smrg{
23932001f49Smrg   unsigned char *ptr;
24032001f49Smrg   int i, j;
24132001f49Smrg
24232001f49Smrg   final->data = (unsigned char *)malloc((raw->sizeX+1)*(raw->sizeY+1)*4);
24332001f49Smrg   if (final->data == NULL) {
24432001f49Smrg      fprintf(stderr, "Out of memory!\n");
24532001f49Smrg      return;
24632001f49Smrg   }
24732001f49Smrg
24832001f49Smrg   ptr = final->data;
24932001f49Smrg   for (i = 0; i < (int)(raw->sizeY); i++) {
25032001f49Smrg      RawImageGetRow(raw, raw->tmpR, i, 0);
25132001f49Smrg      RawImageGetRow(raw, raw->tmpG, i, 1);
25232001f49Smrg      RawImageGetRow(raw, raw->tmpB, i, 2);
25332001f49Smrg      if (raw->sizeZ>3) {
25432001f49Smrg         RawImageGetRow(raw, raw->tmpA, i, 3);
25532001f49Smrg      }
25632001f49Smrg      for (j = 0; j < (int)(raw->sizeX); j++) {
25732001f49Smrg         *ptr++ = *(raw->tmpR + j);
25832001f49Smrg         *ptr++ = *(raw->tmpG + j);
25932001f49Smrg         *ptr++ = *(raw->tmpB + j);
26032001f49Smrg         if (raw->sizeZ>3) {
26132001f49Smrg            *ptr++ = *(raw->tmpA + j);
26232001f49Smrg         }
26332001f49Smrg      }
26432001f49Smrg   }
26532001f49Smrg}
26632001f49Smrg
26732001f49Smrg
26832001f49Smrgstatic TK_RGBImageRec *tkRGBImageLoad(const char *fileName)
26932001f49Smrg{
27032001f49Smrg   rawImageRec *raw;
27132001f49Smrg   TK_RGBImageRec *final;
27232001f49Smrg
27332001f49Smrg   raw = RawImageOpen(fileName);
27432001f49Smrg   if (!raw) {
27532001f49Smrg      fprintf(stderr, "File not found\n");
27632001f49Smrg      return NULL;
27732001f49Smrg   }
27832001f49Smrg   final = (TK_RGBImageRec *)malloc(sizeof(TK_RGBImageRec));
27932001f49Smrg   if (final == NULL) {
28032001f49Smrg      fprintf(stderr, "Out of memory!\n");
28132001f49Smrg      RawImageClose(raw);
28232001f49Smrg      return NULL;
28332001f49Smrg   }
28432001f49Smrg   final->sizeX = raw->sizeX;
28532001f49Smrg   final->sizeY = raw->sizeY;
28632001f49Smrg   final->components = raw->sizeZ;
28732001f49Smrg   RawImageGetData(raw, final);
28832001f49Smrg   RawImageClose(raw);
28932001f49Smrg   return final;
29032001f49Smrg}
29132001f49Smrg
29232001f49Smrg
29332001f49Smrgstatic void FreeImage( TK_RGBImageRec *image )
29432001f49Smrg{
29532001f49Smrg   free(image->data);
29632001f49Smrg   free(image);
29732001f49Smrg}
29832001f49Smrg
29932001f49Smrg
30032001f49Smrg/*
30132001f49Smrg * Load an SGI .rgb file and generate a set of 2-D mipmaps from it.
30232001f49Smrg * Input:  imageFile - name of .rgb to read
30332001f49Smrg *         intFormat - internal texture format to use, or number of components
30432001f49Smrg * Return:  GL_TRUE if success, GL_FALSE if error.
30532001f49Smrg */
30632001f49SmrgGLboolean LoadRGBMipmaps( const char *imageFile, GLint intFormat )
30732001f49Smrg{
30832001f49Smrg   GLint w, h;
30932001f49Smrg   return LoadRGBMipmaps2( imageFile, GL_TEXTURE_2D, intFormat, &w, &h );
31032001f49Smrg}
31132001f49Smrg
31232001f49Smrg
31332001f49Smrg
31432001f49SmrgGLboolean LoadRGBMipmaps2( const char *imageFile, GLenum target,
31532001f49Smrg                           GLint intFormat, GLint *width, GLint *height )
31632001f49Smrg{
31732001f49Smrg   GLint error;
31832001f49Smrg   GLenum format;
31932001f49Smrg   TK_RGBImageRec *image;
32032001f49Smrg
32132001f49Smrg   image = tkRGBImageLoad( imageFile );
32232001f49Smrg   if (!image) {
32332001f49Smrg      return GL_FALSE;
32432001f49Smrg   }
32532001f49Smrg
32632001f49Smrg   if (image->components==3) {
32732001f49Smrg      format = GL_RGB;
32832001f49Smrg   }
32932001f49Smrg   else if (image->components==4) {
33032001f49Smrg      format = GL_RGBA;
33132001f49Smrg   }
33232001f49Smrg   else {
33332001f49Smrg      /* not implemented */
33432001f49Smrg      fprintf(stderr,
33532001f49Smrg              "Error in LoadRGBMipmaps %d-component images not implemented\n",
33632001f49Smrg              image->components );
33732001f49Smrg      FreeImage(image);
33832001f49Smrg      return GL_FALSE;
33932001f49Smrg   }
34032001f49Smrg
34132001f49Smrg   error = gluBuild2DMipmaps( target,
34232001f49Smrg                              intFormat,
34332001f49Smrg                              image->sizeX, image->sizeY,
34432001f49Smrg                              format,
34532001f49Smrg                              GL_UNSIGNED_BYTE,
34632001f49Smrg                              image->data );
34732001f49Smrg
34832001f49Smrg   *width = image->sizeX;
34932001f49Smrg   *height = image->sizeY;
35032001f49Smrg
35132001f49Smrg   FreeImage(image);
35232001f49Smrg
35332001f49Smrg   return error ? GL_FALSE : GL_TRUE;
35432001f49Smrg}
35532001f49Smrg
35632001f49Smrg
35732001f49Smrg
35832001f49Smrg/*
35932001f49Smrg * Load an SGI .rgb file and return a pointer to the image data.
36032001f49Smrg * Input:  imageFile - name of .rgb to read
36132001f49Smrg * Output:  width - width of image
36232001f49Smrg *          height - height of image
36332001f49Smrg *          format - format of image (GL_RGB or GL_RGBA)
36432001f49Smrg * Return:  pointer to image data or NULL if error
36532001f49Smrg */
36632001f49SmrgGLubyte *LoadRGBImage( const char *imageFile, GLint *width, GLint *height,
36732001f49Smrg                       GLenum *format )
36832001f49Smrg{
36932001f49Smrg   TK_RGBImageRec *image;
37032001f49Smrg   GLint bytes;
37132001f49Smrg   GLubyte *buffer;
37232001f49Smrg
37332001f49Smrg   image = tkRGBImageLoad( imageFile );
37432001f49Smrg   if (!image) {
37532001f49Smrg      return NULL;
37632001f49Smrg   }
37732001f49Smrg
37832001f49Smrg   if (image->components==3) {
37932001f49Smrg      *format = GL_RGB;
38032001f49Smrg   }
38132001f49Smrg   else if (image->components==4) {
38232001f49Smrg      *format = GL_RGBA;
38332001f49Smrg   }
38432001f49Smrg   else {
38532001f49Smrg      /* not implemented */
38632001f49Smrg      fprintf(stderr,
38732001f49Smrg              "Error in LoadRGBImage %d-component images not implemented\n",
38832001f49Smrg              image->components );
38932001f49Smrg      FreeImage(image);
39032001f49Smrg      return NULL;
39132001f49Smrg   }
39232001f49Smrg
39332001f49Smrg   *width = image->sizeX;
39432001f49Smrg   *height = image->sizeY;
39532001f49Smrg
39632001f49Smrg   bytes = image->sizeX * image->sizeY * image->components;
39732001f49Smrg   buffer = (GLubyte *) malloc(bytes);
39832001f49Smrg   if (!buffer) {
39932001f49Smrg      FreeImage(image);
40032001f49Smrg      return NULL;
40132001f49Smrg   }
40232001f49Smrg
40332001f49Smrg   memcpy( (void *) buffer, (void *) image->data, bytes );
40432001f49Smrg
40532001f49Smrg   FreeImage(image);
40632001f49Smrg
40732001f49Smrg   return buffer;
40832001f49Smrg}
40932001f49Smrg
41032001f49Smrg#define CLAMP( X, MIN, MAX )  ( (X)<(MIN) ? (MIN) : ((X)>(MAX) ? (MAX) : (X)) )
41132001f49Smrg
41232001f49Smrg
41332001f49Smrgstatic void ConvertRGBtoYUV(GLint w, GLint h, GLint texel_bytes,
41432001f49Smrg			    const GLubyte *src,
41532001f49Smrg                            GLushort *dest)
41632001f49Smrg{
41732001f49Smrg   GLint i, j;
41832001f49Smrg
41932001f49Smrg   for (i = 0; i < h; i++) {
42032001f49Smrg      for (j = 0; j < w; j++) {
42132001f49Smrg         const GLfloat r = (src[0]) / 255.0;
42232001f49Smrg         const GLfloat g = (src[1]) / 255.0;
42332001f49Smrg         const GLfloat b = (src[2]) / 255.0;
42432001f49Smrg         GLfloat y, cr, cb;
42532001f49Smrg         GLint iy, icr, icb;
42632001f49Smrg
42732001f49Smrg         y  = r * 65.481 + g * 128.553 + b * 24.966 + 16;
42832001f49Smrg         cb = r * -37.797 + g * -74.203 + b * 112.0 + 128;
42932001f49Smrg         cr = r * 112.0 + g * -93.786 + b * -18.214 + 128;
43032001f49Smrg         /*printf("%f %f %f -> %f %f %f\n", r, g, b, y, cb, cr);*/
43132001f49Smrg         iy  = (GLint) CLAMP(y,  0, 254);
43232001f49Smrg         icb = (GLint) CLAMP(cb, 0, 254);
43332001f49Smrg         icr = (GLint) CLAMP(cr, 0, 254);
43432001f49Smrg
43532001f49Smrg         if (j & 1) {
43632001f49Smrg            /* odd */
43732001f49Smrg            *dest = (iy << 8) | icr;
43832001f49Smrg         }
43932001f49Smrg         else {
44032001f49Smrg            /* even */
44132001f49Smrg            *dest = (iy << 8) | icb;
44232001f49Smrg         }
44332001f49Smrg         dest++;
44432001f49Smrg	 src += texel_bytes;
44532001f49Smrg      }
44632001f49Smrg   }
44732001f49Smrg}
44832001f49Smrg
44932001f49Smrg
45032001f49Smrg/*
45132001f49Smrg * Load an SGI .rgb file and return a pointer to the image data, converted
45232001f49Smrg * to 422 yuv.
45332001f49Smrg *
45432001f49Smrg * Input:  imageFile - name of .rgb to read
45532001f49Smrg * Output:  width - width of image
45632001f49Smrg *          height - height of image
45732001f49Smrg * Return:  pointer to image data or NULL if error
45832001f49Smrg */
45932001f49SmrgGLushort *LoadYUVImage( const char *imageFile, GLint *width, GLint *height )
46032001f49Smrg{
46132001f49Smrg   TK_RGBImageRec *image;
46232001f49Smrg   GLushort *buffer;
46332001f49Smrg
46432001f49Smrg   image = tkRGBImageLoad( imageFile );
46532001f49Smrg   if (!image) {
46632001f49Smrg      return NULL;
46732001f49Smrg   }
46832001f49Smrg
46932001f49Smrg   if (image->components != 3 && image->components !=4 ) {
47032001f49Smrg      /* not implemented */
47132001f49Smrg      fprintf(stderr,
47232001f49Smrg              "Error in LoadYUVImage %d-component images not implemented\n",
47332001f49Smrg              image->components );
47432001f49Smrg      FreeImage(image);
47532001f49Smrg      return NULL;
47632001f49Smrg   }
47732001f49Smrg
47832001f49Smrg   *width = image->sizeX;
47932001f49Smrg   *height = image->sizeY;
48032001f49Smrg
48132001f49Smrg   buffer = (GLushort *) malloc( image->sizeX * image->sizeY * 2 );
48232001f49Smrg
48332001f49Smrg   if (buffer)
48432001f49Smrg      ConvertRGBtoYUV( image->sizeX,
48532001f49Smrg		       image->sizeY,
48632001f49Smrg		       image->components,
48732001f49Smrg		       image->data,
48832001f49Smrg		       buffer );
48932001f49Smrg
49032001f49Smrg
49132001f49Smrg   FreeImage(image);
49232001f49Smrg   return buffer;
49332001f49Smrg}
49432001f49Smrg
495