/* Hey, emacs, this is -*- C -*- code.  */

/* read-degas.c - read Atari Degas images

Copyright (C) 1992 D P Gymer

This 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.  */

/* $Id: read-degas.c,v 0.3.2.0 1992/06/11 22:30:07 dpg Alpha dpg $ */

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

#include "view.h"

/* This file assumes that a short is 16 bits.  */

/* Read a big-endian short.  Return 0 iff we succeed.  */
static int
read_big16 (unsigned short *val, FILE *fp)
{
  int high = fgetc (fp);
  int low = fgetc (fp);

  if (low == EOF || high == EOF)
    return 1;
  *val = low + ((high << 8) & 0xff00);
  return 0;
}

/* Try to read a Degas palette.  0 iff we succeed.  */
static int
read_pal (FILE *fp, MAP *map, PALETTE **palette_index)
{
  PALETTE **palp = &map->palette;
  int count;

  count = 0;
  do
    {
      PALETTE *this;
      unsigned short rgb;
      struct color palval;

      if (read_big16 (&rgb, fp))
	return 1;

      /* Takes into account the peculiar STe palette.  */
#define PALVAL(x) ((((x) << 1) & 14) | (((x) >> 3) & 1))
      palval.red = PALVAL (rgb >> 8) * MAXRGBVAL / 15;
      palval.green = PALVAL (rgb >> 4) * MAXRGBVAL / 15;
      palval.blue = PALVAL (rgb) * MAXRGBVAL / 15;

      /* See if we've already got the color.  */
      this = *palp;
      while (this)
	{
	  if (COLOREQ (palval, this->color))
	    break;
	  this = this->next;
	}

      /* Didn't already have it, so we create it.  It happens to go at the
         start of the palette list.  */
      if (!this)
	{
	  this = alloc_palette ();
	  this->number = count;
	  this->count = 0;
	  this->color = palval;
	  this->next = *palp;
	  *palp = this;
	}

      *palette_index++ = this;
    }
  while (++count < 16);

  return 0;
}

/* Do the conversion.  */
static int
convert (FILE *fp, MAP *map, PALETTE **pal_index, int planes)
{
  int y;
  int bit;
  unsigned short *screen = alloca (planes * sizeof (unsigned short));

  screen = alloca (planes * sizeof (unsigned short));
  if (!screen)
    {
      view_message (0, "alloca");
      exit (1);
    }

  bit = 0;
  y = 0;
  do
    {
      int x;
      COLOR *line = map->image[y];

      x = 0;
      do
	{
	  int c;
	  int plane;

	  if (bit)
	    --bit;
	  else
	    {
	      unsigned short *screenp;

	      screenp = screen;
	      plane = planes;
	      while (plane--)
		{
		  if (read_big16 (screenp++, fp))
		    return 1;
		}
	      bit = 15;
	    }

	  c = 0;
	  plane = planes;
	  while (plane--)
	    c |= ((screen[plane] >> bit) & 1) << plane;

	  *line++ = pal_index[c]->number;
	  ++pal_index[c]->count;
	}
      while (++x < map->width);
      status_bar (y, map->height);
    }
  while (++y < map->height);

  return 0;
}

/* Try to read a Degas picture.  */
int
maybe_read_degas (FILE *fp, const char *file, MAP *map)
{
  int width;
  int height;
  int planes;
  short mode;
  PALETTE **pal_index;

  if (read_big16 (&mode, fp))
    return 1;

  switch (mode)
    {
    case 0:			/* Low rez. */
      width = 320;
      height = 200;
      planes = 4;
      break;
    case 1:			/* Medium rez. */
      width = 640;
      height = 200;
      planes = 2;
      break;
    case 2:			/* Hi rez. */
      width = 640;
      height = 400;
      planes = 1;
      break;
    default:
      return 1;
    }

  alloc_image (map, width, height);
  pal_index = alloca (16 * sizeof (PALETTE *));
  if (!pal_index)
    {
      view_message (0, "alloca");
      exit (1);
    }

  if (read_pal (fp, map, pal_index) || convert (fp, map, pal_index, planes))
    return 1;

  return 0;
}
