                   Targaformat (pictures that ends with .tga)

Most paint programs support the targaformat, it's also a pretty simple format,
that's why I use it.
There isn't much to say, I'll show you the code and comment it.


First in every targafile there is a head that tells which type of targa image 
it is, width, height and some other data about the picture.
The head can be read into a struct like this:

struct TGAHdrType {
        short int       NumOfBytInId;
        short int       ColorMapType;
        short int       ImageTypeCode;
        unsigned int    ColorMapOrigin;
        unsigned int    ColorMapLength;
        short int       ColorMapEntrySize;
        unsigned int    XStart;
        unsigned int    YStart;
        unsigned int    Width;
        unsigned int    Height;
        short int       PixelSize;
        short int       ImageDescriptor;
        unsigned int    PaletteStart;
        unsigned int    DataStart;
};

This function reads the head from a file with name filename to a 
struct TGAHdrType (look above). Data is temporary stored in the buffer
char TGAHdrData[2048];

void read_TGAHdr(struct TGAHdrType * TGAHdr, char * filename)
{
   FILE *fs;

   if (!(fs = fopen(filename, "rb")))
          {
          printf("Can't open the file %s\n",filename);
          getch();
          exit(1);
          }

   if (fread(TGAHdrData, 786, 1, fs) != 1)
          {
          printf("Can't read the TGA-header");
          getch();
          exit(1);
          }

   TGAHdr->NumOfBytInId      = TGAHdrData[0];
   TGAHdr->ColorMapType      = TGAHdrData[1];
   TGAHdr->ImageTypeCode     = TGAHdrData[2];
   TGAHdr->ColorMapOrigin    = TGAHdrData[3]+256*TGAHdrData[4];
   TGAHdr->ColorMapLength    = TGAHdrData[5]+256*TGAHdrData[6];
   TGAHdr->ColorMapEntrySize = TGAHdrData[7];
   TGAHdr->XStart            = TGAHdrData[8]+256*TGAHdrData[9];
   TGAHdr->YStart            = TGAHdrData[10]+256*TGAHdrData[11];
   TGAHdr->Width             = TGAHdrData[12]+256*TGAHdrData[13];
   TGAHdr->Height            = TGAHdrData[14]+256*TGAHdrData[15];
   TGAHdr->PixelSize         = TGAHdrData[16];
   TGAHdr->ImageDescriptor   = TGAHdrData[17];
   TGAHdr->PaletteStart      = 18 + TGAHdr->NumOfBytInId;
   TGAHdr->DataStart         = 18 + TGAHdr->NumOfBytInId + 3 * TGAHdr->ColorMapLength;

   fclose(fs);
}


The function below reads the palette from TGAHdrData to the array pal.
void TGAHdr_to_pal_256(struct TGAHdrType TGAHdr,char*pal)
{
   int p; //looprknare
   int red, green, blue;        //r,g och b values vary between 0 - 255
                                //and in mode 13h r,g,b values
                                //vary between 0 - 63
                                //the values heve to be divided by 4

   for (p=0; p<256; p++)
   {
                red   = (TGAHdrData[TGAHdr.PaletteStart+2+(p*3)]);
                green = (TGAHdrData[TGAHdr.PaletteStart+1+(p*3)]);
                blue  = (TGAHdrData[TGAHdr.PaletteStart+0+(p*3)]);

                pal[p*3]=red>>2;         //Divide by four through shifting
                pal[p*3+1]=green>>2;
                pal[p*3+2]=blue>>2;
   }
}






The function below shows an uncompressed tga-image on the screen.
It takes a TGAHdr as parameter, that means the head has to be read before
calling this function.
There are 2 types of uncompressed TGA-images, one draws down-up
the other draws up-down. This function copes with both

void show_TGA_image_256_uncom(struct TGAHdrType TGAHdr, char * filename, int xpos, int ypos)
{
   int i, j, row; //loopcounter

   FILE *fs;

   if (!(fs = fopen(filename, "rb")))
          {
          printf("Can't open the file\n");
          exit(1);
          }

        // Sets the filepointer
        fseek(fs, TGAHdr.DataStart, SEEK_SET);

        if ((TGAHdr.ImageDescriptor&32)==32) {
                //draws down - up
                row=ypos;
                for (i=ypos; i<ypos+TGAHdr.Height; i++)
                {
                        //reads one row
                        fread(TGAHdrData, TGAHdr.Width, 1, fs);
                        //Draws the row
                        for (j=0; j < TGAHdr.Width; j++)
                        {
                                putpixel(xpos+j,i,TGAHdrData[j]);
                        }
                }
        }
        else {
                //Draws up-down
                row=ypos+TGAHdr.Height;
                for (i=row; i>row-TGAHdr.Height; i--)
                {
                        //Reads one row
                        fread(TGAHdrData, TGAHdr.Width, 1, fs);
                        //Draw the row
                        for (j=0; j < TGAHdr.Width; j++)
                        {
                                putpixel(xpos+j,i,TGAHdrData[j]);
                        }
                }
        }
        fclose(fs);
}



