/*
 * sprite.c
 * stefan bellon
 * may 1998
 *
 *
 * The author makes no representations about the suitability of this
 * software for any purpose. It is provided "as is" without express or
 * implied warranty.
 *
 * THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT
 * OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
 * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "xearth.h"
#include "kljcpyrt.h"

/*extern void sprite_setup _P((FILE *));
extern void sprite_row _P((u_char *));
extern void sprite_cleanup _P((void));*/

static FILE    *outs;
static unsigned bytes_per_row;

static unsigned int *header;
static u16or32 *dith;

void sprite_output()
{
  compute_positions();
  scan_map();
  do_dots();
  sprite_setup(stdout);
  render(sprite_row);
  sprite_cleanup();
}

static int last_bit_used_8[4]={31, 7, 15, 23};
static int last_bit_used_16[2]={15, 7};

extern void sprite_setup(s)
     FILE *s;
{
  int  i, pal_size=0, w;
  unsigned char cmap[3][256];

  outs          = s;

  if (num_colors == (1<<24)) bytes_per_row = wdth<<2; else
  if (num_colors == (1<<15)) bytes_per_row = wdth<<1; else
  if (num_colors <= 256)   { bytes_per_row = wdth; pal_size = 2048; }

  //fprintf(stderr, "%dx%d: num_colors = %d, bytes_per_row = %d\n", wdth, hght, num_colors, bytes_per_row);

  header = (unsigned int *) malloc(14*4);

  /* This header is only suitable for 32bpp sprites! */

  /* control block */
  header[0]  = 1;                  /* one sprite in file */
  header[1]  = 16;                 /* offset to first sprite */
  header[2]  = bytes_per_row*hght + 60 + pal_size; /* offset to eof, 60 for header */

  /* sprite header */
  header[3]  = bytes_per_row*hght + 44 + pal_size; /* offset to next sprite */
  memset(&header[4], 0, 12);
  strcpy((char*)&header[4], "xearth"); /* sprite name */
  header[7]  = wdth - 1;           /* width of sprite - 1 */
  header[8]  = hght - 1;           /* height of sprite - 1 */
  header[9]  = 0;                  /* first bit used */

  if (num_colors == 1<<24)
  {
    header[10] = 31;
    header[13] = (1 | (90 << 14) | (90 << 1) | (6 << 27));
  }

  if (num_colors == 1<<15)
  {
    header[10] = last_bit_used_16[wdth%2];
    header[13] = (1 | (90 << 14) | (90 << 1) | (5 << 27));
    header[7] = header[7] >> 1;
  }

  if (num_colors <= 256)
  {
    header[10] = last_bit_used_8[wdth%4];
    header[13] = (1 | (90 << 14) | (90 << 1) | (4 << 27));
    header[7] = header[7] >> 2;
    dither_setup(num_colors);
    dith = (u16or32 *) malloc((unsigned) sizeof(u16or32) * wdth);
    assert(dith != NULL);
    for (i=0; i<dither_ncolors; i++)
    {
      cmap[0][i] = dither_colormap[i*3+0];
      cmap[1][i] = dither_colormap[i*3+1];
      cmap[2][i] = dither_colormap[i*3+2];
    }
  }
  header[11] = 44+pal_size;        /* offset to sprite image */
  header[12] = 44+pal_size;        /* offs. to trasp. map or same as above */

  fwrite(header, 4, 14, outs);

  if (num_colors <= 256)
  {
    for (i=0; i<num_colors; i++)
      w = (cmap[0][i] << 8) | (cmap[1][i] << 16) | (cmap[2][i] << 24),
      fwrite(&w, 4, 1, outs),
      fwrite(&w, 4, 1, outs);
    for (i=num_colors; i<256; i++)
      w = 0,
      fwrite(&w, 4, 1, outs),
      fwrite(&w, 4, 1, outs);
  }

  free(header);
}


extern void sprite_row(row)
     u_char *row;
{
  int  i;
  char b;
  u16or32 *tmp;

  if (num_colors > 256)
  {
    for (i=0; i<wdth; i++)
    {
      fwrite(row + i * 3, 1, 3, outs);
      fprintf(outs, "%c", 0);
    }
  }
  else
  {
    tmp = dith;
    dither_row(row, tmp);
    for (i=0; i!=wdth; i++)
      b = (unsigned char) tmp[i],
      fwrite(&b, 1, 1, outs);
  }
}

extern void sprite_cleanup()
{
  if (num_colors <= 256)
  {
    dither_cleanup();
    free(dith);
  }
}
