home *** CD-ROM | disk | FTP | other *** search
/ Chestnut's Multimedia Mania / MM_MANIA.ISO / graphics / povsrc20 / targa.c < prev    next >
C/C++ Source or Header  |  1993-07-29  |  16KB  |  582 lines

  1. /****************************************************************************
  2. *                targa.c
  3. *
  4. *  This module contains the code to read and write the Targa output file
  5. *  format.
  6. *
  7. *  from Persistence of Vision Raytracer
  8. *  Copyright 1993 Persistence of Vision Team
  9. *---------------------------------------------------------------------------
  10. *  NOTICE: This source code file is provided so that users may experiment
  11. *  with enhancements to POV-Ray and to port the software to platforms other 
  12. *  than those supported by the POV-Ray Team.  There are strict rules under
  13. *  which you are permitted to use this file.  The rules are in the file
  14. *  named POVLEGAL.DOC which should be distributed with this file. If 
  15. *  POVLEGAL.DOC is not available or for more info please contact the POV-Ray
  16. *  Team Coordinator by leaving a message in CompuServe's Graphics Developer's
  17. *  Forum.  The latest version of POV-Ray may be found there as well.
  18. *
  19. * This program is based on the popular DKB raytracer version 2.12.
  20. * DKBTrace was originally written by David K. Buck.
  21. * DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
  22. *
  23. *****************************************************************************/
  24.  
  25. #include "frame.h"
  26. #include "povproto.h"
  27.  
  28. static int Targa_Line_Number;
  29. static unsigned char idbuf[256];
  30.  
  31. extern int First_Line;
  32. static void convert_targa_color PARAMS((IMAGE_COLOUR *, int, unsigned char *));
  33.  
  34. FILE_HANDLE *Get_Targa_File_Handle()
  35.   {
  36.   FILE_HANDLE *handle;
  37.  
  38.   if ((handle = (FILE_HANDLE *) malloc(sizeof(FILE_HANDLE))) == NULL) 
  39.     {
  40.     fprintf (stderr, "Cannot allocate memory for output file handle\n");
  41.     return(NULL);
  42.     }
  43.  
  44.   handle->Default_File_Name_p = Default_Targa_File_Name;
  45.   handle->Open_File_p = Open_Targa_File;
  46.   handle->Write_Line_p = Write_Targa_Line;
  47.   handle->Read_Line_p = Read_Targa_Line;
  48.   handle->Read_Image_p = Read_Targa_Image;
  49.   handle->Close_File_p = Close_Targa_File;
  50.   handle->file = NULL;
  51.   handle->buffer_size = 0;
  52.   handle->buffer = NULL;
  53.   return (handle);
  54.   }
  55.  
  56. char *Default_Targa_File_Name()
  57.   {
  58.   return ("data.tga");
  59.   }
  60.  
  61. int Open_Targa_File (handle, name, width, height, buffer_size, mode)
  62. FILE_HANDLE *handle;
  63. char *name;
  64. int *width;
  65. int *height;
  66. int buffer_size;
  67. int mode;
  68.   {
  69.   int data1, data2, i;
  70.  
  71.   handle->mode = mode;
  72.   handle->filename = name;
  73.   Targa_Line_Number = 0;
  74.  
  75.   switch (mode) 
  76.   {
  77.   case READ_MODE:
  78.     if ((handle->file = fopen (name, READ_FILE_STRING)) == NULL)
  79.       return(0);
  80.  
  81.     if (buffer_size != 0) 
  82.       {
  83.       if ((handle->buffer = malloc (buffer_size)) == NULL)
  84.         return(0);
  85.  
  86.       setvbuf (handle->file, handle->buffer, _IOFBF, buffer_size);
  87.       }
  88.  
  89.     for (i = 0 ; i < 12 ; i++)
  90.       if (getc(handle->file) == EOF)
  91.         return(0);
  92.  
  93.     if (((data1 = getc(handle->file)) == EOF)
  94.       || ((data2 = getc(handle->file)) == EOF))
  95.       return(0);
  96.  
  97.     *width  = data2 * 256 + data1;
  98.  
  99.     if (((data1 = getc(handle->file)) == EOF)
  100.       || ((data2 = getc(handle->file)) == EOF))
  101.       return(0);
  102.  
  103.     for (i = 0 ; i < 2 ; i++)
  104.       if (getc(handle->file) == EOF)
  105.         return(0);
  106.  
  107.     *height = data2 * 256 + data1;
  108.     handle->width = *width;
  109.     handle->height = *height;
  110.     handle->buffer_size = buffer_size;
  111.     break;
  112.  
  113.   case WRITE_MODE:
  114.     if ((handle->file = fopen (name, WRITE_FILE_STRING)) == NULL)
  115.       return(0);
  116.  
  117.     if (buffer_size != 0) 
  118.       {
  119.       if ((handle->buffer = malloc (buffer_size)) == NULL)
  120.         return(0);
  121.  
  122.       setvbuf (handle->file, handle->buffer, _IOFBF, buffer_size);
  123.       }
  124.  
  125.     for (i = 0; i < 10; i++)    /* 00, 00, 02, then 7 00's... */
  126.       if (i == 2)
  127.         putc(i, handle->file);
  128.       else
  129.         putc(0, handle->file);
  130.  
  131.     putc(First_Line % 256, handle->file); /* y origin set to "First_Line" */
  132.     putc(First_Line / 256, handle->file);
  133.  
  134.     putc(*width % 256, handle->file);  /* write width and height */
  135.     putc(*width / 256, handle->file);
  136.     putc(*height % 256, handle->file);
  137.     putc(*height / 256, handle->file);
  138.     putc(24, handle->file);  /* 24 bits/pixel (16 million colors!) */
  139.     putc(32, handle->file);  /* Bitmask, pertinent bit: top-down raster */
  140.  
  141.     handle->width = *width;
  142.     handle->height = *height;
  143.     handle->buffer_size = buffer_size;
  144.  
  145.     break;
  146.  
  147.   case APPEND_MODE:
  148.     if ((handle->file = fopen (name, APPEND_FILE_STRING)) == NULL)
  149.       return(0);
  150.  
  151.     if (buffer_size != 0) 
  152.       {
  153.       if ((handle->buffer = malloc (buffer_size)) == NULL)
  154.         return(0);
  155.  
  156.       setvbuf (handle->file, handle->buffer, _IOFBF, buffer_size);
  157.       }
  158.  
  159.     break;
  160.   }
  161.   return(1);
  162.   }
  163.  
  164. void Write_Targa_Line (handle, line_data, line_number)
  165. FILE_HANDLE *handle;
  166. COLOUR *line_data;
  167. int line_number;
  168.   {
  169.   register int x;
  170.  
  171.   for (x = 0; x < handle->width; x++) 
  172.     {
  173.     putc((int) floor (line_data[x].Blue * 255.0), handle->file);
  174.     putc((int) floor (line_data[x].Green * 255.0), handle->file);
  175.     putc((int) floor (line_data[x].Red * 255.0), handle->file);
  176.     }
  177.  
  178.   if (handle->buffer_size == 0) 
  179.     {
  180.     fflush(handle->file);                       /* close and reopen file for */
  181.     handle->file = freopen(handle->filename, APPEND_FILE_STRING,
  182.       handle->file);                /* integrity in case we crash*/
  183.     }
  184.   }
  185.  
  186. int Read_Targa_Line (handle, line_data, line_number)
  187. FILE_HANDLE *handle;
  188. COLOUR *line_data;
  189. int *line_number;
  190.   {
  191.   int x, data;
  192.  
  193.   for (x = 0; x < handle->width; x++) 
  194.     {
  195.  
  196.     /* Read the BLUE data byte.  If EOF is reached on the first character read,
  197.       then this line hasn't been rendered yet.  Return 0.  If an EOF occurs
  198.       somewhere within the line, this is an error - return -1. */
  199.  
  200.     if ((data = getc(handle->file)) == EOF)
  201.       if (x == 0)
  202.         return (0);
  203.       else
  204.         return (-1);
  205.  
  206.     line_data[x].Blue = (DBL) data / 255.0;
  207.  
  208.     /* Read the GREEN data byte. */
  209.     if ((data = getc(handle->file)) == EOF)
  210.       return (-1);
  211.     line_data[x].Green = (DBL) data / 255.0;
  212.  
  213.  
  214.     /* Read the RED data byte. */
  215.     if ((data = getc(handle->file)) == EOF)
  216.       return (-1);
  217.     line_data[x].Red = (DBL) data / 255.0;
  218.     }
  219.  
  220.   *line_number = Targa_Line_Number++;
  221.   return(1);
  222.   }
  223.  
  224. void Close_Targa_File (handle)
  225. FILE_HANDLE *handle;
  226.   {
  227.   if(handle->file)
  228.     fclose (handle->file);
  229.   if (handle->buffer != NULL)
  230.     free (handle->buffer);
  231.   }
  232.  
  233. static void
  234. convert_targa_color(tcolor, pixelsize, bytes)
  235. IMAGE_COLOUR *tcolor;
  236. int pixelsize;
  237. unsigned char *bytes;
  238.   {
  239.   switch (pixelsize) 
  240.   {
  241.   case 1:
  242.     tcolor->Red   = bytes[0];
  243.     tcolor->Green = bytes[0];
  244.     tcolor->Blue  = bytes[0];
  245.     tcolor->Filter = 0;
  246.     break;
  247.   case 2:
  248.     tcolor->Red   = ((bytes[1] & 0x7c) << 1);
  249.     tcolor->Green = (((bytes[1] & 0x03) << 3) |
  250.       ((bytes[0] & 0xe0) >> 5)) << 3;
  251.     tcolor->Blue  = (bytes[0] & 0x1f) << 3;
  252.     tcolor->Filter = (bytes[1] & 0x80 ? 255 : 0);
  253.     break;
  254.   case 3:
  255.     tcolor->Red   = bytes[2];
  256.     tcolor->Green = bytes[1];
  257.     tcolor->Blue  = bytes[0];
  258.     tcolor->Filter = 0;
  259.     break;
  260.   case 4:
  261.     tcolor->Red   = bytes[2];
  262.     tcolor->Green = bytes[1];
  263.     tcolor->Blue  = bytes[0];
  264.     tcolor->Filter = bytes[3];
  265.     break;
  266.   default:
  267.     fprintf(stderr, "Bad pixelsize in Targa color\n");
  268.     close_all();
  269.     exit(1);
  270.   }
  271.   }
  272.  
  273. /* Reads a Targa image into an RGB image buffer.  Handles 8, 16, 24, 32 bit
  274.    formats.  Raw or color mapped. Simple raster and RLE compressed pixel
  275.    encoding. Right side up or upside down orientations. */
  276. void
  277. Read_Targa_Image(Image, name)
  278. IMAGE *Image;
  279. char *name;
  280.   {
  281.   FILE *filep;
  282.   IMAGE_LINE *line_data;
  283.   IMAGE_COLOUR *cmap, pixel;
  284.   int h;
  285.   unsigned i, j, k;
  286.   int temp;
  287.   unsigned char cflag, *map_line, bytes[4], tgaheader[18];
  288.   unsigned ftype, idlen, cmlen, cmsiz, psize, orien;
  289.   unsigned width, height;
  290.  
  291.   /* Start by trying to open the file */
  292.   if ((filep = Locate_File(name, READ_FILE_STRING)) == NULL) 
  293.     {
  294.     fprintf (stderr, "Cannot open Targa file %s\n", name);
  295.     close_all();
  296.     exit(1);
  297.     }
  298.   if (fread(tgaheader, 18, 1, filep) != 1) 
  299.     {
  300.     fprintf(stderr, "Error reading header of Targa image: %s\n", name);
  301.     close_all();
  302.     exit(1);
  303.     }
  304.  
  305.   /* Decipher the header information */
  306.   idlen  = tgaheader[ 0];
  307.   ftype  = tgaheader[ 2];
  308.   cmlen  = tgaheader[ 5] + (tgaheader[ 6] << 8);
  309.   cmsiz  = tgaheader[ 7] / 8;
  310.   width  = tgaheader[12] + (tgaheader[13] << 8);
  311.   height = tgaheader[14] + (tgaheader[15] << 8);
  312.   psize  = tgaheader[16] / 8;
  313.   orien  = tgaheader[17] & 0x20; /* Right side up ? */
  314.  
  315.   Image->iwidth  = width;
  316.   Image->iheight = height;
  317.   Image->width   = (DBL)width;
  318.   Image->height  = (DBL)height;
  319.   Image->Colour_Map_Size = cmlen;
  320.   Image->Colour_Map = NULL;
  321.  
  322.   /* Determine if this is a supported Targa type */
  323.   if (ftype == 9 || ftype == 10)
  324.     cflag = 1;
  325.   else if (ftype == 1 || ftype == 2 || ftype == 3)
  326.     cflag = 0;
  327.   else 
  328.     {
  329.     fprintf(stderr, "Image file %s is an unsupported Targa type: %d\n",
  330.       name, ftype);
  331.     close_all();
  332.     exit(1);
  333.     }
  334.  
  335.   /* Skip over the picture ID information */
  336.   if (idlen > 0 && fread(idbuf, idlen, 1, filep) != 1) 
  337.     {
  338.     fprintf(stderr, "reading identification field of %s\n", name);
  339.     close_all();
  340.     exit(1);
  341.     }
  342.  
  343.   /* Read in the the color map (if any) */
  344.   if (cmlen > 0) 
  345.     {
  346.     if (psize != 1) 
  347.       {
  348.       fprintf(stderr, "Can't support %d bits in a color map index\n",
  349.         psize * 8);
  350.       close_all();
  351.       exit(1);
  352.       }
  353.     if ((cmap = (IMAGE_COLOUR *)malloc(cmlen * sizeof(IMAGE_COLOUR))) == NULL) 
  354.       {
  355.       fprintf(stderr, "Failed to allocate memory for image: %s\n", name);
  356.       close_all();
  357.       exit(1);
  358.       }
  359.     for (i=0;i<cmlen;i++) 
  360.       {
  361.       for (j=0;j<cmsiz;j++)
  362.         if ((temp = fgetc(filep)) == EOF) 
  363.         {
  364.         fprintf(stderr, "Premature EOF in image file: %s\n", name);
  365.         close_all();
  366.         exit(1);
  367.         }
  368.         else
  369.           bytes[j] = (unsigned char)temp;
  370.       convert_targa_color(&cmap[i], cmsiz, bytes);
  371.       }
  372.     Image->Colour_Map = cmap;
  373.     }
  374.   else
  375.     Image->Colour_Map = NULL;
  376.  
  377.   /* Allocate the buffer for the image */
  378.   if (cmlen > 0) 
  379.     {
  380.     if ((Image->data.map_lines = (unsigned char **)
  381.       malloc(height * sizeof(unsigned char *)))==NULL) 
  382.       {
  383.       fprintf (stderr, "Cannot allocate memory for image: %s\n", name);
  384.       close_all(); 
  385.       exit(1);
  386.       }
  387.     }
  388.   else if ((Image->data.rgb_lines = (struct Image_Line *)
  389.     malloc(height * sizeof(struct Image_Line))) == NULL) 
  390.     {
  391.     fprintf (stderr, "Cannot allocate memory for image: %s\n", name);
  392.     close_all(); 
  393.     exit(1);
  394.     }
  395.   for (i=0;i<height;i++) 
  396.     {
  397.     if (cmlen > 0) 
  398.       {
  399.       k = width * sizeof(unsigned char);
  400.       map_line = (unsigned char *)malloc(k);
  401.       if (map_line == NULL) 
  402.         {
  403.         fprintf(stderr, "Cannot allocate memory for image: %s\n", name);
  404.         close_all();
  405.         exit(1);
  406.         }
  407.       Image->data.map_lines[i] = map_line;
  408.       }
  409.     else 
  410.       {
  411.       line_data = &Image->data.rgb_lines[i];
  412.       k = width * sizeof(unsigned char);
  413.       line_data->red   = (unsigned char *)malloc(k);
  414.       line_data->green = (unsigned char *)malloc(k);
  415.       line_data->blue  = (unsigned char *)malloc(k);
  416.       if (line_data->red == NULL || line_data->green == NULL ||
  417.         line_data->blue == NULL) 
  418.         {
  419.         fprintf(stderr, "Cannot allocate memory for image: %s\n", name);
  420.         close_all();
  421.         exit(1);
  422.         }
  423.       }
  424.     }
  425.  
  426.   /* Read the image into the buffer */
  427.   if (cflag) 
  428.     {
  429.     /* RLE compressed images */
  430.     if (cmlen > 0)
  431.       if (orien)
  432.         map_line = Image->data.map_lines[0];
  433.       else
  434.         map_line = Image->data.map_lines[height-1];
  435.     else
  436.       if (orien)
  437.         line_data = &Image->data.rgb_lines[0];
  438.       else
  439.         line_data = &Image->data.rgb_lines[height-1];
  440.     i = 0; /* row counter */
  441.     j = 0; /* column counter */
  442.     while (i < height) 
  443.       {
  444.       /* Grab a header */
  445.       if ((h = fgetc(filep)) == EOF) 
  446.         {
  447.         fprintf(stderr, "Premature EOF in image file: %s\n", name);
  448.         close_all();
  449.         exit(1);
  450.         }
  451.       if (h & 0x80) 
  452.         {
  453.         /* Repeat buffer */
  454.         h &= 0x7F;
  455.         for (k=0;k<psize;k++)
  456.           if ((temp = fgetc(filep)) == EOF) 
  457.           {
  458.           fprintf(stderr, "Premature EOF in image file: %s\n", name);
  459.           close_all();
  460.           exit(1);
  461.           }
  462.           else
  463.             bytes[k] = (unsigned char)temp;
  464.         if (cmlen == 0)
  465.           convert_targa_color(&pixel, psize, bytes);
  466.         for ( ; h >= 0; h--) 
  467.           {
  468.           if (cmlen > 0)
  469.             map_line[j] = bytes[0];
  470.           else 
  471.             {
  472.             line_data->red[j]   = (unsigned char)pixel.Red;
  473.             line_data->green[j] = (unsigned char)pixel.Green;
  474.             line_data->blue[j]  = (unsigned char)pixel.Blue;
  475.             }
  476.           if (++j == width) 
  477.             {
  478.             i++;
  479.             if (cmlen > 0) 
  480.               {
  481.               if (orien)
  482.                 map_line = Image->data.map_lines[i];
  483.               else
  484.                 map_line = Image->data.map_lines[height-i-1];
  485.               }
  486.             else
  487.               line_data += (orien ? 1 : -1);
  488.             j = 0;
  489.             }
  490.           }
  491.         }
  492.       else 
  493.         {
  494.         /* Copy buffer */
  495.           for (;h>=0;h--) 
  496.           {
  497.           for (k=0;k<psize;k++)
  498.             if ((temp = fgetc(filep)) == EOF) 
  499.             {
  500.             fprintf(stderr, "Premature EOF in image file: %s\n", name);
  501.             close_all();
  502.             exit(1);
  503.             }
  504.             else
  505.               bytes[k] = (unsigned char)temp;
  506.           if (cmlen > 0)
  507.             map_line[j] = bytes[0];
  508.           else 
  509.             {
  510.             convert_targa_color(&pixel, psize, bytes);
  511.             line_data->red[j]   = (unsigned char)pixel.Red;
  512.             line_data->green[j] = (unsigned char)pixel.Green;
  513.             line_data->blue[j]  = (unsigned char)pixel.Blue;
  514.             }
  515.           if (++j == width) 
  516.             {
  517.             i++;
  518.             if (cmlen > 0) 
  519.               {
  520.               if (orien)
  521.                 map_line = Image->data.map_lines[i];
  522.               else
  523.                 map_line = Image->data.map_lines[height-i-1];
  524.               }
  525.             else
  526.               line_data += (orien ? 1 : -1);
  527.             j = 0;
  528.             }
  529.           }
  530.         }
  531.       }
  532.     }
  533.   else 
  534.     {
  535.     /* Simple raster image file, read in all of the pixels */
  536.       if (cmlen == 0) 
  537.       {
  538.       if (orien)
  539.         line_data = &Image->data.rgb_lines[0];
  540.       else
  541.         line_data = &Image->data.rgb_lines[height-1];
  542.       }
  543.     for (i=0;i<height;i++) 
  544.       {
  545.       if (cmlen > 0) 
  546.         {
  547.         if (orien)
  548.           map_line = Image->data.map_lines[i];
  549.         else
  550.           map_line = Image->data.map_lines[height-i-1];
  551.         }
  552.       for (j=0;j<width;j++) 
  553.         {
  554.         for (k=0;k<psize;k++)
  555.           if ((temp = fgetc(filep)) == EOF) 
  556.           {
  557.           fprintf(stderr, "Premature EOF in image file: %s\n", name);
  558.           close_all();
  559.           exit(1);
  560.           }
  561.           else
  562.             bytes[k] = (unsigned char)temp;
  563.         if (cmlen > 0)
  564.           map_line[j] = bytes[0];
  565.         else 
  566.           {
  567.           convert_targa_color(&pixel, psize, bytes);
  568.           line_data->red[j]   = (unsigned char)pixel.Red;
  569.           line_data->green[j] = (unsigned char)pixel.Green;
  570.           line_data->blue[j]  = (unsigned char)pixel.Blue;
  571.           }
  572.         }
  573.       if (cmlen == 0)
  574.         line_data += (orien ? 1 : -1);
  575.       }
  576.     }
  577.   /* Any data following the image is ignored. */
  578.  
  579.   /* Close the image file */
  580.   fclose(filep);
  581.   }
  582.