/*==========================================================
  File:  tga.c
  Author:  unknown

  Description:  Gets TGA data from a TGA image file.

  Note:  I obtained this from somewhere on the OpenGL website
         and modified it to fit my needs.
  ==========================================================*/


#include <stdio.h>
#include <stdlib.h>
#include <math.h>

#include "tga.h"
#include "util.h"

/*
   The following is rather crude demonstration code to read 
   uncompressed and compressed TGA files of 16, 24, or 32 bit 
   TGA. 
   Hope it is helpful.
*/


unsigned char *TGA_getData(char *filenameint *wint *h)
{
   int n=0,i,j;
   unsigned int bytes2read,skipover = 0;
   unsigned char p[5];
   FILE *fptr;
   TGA_HEADER header;
   TGA_PIXEL *pixels;
   unsigned char *data;

   if(!filenamereturn 0;

   if ((fptr = fopen(filename,"r")) == NULL)
     return 0;

   /* Display the header fields */
   header.idlength = fgetc(fptr);
   header.colourmaptype = fgetc(fptr);
   header.datatypecode = fgetc(fptr);
   fread(&header.colourmaporigin,2,1,fptr);
   fread(&header.colourmaplength,2,1,fptr);
   header.colourmapdepth = fgetc(fptr);
   fread(&header.x_origin,2,1,fptr);
   fread(&header.y_origin,2,1,fptr);
   fread(&header.width,2,1,fptr);
   fread(&header.height,2,1,fptr);
   header.bitsperpixel = fgetc(fptr);
   header.imagedescriptor = fgetc(fptr);

   /* Allocate space for the image */
   if ((pixels = malloc(header.width*header.height*sizeof(TGA_PIXEL))) == NULL) {
      fclose(fptr);
      perror("TGA_getData malloc");
      return 0;
   }
   for (i=0;i<header.width*header.height;i++) {
      pixels[i].r = 0;
      pixels[i].g = 0;
      pixels[i].b = 0;
      pixels[i].a = 0;
   }

   /* What can we handle */
   if (header.datatypecode != 2 && header.datatypecode != 10) {
     fclose(fptr);
     free(pixels);
     return 0;
   }

   if (header.bitsperpixel != 16 && 
       header.bitsperpixel != 24 && header.bitsperpixel != 32) {
     fclose(fptr);
     free(pixels);
     return 0;
   }
   if (header.colourmaptype != 0 && header.colourmaptype != 1) {
     fclose(fptr);
     free(pixels);
     return 0;
   }

   /* Skip over unnecessary stuff */
   skipover += header.idlength;
   skipover += header.colourmaptype * header.colourmaplength;
   fseek(fptr,skipover,SEEK_CUR);

   /* Read the image */
   bytes2read = header.bitsperpixel / 8;
   while (n < header.width * header.height) {
      if (header.datatypecode == 2) {                     /* Uncompressed */
         if (fread(p,1,bytes2read,fptr) != bytes2read) {
            fprintf(stderr,"TGA_getData: Unexpected end of file at pixel %d\n",i);
            free(pixels);
            fclose(fptr);
            return 0;
         }
         MergeBytes(&(pixels[n]),p,bytes2read);
         n++;
      } else if (header.datatypecode == 10) {             /* Compressed */
         if (fread(p,1,bytes2read+1,fptr) != bytes2read+1) {
            fprintf(stderr,"TGA_getData: Unexpected end of file at pixel %d\n",i);
            free(pixels);
            fclose(fptr);
            return 0;
         }
         j = p[0] & 0x7f;
         MergeBytes(&(pixels[n]),&(p[1]),bytes2read);
         n++;
         if (p[0] & 0x80) {         /* RLE chunk */
            for (i=0;i<j;i++) {
               MergeBytes(&(pixels[n]),&(p[1]),bytes2read);
               n++;
            }
         } else {                   /* Normal chunk */
            for (i=0;i<j;i++) {
               if (fread(p,1,bytes2read,fptr) != bytes2read) {
                  fprintf(stderr,"TGA_loadData: Unexpected end of file at pixel %d\n",i);
                  free(pixels);
                  fclose(fptr);
                  return 0;
               }
               MergeBytes(&(pixels[n]),p,bytes2read);
               n++;
            }
         }
      }
   }
   fclose(fptr);

   data=(unsigned char *)malloc(header.height * header.width * 4);

   for (i=0,n=0;i<header.height*header.width;i++) 
   {
      data[n++] = pixels[i].r;
      data[n++] = pixels[i].g;
      data[n++] = pixels[i].b;
      data[n++] = pixels[i].a;
   }

   free(pixels);
   *w=header.width;
   *h=header.height;
   return data;
}

void MergeBytes(TGA_PIXEL *pixel,unsigned char *p,int bytes)
{
   if (bytes == 4) {
      pixel->r = p[2];
      pixel->g = p[1];
      pixel->b = p[0];
      pixel->a = p[4];
   } else if (bytes == 3) {
      pixel->r = p[2];
      pixel->g = p[1];
      pixel->b = p[0];
      pixel->a = 0;
   } else if (bytes == 2) {
      pixel->r = (p[1] & 0x7c) << 1;
      pixel->g = ((p[1] & 0x03) << 6) | ((p[0] & 0xe0) >> 2);
      pixel->b = (p[0] & 0x1f) << 3;
      pixel->a = (p[1] & 0x80);
   }
}