/****************************************************************************
 * readbmp.h - BMP loader.
 *
 * Author: Jon Taylor (taylorj@gaia.ecs.csus.edu)
 * Based on original code by Carsten Engelmann (cengelm@gwdg.de)
 ***************************************************************************/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <unistd.h>
#include <sys/stat.h>

#define TRUE 1
#define FALSE 0

/* BITMAPFILEHEADER
 *
 * Bitmap File Information
 *
 * The BITMAPFILEHEADER data structure contains information about the type,
 * size, and layout of a device-independent bitmap (DIB) file.
 */
typedef struct BITMAPFILEHEADER {
        short   bfType;
        int     bfSize;
        short   bfReserved1;
        short   bfReserved2;
        int     bfOffBits;
} BITMAPFILEHEADER;

typedef struct BITMAPINFOHEADER{
	unsigned int  biSize;
   	unsigned int  biWidth;
   	unsigned int  biHeight;
   	unsigned short   biPlanes;
   	unsigned short   biBitCount;
   	unsigned int  biCompression;
   	unsigned int  biSizeImage;
   	unsigned int  biXPelsPerMeter;
   	unsigned int  biYPelsPerMeter;
   	unsigned int  biClrUsed;
   	unsigned int  biClrImportant;
} BITMAPINFOHEADER;

typedef struct BITMAPCOREHEADER{
        unsigned int  bcSize;
        unsigned short  bcWidth;
        unsigned short  bcHeight;
        unsigned short   bcPlanes;
        unsigned short   bcBitCount;
} BITMAPCOREHEADER;

typedef struct {
  int width,height,bpp,numcols;
  char type[4];
} PICINFO;

static int flip ();

