/*
 * $Id: $
 */

/*
 * Mesa 3-D graphics library
 * Copyright (C) 1995  Brian Paul  (brianp@ssec.wisc.edu)
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the Free
 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <AOS/amigamesa.h>
#include <AOS/ht_palettes.c>
#include <graphics/view.h>

ULONG RGBAColorMap[256];

static BOOL AllocColors(struct ColorEntry *Cols, LONG Number, struct Screen *Screen)
{
  LONG i, pen;
  BOOL fail = GL_TRUE;
  ULONG ColTab[3];
  struct ColorMap *ColorMap = Screen->ViewPort.ColorMap;

  for (i = 0; i < Number; i++) {
    pen = ObtainBestPen(ColorMap, c8toc32(Cols[i].orgEntry.r),
				  c8toc32(Cols[i].orgEntry.g),
				  c8toc32(Cols[i].orgEntry.b),
				  OBP_Precision, PRECISION_EXACT, TAG_DONE);
    if ((Cols[i].PenNo = pen) == -1)
      fail = GL_FALSE;
    else {
      GetRGB32(ColorMap, pen, 1, ColTab);
      Cols[i].mapEntry.r = ColTab[0] >> 24;
      Cols[i].mapEntry.g = ColTab[1] >> 24;
      Cols[i].mapEntry.b = ColTab[2] >> 24;
    }
  }

  for (i = 0; i < ColorMap->Count; i++) {
    GetRGB32(ColorMap, i, 1, ColTab);
    RGBAColorMap[i] = ((ColTab[0] >>  0) & 0xFF000000) |
		      ((ColTab[1] >>  8) & 0x00FF0000) |
		      ((ColTab[2] >> 16) & 0x0000FF00) | 0;
  }

  return (BOOL) fail;
}

static void FreeColors(struct ColorEntry *Cols, LONG Number, struct Screen *Screen)
{
  LONG i;

  for (i = 0; i < Number; i++)
    ReleasePen(Screen->ViewPort.ColorMap, Cols[i].PenNo);
}

#define sqr(x) ((x)*(x))

#define	CACHED	0xFF
#define	INVALID	0x00
static struct {
  unsigned char PenNo, R, B, valid;
} penCache[256];

ULONG GetPen(register unsigned char R __asm__ ("d0"),
	     register unsigned char G __asm__ ("d1"),
	     register unsigned char B __asm__ ("d2"))
{
  short int i;
  struct ColorEntry *entries;
  ULONG pen;

  if(tryCached) {
#define	cachedPen	pen
    /* use R as LUT 'cause it has the middle energy */
    if((cachedPen = *((ULONG *)&penCache[G]))) {
      cachedPen >>= 8;
      if((unsigned char)cachedPen == (unsigned char)B) {
        cachedPen >>= 8;
        if((unsigned char)cachedPen == (unsigned char)R) {
          cachedPen >>= 8;
          return cachedPen;
        }
      }
    }
    cachedPen = ((((R << 8) | B) << 8) | CACHED);
    *((ULONG *)&penCache[G]) = cachedPen;
  }

  if (trueColor) {
    entries = pal332;
    i = htc_NumCols332 - 1;
  }
  else {
    entries = pal;
    i = htc_NumCols - 1;
  }
  pen = 0;
  
  {
    /* infinite bad start-match */
    int match = 0x7FFFFFFF;
    
    // find match 
    for (; i >= 0; i--) {
      int sum;
      int thismatch;
    
      if ((thismatch = (ULONG)(entries[i].mapEntry.r) - (ULONG)R) < 0)
        thismatch = -thismatch;
      if ((sum = (ULONG)(entries[i].mapEntry.g) - (ULONG)G) < 0)
        sum = -sum;
      thismatch += sum;
      if ((sum = (ULONG)(entries[i].mapEntry.b) - (ULONG)B) < 0)
        sum = -sum;
      if((thismatch += sum) != 0) {
        if (match > thismatch) {
          match = thismatch;
          pen = i;
        }
      }
      else {
        pen = i;
        break;
      }
    }
    pen = (ULONG)(entries[pen].PenNo);
  }

  if(tryCached)
    penCache[G].PenNo = (unsigned char)(pen);

  return pen;
}

void AllocCMap(struct Screen *Scr)
{
  if(tryCached)
    bzero(penCache, sizeof(penCache));

  if(!trueColor)
    AllocColors(pal, htc_NumCols, Scr);
  else
    AllocColors(pal332, htc_NumCols332, Scr);
}

void FreeCMap(struct Screen *Scr)
{
  if(!trueColor)
    FreeColors(pal, htc_NumCols, Scr);
  else
    FreeColors(pal332, htc_NumCols332, Scr);
}
