/* BOGL - Ben's Own Graphics Library.
   Written by Ben Pfaff <pfaffben@debian.org>.

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License as
   published by the Free Software Foundation; either version 2 of the
   License, or (at your option) any later version.
   
   This program is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   General Public License for more details.
   
   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
   USA. */

#define _GNU_SOURCE 1
#include <ctype.h>
#include <errno.h>
#include <gd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/* Allocation routines. */

static void
out_of_memory (void)
{
  printf ("Virtual memory exhausted.\n");
  exit (EXIT_FAILURE);
}

void *
xmalloc (size_t size)
{
  void *p;
  
  if (size == 0)
    return 0;
  p = malloc (size);
  if (!p)
    out_of_memory ();
  return p;
}

void *
xrealloc (void *p, size_t size)
{
  if (p == NULL)
    return xmalloc (size);
  if (size == 0)
    {
      free (p);
      return NULL;
    }
  p = realloc (p, size);
  if (!p)
    out_of_memory ();
  return p;
}

char *
xstrdup (const char *s)
{
  size_t size = strlen (s) + 1;
  char *p = xmalloc (size);
  memcpy (p, s, size);
  return p;
}

int
main (int argc, char *argv[])
{
  char *name;

  FILE *giffile;
  gdImagePtr gif;
  int ncols;
  int w;
  int h;
  
  if (argc < 2)
    {
      printf ("usage: giftobogl graphic.gif > graphic.c\n");
      exit (EXIT_FAILURE);
    }

  /* Compute name for internal structures. */
  {
    char *cp;
    
    name = xstrdup (argv[1]);
    strcpy (name, argv[1]);
    for (cp = name; *cp; cp++)
      if (!isalnum ((unsigned char) *cp))
	{
	  if (!strcmp (cp, ".gif"))
	    {
	      *cp = 0;
	      break;
	    }

	  *cp = '_';
	}
  }

  giffile = fopen (argv[1], "rb");
  if (!giffile)
    {
      printf ("error opening %s: %s\n", argv[1], strerror (errno));
      exit (EXIT_FAILURE);
    }

  gif = gdImageCreateFromGif (giffile);
  if (!gif)
    exit (EXIT_FAILURE);

  w = gif->sx;
  h = gif->sy;
  ncols = gdImageColorsTotal (gif);
  if (ncols > 16)
    {
      printf ("Image has too many colors (%d)\n", ncols);
      exit (EXIT_FAILURE);
    }

  printf ("/* Generated by giftobogl. */\n"
	  "#include \"bogl.h\"\n\n"
	  "/* Image data with simple run-length encoding.  Each byte\n"
	  "   contains a pixel value in its lower nibble, and a repeat\n"
	  "   count in its upper nibble. */\n\n"
	  "static unsigned char %s_data[] = {\n\n",
	  name);

  /* Image data. */
  {
    int y;

    for (y = 0; y < h; y++)
      {
	int n, x1;
	
	printf ("/* Row %d. */", y);

	n = 0;
	for (x1 = 0; x1 < w; )
	  {
	    int c = gdImageGetPixel (gif, x1, y);
	    int x2 = x1 + 1;

	    while (x2 < w && c == gdImageGetPixel (gif, x2, y) && x2 - x1 < 15)
	      x2++;

	    if (n++ % 12 == 0)
	      putchar ('\n');
	    printf ("0x%x%x, ", x2 - x1, c);

	    x1 = x2;
	  }
	printf ("\n\n");
      }
  }

  /* Palette data. */
  {
    int i;
    
    printf ("};\n\n"
	    "/* Palette data. */\n"
	    "static unsigned char %s_palette[%d][3] = {\n",
	    name, ncols);
    for (i = 0; i < ncols; i++)
      printf ("  {0x%02x, 0x%02x, 0x%02x},\n",
	      gdImageRed (gif, i),
	      gdImageGreen (gif, i),
	      gdImageBlue (gif, i));
  }

  printf ("};\n\n"
	  "/* Pixmap structure. */\n"
	  "struct bogl_pixmap pixmap_%s = {\n"
	  "  %d,\t\t/* Width. */\n"
	  "  %d,\t\t/* Height. */\n"
	  "  %d,\t\t/* Number of colors. */\n"
	  "  %d,\t\t/* Transparent color. */\n"
	  "  %s_palette,\t/* Palette. */\n"
	  "  %s_data,\t/* Data. */\n"
	  "};\n",
	  name, w, h, ncols, gdImageGetTransparent (gif), name, name);

  return 0;
}
