Advertisement
tm512

tga2nif

Aug 3rd, 2012
66
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 6.83 KB | None | 0 0
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <unistd.h>
  5. #include <sys/stat.h>
  6. #include <fcntl.h>
  7. #include <errno.h>
  8.  
  9. #include <zlib.h>
  10.  
  11. #ifdef WIN32
  12. #include <io.h>
  13. #define set_binary_mode(f) setmode (f, O_BINARY)
  14. #else
  15. #define set_binary_mode(f)
  16. #endif
  17.  
  18. /*
  19.     'n', 'i', 'f', '\0' (32 bits)
  20.     image width (16 bits)
  21.     image height (16 bits)
  22.     compressed image size (32 bits)
  23.  
  24.     compressed image data (ARGB format, 32bpp, zlib)
  25.  
  26.     for each shift table
  27.         length (32 bits)
  28.         for each shift entry
  29.             x (16 bits)
  30.             y (16 bits)
  31. */
  32.  
  33. typedef struct
  34. {
  35.     unsigned char id_length;
  36.     unsigned char cmap_type;
  37.     unsigned char image_type;
  38.  
  39.     unsigned short cmap_start;
  40.     unsigned short cmap_length;
  41.     unsigned char cmap_esize;
  42.  
  43.     unsigned short xorigin;
  44.     unsigned short yorigin;
  45.     unsigned short width;
  46.     unsigned short height;
  47.     unsigned char depth;
  48.     unsigned char desc;
  49. } tgainfo_t;
  50.  
  51. int readtgainfo (int fd, tgainfo_t *info)
  52. {
  53.     int totalread = 0;
  54.  
  55.     totalread += read (fd, &info->id_length, 1);
  56.     totalread += read (fd, &info->cmap_type, 1);
  57.     totalread += read (fd, &info->image_type, 1);
  58.     totalread += read (fd, &info->cmap_start, 2);
  59.     totalread += read (fd, &info->cmap_length, 2);
  60.     totalread += read (fd, &info->cmap_esize, 1);
  61.     totalread += read (fd, &info->xorigin, 2);
  62.     totalread += read (fd, &info->yorigin, 2);
  63.     totalread += read (fd, &info->width, 2);
  64.     totalread += read (fd, &info->height, 2);
  65.     totalread += read (fd, &info->depth, 1);
  66.     totalread += read (fd, &info->desc, 1);
  67.     return totalread;
  68. }
  69.  
  70. int main (int argc, char **argv)
  71. {
  72.     const char *nifstart = "nif"; // string to begin a .nif file with
  73.     int base, shift, nifout;
  74.     int len, i, j;
  75.     tgainfo_t baseinfo;
  76.     char *nifname;
  77.     unsigned char *img = NULL, *zimg = NULL;
  78.     unsigned long imglen, zimglen;
  79.     FILE *windbg = fopen ("tga2nif.log", "w");
  80.  
  81.     if (argc < 2)
  82.     {
  83.         fprintf (stderr, "Usage: tga2nif [base].tga [shift1].tga [shift2].tga ... [shiftN].tga\n");
  84.         return 1;
  85.     }
  86.  
  87.     // open base file
  88.     base = open (argv [1], O_RDONLY);
  89.     if (base < 0)
  90.     {
  91.         fprintf (stderr, "Couldn't open file %s (%s)\n", argv [1], strerror (errno));
  92.         return 1;
  93.     }
  94.  
  95.     // read base file tga info
  96.     if (readtgainfo (base, &baseinfo) != 18)
  97.     {
  98.         fprintf (stderr, "input file %s was incomplete\n", argv [1]);
  99.         return 1;
  100.     }
  101.  
  102.     if (baseinfo.cmap_type)
  103.     {
  104.         fprintf (stderr, "input file %s has color map\n", argv [1]);
  105.         return 1;
  106.     }
  107.  
  108.     // open nif file
  109.     len = strlen (argv [1]);
  110.     nifname = malloc (len + 1);
  111.     sprintf (nifname, "%s", argv [1]);
  112.     sprintf (nifname + len - 4, ".nif");
  113.     nifout = creat (nifname, S_IRUSR | S_IWUSR);
  114.     set_binary_mode (nifout);
  115.     if (nifout < 0)
  116.     {
  117.         fprintf (stderr, "Couldn't open output file %s (%s)\n", nifname, strerror (errno));
  118.         return 1;
  119.     }
  120.  
  121.     // write nif header info
  122.     if (write (nifout, nifstart, 4) != 4
  123.      || write (nifout, &baseinfo.width, 2) != 2
  124.      || write (nifout, &baseinfo.height, 2) != 2)
  125.     {
  126.         fprintf (stderr, "Error writing nif header (%s)\n", strerror (errno));
  127.         return 1;
  128.     }
  129.  
  130.     fprintf (windbg, "image is %ux%u\n", baseinfo.width, baseinfo.height);
  131.  
  132.     // prepare/write image data array
  133.     imglen = 4 * baseinfo.width * baseinfo.height;
  134.     zimglen = compressBound (imglen);
  135.     img = malloc (imglen);
  136.     zimg = malloc (zimglen);
  137.     if (!img || !zimg)
  138.     {
  139.         fprintf (stderr, "Couldn't malloc image buffer\n");
  140.         return 1;
  141.     }
  142.  
  143.     fprintf (windbg, "Allocated %luB for image data and %luB for compressed data\n", imglen, zimglen);
  144.  
  145.     for (i = 0; i < baseinfo.width; i++)
  146.         for (j = 0; j < baseinfo.height; j++)
  147.         {
  148.             unsigned char colors [3]; // bgr from .tga
  149.             unsigned int outcolor; // argb for .nif
  150.             unsigned int *pxp; // pixel pointer
  151.  
  152.             read (base, colors, 3); // get three bytes from the tga file
  153.             if (colors [0] == 0x00 && colors [1] == 0xff && colors [2] == 0x00) // green, transparent
  154.                 outcolor = 0x00000000;
  155.             else
  156.                 outcolor = 0xff << 24 | colors [2] << 16 | colors [1] << 8 | colors [0];
  157.  
  158.             fprintf (windbg, "[%i, %i, %x] -> %u\n", i, j, outcolor, (baseinfo.width - 1 - i) * baseinfo.height + (j + baseinfo.height) % baseinfo.width);
  159.             if ((baseinfo.width - 1 - i) * baseinfo.height + (j + baseinfo.height) % baseinfo.width > imglen)
  160.                 fprintf (windbg, "offset exceeds image buffer length, we're gonna crash here! :D\n");
  161.  
  162.             pxp = (unsigned int*)img + (baseinfo.width - 1 - i) * baseinfo.height + (j + baseinfo.height) % baseinfo.width;
  163.             *pxp = outcolor;
  164.         }
  165.  
  166.     int zret;
  167.     if ((zret = compress2 (zimg, &zimglen, img, imglen, Z_BEST_COMPRESSION)) != Z_OK)
  168.     {
  169.         fprintf (stderr, "Error compressing image data (%s)\n", zError (zret));
  170.         return 1;
  171.     }
  172.  
  173.     unsigned int zimglen32 = (unsigned int)zimglen;
  174.     if (write (nifout, &zimglen32, 4) != 4)
  175.     {
  176.         fprintf (stderr, "Error writing nif header (%s)\n", strerror (errno));
  177.         return 1;
  178.     }
  179.  
  180.     // write image data to file
  181.     int totalwrite = 0;
  182.     do
  183.     {
  184.         totalwrite += write (nifout, zimg + totalwrite, zimglen - totalwrite);
  185.     } while (totalwrite < zimglen);
  186.  
  187.     // make shift tables
  188.     for (i = 2; i < argc; i++)
  189.     {
  190.         tgainfo_t shiftinfo;
  191.         off_t pos;
  192.         unsigned short k, l;
  193.         unsigned int numentr = 0;
  194.  
  195.         shift = open (argv [i], O_RDONLY);
  196.         if (shift < 0)
  197.             continue;
  198.  
  199.         if (readtgainfo (shift, &shiftinfo) != 18 || shiftinfo.cmap_type)
  200.             continue;
  201.  
  202.         // save position so we can go back and write how many entries
  203.         pos = lseek (nifout, 0, SEEK_CUR);
  204.         write (nifout, &numentr, 4);
  205.  
  206.         for (k = 0; k < shiftinfo.width; k++)
  207.             for (l = 0; l < shiftinfo.height; l++)
  208.             {
  209.                 unsigned char colors [3];
  210.                 unsigned short ex, ey;
  211.                 read (shift, colors, 3);
  212.  
  213.                 if (colors [0] == 0x00 && colors [1] == 0xff && colors [2] == 0x00)
  214.                     continue;
  215.  
  216.                 numentr ++;
  217.                 ex = (l + shiftinfo.height) % shiftinfo.width;
  218.                 ey = shiftinfo.width - 1 - k;
  219.  
  220.                 write (nifout, &ex, 2);
  221.                 write (nifout, &ey, 2);
  222.             }
  223.  
  224.         // go back and write how many entries there are
  225.         lseek (nifout, pos, SEEK_SET);
  226.         write (nifout, &numentr, 4);
  227.         lseek (nifout, numentr * 4, SEEK_CUR);
  228.     }
  229.  
  230.     close (nifout);
  231.     return 0;
  232. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement