/*----------------------------------------------------------------------------*
 | This file is part of DEU (Doom Editing Utilities), created by the DEU team:|
 | Raphael Quinet, Brendon Wyber, Ted Vessenes and others.  See README.1ST or |
 | the "about" dialog box for full credits.                                   |
 |                                                                            |
 | DEU is an open project: if you think that you can contribute, please join  |
 | the DEU team.  You will be credited for any code (or ideas) included in    |
 | the next version of the program.                                           |
 |                                                                            |
 | If you want to make any modifications and re-distribute them on your own,  |
 | you must follow the conditions of the DEU license.  Read the file LICENSE  |
 | in this directory or README.1ST in the top directory.  If do not have a    |
 | copy of these files, you can request them from any member of the DEU team, |
 | or by mail: Raphael Quinet, Rue des Martyrs 9, B-4550 Nandrin (Belgium).   |
 |                                                                            |
 | This program comes with absolutely no warranty.  Use it at your own risks! |
 *----------------------------------------------------------------------------*

 G_COLCNV.C - Color conversion routines (16 or 256 colors palette)

 Functions created by Ted Vessenes
*/

/* the includes */
#include "deu.h"
#include <math.h>
#include "d_main.h"
#include "d_misc.h"
#include "d_wads.h"
#include "g_gfx.h"
#include "g_colcnv.h"

extern int num_colors; /* from g_gfx*.c */


/*
   Translate an RGB color to an HSV color.
*/

static void TranslateToHSV(int r, int g, int b, UInt8 huge *h, UInt8 huge *s, UInt8 huge *v)
{
  int maxcol, mincol;

  maxcol = MAX(r, MAX(g, b));
  mincol = MIN(r, MIN(g, b));
  *v = maxcol;
  if (maxcol == mincol)
    {
      *h = 000;
      *s = 0;
    }
  else
    {
      *s = MIN((256 * (maxcol - mincol)) / maxcol, 0xFF);
      if (mincol == b)
        *h =       85 * (g - mincol) / (r + g - 2 * mincol);
      else if (mincol == r)
        *h =  86 + 85 * (b - mincol) / (b + g - 2 * mincol);
      else
        *h = 171 + 85 * (r - mincol) / (r + b - 2 * mincol);
    }
}



/*
   Computes the distance between a VGA HSV color and an EGA color.
*/

static long HSVDist(int h, int s, int v, int ega)
{
  /*! These values might need to be tweaked */
  /* Note that this ega palette is in HSV */
  int egapal[0x30] = { 000,   0,   0,   171, 256, 170,
                        85, 256, 170,   128, 256, 170,
                         0, 256, 170,   213, 256, 170,
          /* Brown */   27, 256, 170,   000,   0, 192,
                       000,   0, 128,   171, 256, 256,
                        85, 256, 256,   128, 256, 256,
                         0, 256, 256,   213, 256, 256,
                        43, 256, 256,   000,   0, 256};
  long  height, dist, S;
  double theta, temp;

  if (DoomVersion < 16)
    {
      egapal[3 *      CYAN    ] = 171;
      egapal[3 * LIGHTCYAN    ] = 171;
      egapal[3 *      CYAN + 1] = 128;
      egapal[3 * LIGHTCYAN + 1] =  64;
    }

  theta = 3.14159 * (double)(egapal[3 * ega] - h) / 128.0;
  S = egapal[3 * ega + 1];

  height = egapal[3 * ega + 2] - v;
  temp = (2.0 * (double)s * (double)S * cos(theta));
  dist = (long)s * (long)s + S * S - (long)temp;
  return (3 * (height * height) + 2 * dist); /* Good place to add in weights */
}


/*
   Translate a standard color to Doom palette 0 (approx.).
*/

int TranslateToDoomColor(int color16)
{
  static int  translate[16];
  static Bool init = FALSE;
  int         ega, vga;
  long        dist, curdist;
  int         best = 0;
  MDirPtr     dir;
  UInt8 huge *dpal;

  if (num_colors == 16)
    return color16;

  if (!init)
    {
      dir = FindMasterDir(MasterDir, "PLAYPAL");
      if (dir)
        {
          dpal = (UInt8 huge *)GetFarMemory(768L);
          BasicWadSeek(dir->wadfile, dir->dir.start);
          BasicWadRead(dir->wadfile, dpal, 768L);
        }

      for (vga = 0; vga < 0x100; vga++)
        TranslateToHSV( dpal[3 * vga],  dpal[3 * vga + 1],  dpal[3 * vga + 2],
                       &dpal[3 * vga], &dpal[3 * vga + 1], &dpal[3 * vga + 2]);

      for (ega = 0; ega < 0x10; ega++)
        {
          dist = 0x7FFFFFFFL;
          for (vga = 0; vga < 0x100; vga++)
            {
              curdist = HSVDist(dpal[3 * vga], dpal[3 * vga + 1], dpal[3 * vga + 2],
                                ega);
              if (curdist < dist)
                {
                  dist = curdist;
                  best = vga;
                }
            }
          translate[ega] = best;
        }

      FreeFarMemory(dpal);
      init = TRUE;
    }
  return translate[color16];
}


/*
   Translate a Doom palette 0 color to a standard color (approx.).
*/

int TranslateTo16Color(int color256)
{
  static int  translate[256];
  static Bool init = FALSE;
  UInt8       h, s, v;
  int         ega, vga;
  long        dist, curdist;
  int         best = 0;
  MDirPtr     dir;
  UInt8 huge *dpal;

  if (num_colors == 256)
    return color256;

  if (!init)
    {
      dir = FindMasterDir(MasterDir, "PLAYPAL");
      if (dir)
        {
          dpal = (UInt8 huge *)GetFarMemory(768L);
          BasicWadSeek(dir->wadfile, dir->dir.start);
          BasicWadRead(dir->wadfile, dpal, 768L);
        }

      for (vga = 0; vga < 0x100; vga++)
        {
          TranslateToHSV(dpal[3 * vga], dpal[3 * vga + 1], dpal[3 * vga + 2],
                         &h, &s, &v);
          dist = 0x7FFFFFFFL;
          for (ega = 0; ega < 0x10; ega++)
            {
              curdist = HSVDist(h, s, v, ega);
              if (curdist < dist)
                {
                  dist = curdist;
                  best = ega;
                }
            }
          translate[vga] = best;
        }

      FreeFarMemory(dpal);
      init = TRUE;
    }
  return translate[color256];
}


/* end of file */