This function draws a rlecompressed tga image on the screen.
RLE stands for Run Length Encoding. In an RLE-encoded picture every pixel is
not one byte. One byte tells how many pixels in the same color is to follow.
The next byte tells which color it is.
void show_TGA_image_256_rle(struct TGAHdrType TGAHdr, char * filename, int xpos, int ypos)
{
        int row, kol, dir, i;
        char pakethdr;
        short int pakettyp;
        short int hdrnumber;
        short int rlecolor;

        FILE *fs;

        if (!(fs = fopen(filename, "rb")))
        {
                printf("Can't open the file\n");
                exit(1);
        }

        // Set the filepointer
        fseek(fs, TGAHdr.DataStart, SEEK_SET);

        //Begin in the upper left or lower right corner, check bit 5
        if ((TGAHdr.ImageDescriptor&32)==32) {
                row=ypos;
                dir=1;
        }
        else {
                row=ypos+TGAHdr.Height;
                dir=-1;
        }

        kol=0;

        while (!feof(fs)) {
                //read pakethdr
                fread(&pakethdr, 1, 1, fs);
                pakettyp = pakethdr&128;
                hdrnumber = pakethdr&127;
                if (pakettyp==0) {
                        //read raw_body
                        fread(TGAHdrData, hdrnumber+1, 1, fs);
                        //draw rhe package
                        for (i=0; i<hdrnumber+1; i++) {
                                putpixel(xpos+kol,row,TGAHdrData[i]);
                                kol++;
                                if ((kol%TGAHdr.Width==0) && (kol!=0)) {
                                        row=row+dir;
                                        kol=0;
                                }
                        }
                }
                else {
                        //read rle_body
                        fread(&rlecolor, 1, 1, fs);
                        //draw
                        for (i=0; i<hdrnumber+1; i++) {
                                putpixel(xpos+kol,row,rlecolor);
                                kol++;
                                if ((kol%TGAHdr.Width==0) && (kol!=0)) {
                                        row=row+dir;
                                        kol=0;
                                }
                        }
                }
        }
        fclose(fs);
}



This function shows a tga-picture on the screen and reads the pictures
palette to the array pal. Then you are free to do everything you want with 
the palette (ie set it);
In fittga the palette is used to compare with another palette which color
in it is closest to which pixel in the other palette.
This function only copes with 256colors-tga-images.
If you're using mode13h the picture should be <= 320*200 pixels
void ViewTgaNGetPal(char*image, unsigned char*pal)
{
        struct TGAHdrType TGAHdr;

        //Read the tgaheader
        read_TGAHdr(&TGAHdr,image);
        width=TGAHdr.Width;
        height=TGAHdr.Height;

        switch (TGAHdr.ImageTypeCode)
        {
                case 1:
                        TGAHdr_to_pal_256(TGAHdr,pal);
                        show_TGA_image_256_uncom(TGAHdr,image,0,0);
                        break;
                case 9:
                        TGAHdr_to_pal_256(TGAHdr,pal);
                        show_TGA_image_256_rle(TGAHdr,image,0,0);
                        break;

                default:
                        printf("\nI can't draw that targa format!!\n");
        }
}

This is an example of a mainprogram that uses the functions above
void main(void)
{
char pal[256*3];
char readname[40]="evildead.tga";

 setmode(0x0013);

 blackpal();            //set all colors to black so nothing will be shown
                        //while the picture is drawn
 ViewTgaNGetPal(readname,pal); //show the tga and get the palette
 setpal(pal);           //set the palette and the picture will appear
 getch();               //let the user admire the picture until he/she presses a key
 setmode(3);
}

I hope that by studying these functions you'll understand how the targa format
works.

Abe McCabe
1995-11-16

PS      
        The TGA-routines comes from Dr Dobbs Journal and have been tampered
        with by me and Thomas Larsson (http://www.mds.mdh.se/~dat93tln)
DS
