Subversion Repositories Kolibri OS

Rev

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
}
494