void *read_bmp_file ()
{
  FILE *infile;
  int i, j;
  int iswindows = 0;
  int dummy, count, done, output_type;
  unsigned char *buf, *bmap, *pal;
  unsigned char read[2];
  unsigned char *p, *ptr, *dptr, *hptr;
  unsigned int w, h, palsize;
  BITMAPINFOHEADER bih;
  BITMAPCOREHEADER bch;
  PICINFO *pp;
  pp=malloc(sizeof(PICINFO));
  
  bmap = NULL;
  pal = NULL;
  
  infile=fopen("/usr/games/angband/lib/8x13.bmp","r");
  
  buf=(unsigned char *) malloc (54);

  fread (buf, 1, 26, infile);

  memcpy (&bch, buf + 14, 12);
  
  if (bch.bcSize == 40)		/* truly MS_Windows 3.x ?*/
    {
      fread (buf + 26, 1, 28, infile);/* then we need the rest */
      memcpy (&bih, buf + 14, 40);
      iswindows = TRUE;
    }
  else
    iswindows = FALSE;

  p=malloc (768);  
  pal = p;

  if (iswindows)		/*  MS_Windows 3.x */
    {
      pp->width = w = bih.biWidth;
      pp->height = h = bih.biHeight;
      pp->bpp = bih.biBitCount;

  /* Here the "offbits" -  we need 'em for the
     * palette size - e.g. XV uses different sizes
     */
      palsize = (*(unsigned *) (buf + 10) - 54) / 4;
    }
  else                         /*  OS/2 V1.1       */
    {
      pp->width = w = bch.bcWidth;
      pp->height = h = bch.bcHeight;
      pp->bpp = bch.bcBitCount;
      palsize = (*(unsigned *) (buf + 10) - 26) / 3;
    }

  if ((pp->bpp >> 3) < 3)
    output_type = 1;
  
  /* w is the size of a horizontal line in bytes
   * bih.biWidth is the number of valid pixels in a line
   * the latter one is passed to vgadisp.c as pp->width
   */
  switch (pp->bpp)
    {
    case 1:
      if (w % 32)
        w = (w / 32) * 32 + 32;;
      break;
    case 4:
      if (w % 8)
	w = (w / 8) * 8 + 8;
      break;
    case 8:
      if (w % 4)
	w = (w / 4) * 4 + 4;
      break;
    }

  if ((pp->bpp == 24) && (output_type == 3))
    dummy = 3;
  else
    dummy = 1;
  bmap = malloc (w * (h + 2) * dummy);
  memset (bmap, 0, w * (h + 2) * dummy);

  switch (pp->bpp)
    {
    case 1:
      /* 1bit non compressed */
      ptr = pal;
          fread (ptr , 1, 3, infile);
          if (iswindows)
            fread (&dummy, 1, 1, infile);
          fread (ptr + 3, 1, 3, infile);
          if (iswindows)
            fread (&dummy, 1, 1, infile);
      for (i = 0; i < 2; i++)
        {
          p[i] = ptr[3 * i + 2];
          p[i + 256] = ptr[3 * i + 1];
          p[i + 512] = ptr[3 * i];
        }
      free (pal);
      pal = p;
      ptr = bmap;
	for (j = h - 1; j >= 0; j--)
	    for (i = 0, count=0 ; i < (w >> 3); i++)
             {
		hptr = ptr + j * pp->width;
                dummy = fgetc (infile);
                if (count < pp->width)
                  {
                    hptr[count] = (dummy & 128)?1:0;count++;
                    hptr[count] = (dummy & 64)?1:0;count++;
                    hptr[count] = (dummy & 32)?1:0;count++;
                    hptr[count] = (dummy & 16)?1:0;count++;
                    hptr[count] = (dummy & 8)?1:0;count++;
                    hptr[count] = (dummy & 4)?1:0;count++;
                    hptr[count] = (dummy & 2)?1:0;count++;
                    hptr[count] = dummy & 1;count++;
                  }
              }
        pp->numcols=2;
	break;
    case 4:
      /* 4bit non compressed */
      ptr = pal;
      for (i = 0; i < palsize; i++)
	{ 
	  fread (ptr + 3 * i, 1, 3, infile);
	  if (iswindows)
	    fread (&dummy, 1, 1, infile);
	}
      for (i = 0; i < palsize; i++)
	{
	  p[i] = ptr[3 * i + 2];
	  p[i + 256] = ptr[3 * i + 1];
	  p[i + 512] = ptr[3 * i];
	}
      free (pal);
      pal = p;
      ptr = bmap;
      if ((!iswindows) || (bih.biCompression == 0))
	{ 
	  for (j = h - 1; j >= 0; j--)
	    for (i = 0, count = 0; i < (w / 2); i++)
	      {
		dummy = fgetc (infile);
		if (count < pp->width)
		  {
		    ptr[count + j * pp->width] = dummy >> 4;
		    count++;
		  }
		if (count < pp->width)
		  {
		    ptr[count + j * pp->width] = dummy & 15;
		    count++;
		  }
	      }
	}
      else
	{
	  /* 4bit RLE compressed */
	  done = 0;
	  count = 0;
	  while (done == 0)
	    {
	      fread (read, 1, 2, infile);
	      if (*read)
		{
		  i = 0;
		  do
		    {
		      *ptr = read[1] >> 4;
		      ptr++;
		      i++;
		      if (i < (read[0]))
			{
			  *ptr = read[1] & 15;
			  ptr++;
			  i++;
			}
		    }
		  while (i < (*read));
		}
	      else if (read[1] == 0)
		{
		  count++;
		}
	      else if (read[1] == 1)
		done = 1;
	      else if (read[1] == 2)
		{
		  /* This isn't really tested */
		  ptr += fgetc (infile) + bih.biWidth * fgetc (infile);
		}
	      else
		{
		  dptr = hptr = (unsigned char *) malloc (read[1] >> 1);
		  fread (dptr, 1, read[1] >> 1, infile);
		  if (read[1] % 4 > 1)
		    dummy = fgetc (infile);
		  i = 0;
		  do
		    {
		      *ptr = (*dptr) >> 4;
		      i++;
		      ptr++;
		      if (i < read[1])
			{
			  *ptr = (*dptr) & 15;
			  i++;
			  ptr++;
			}
		      dptr++;
		    }
		  while (i < read[1]);
		  free (hptr);
		}
	    }
	  flip (*bmap, bih.biWidth, bih.biHeight);
	}
      pp->width = w;
      pp->numcols= 16;
      break;

    case 8:
      /* 8bit non compressed */
      ptr = pal;
      for (i = 0; i < palsize; i++)
	{
	  fread (ptr + 3 * i, 1, 3, infile);
	  if (iswindows)
	    dummy = fgetc (infile);
	}
      for (i = 0; i < palsize; i++)
	{
	  p[i] = ptr[3 * i + 2];
	  p[i + 256] = ptr[3 * i + 1];
	  p[i + 512] = ptr[3 * i];
	}
      free (pal);
      pal = p;
      ptr = bmap;
      if ((!iswindows) || (bih.biCompression == 0))
	for (i = h - 1; i >= 0; i--)
	  {
	    fread (ptr + pp->width * i, 1, w, infile);
	  }
      else
	/* 8bit RLE compressed */
	{
	  done = 0;
	  count = 0;
	  while (done == 0)
	    {
	      fread (read, 1, 2, infile);
	      if (read[0])
		for (i = 0; i < (int) read[0]; i++)
		  {
		    *ptr = read[1];
		    ptr++;
		  }
	      else if (read[1] == 0)
		{
		  count++;
		}
	      else if (read[1] == 1)
		done = 1;
	      else if (read[1] == 2)
		ptr += fgetc (infile) + bih.biWidth * fgetc (infile);
	      else
		{
		  fread (ptr, 1, read[1], infile);
		  if (read[1] % 2)
		    fgetc (infile);
		  ptr += read[1];
		}
	    }
	  flip (*bmap, bih.biWidth, bih.biHeight);
	}
      pp->numcols= 256;
      break;

    }

  free (buf);
/*  fclose (infile); */
  return (bmap);
}

static int flip (unsigned char * image, unsigned int w, unsigned int h)
{
  unsigned int i;
  unsigned char *hptr;

  hptr = (unsigned char *) malloc (w);
  for (i = 0; i < (h / 2); i++)
    {
      memcpy (hptr, image + i * w, w);
      memcpy (image + i * w, image + (h - i - 1) * w, w);
      memcpy (image + (h - i - 1) * w, hptr, w);
    }
  free (hptr);
  return (0);
}
