/**********************************************************************
This file is part of Crack dot Com's free source code release of Golgotha.
for information about compiling & licensing issues visit this URL
 If that doesn't help, contact Jonathan Clark at 
  golgotha_source@usa.net (Subject should have "GOLG" in it) 
***********************************************************************/

#include "arch.hh"
#include "quantize/median.hh"
#include "quantize/histogram.hh"
#include 
#include "memory/malloc.hh"

// counts for each color, global so that it can be accessed by qsort function
static w32 *counts;   


static int red_compare(const void *a, const void *b)
{
  w16 color1=counts[*((w16 *)a)],
      color2=counts[*((w16 *)b)];

  return ((sw32) ((color1 & (  (1 | 2 | 4 | 8 | 16) << 11))>>11))-
    ((sw32) ((color2 & (  (1 | 2 | 4 | 8 | 16) << 11))>>11));
}


static int green_compare(const void *a, const void *b)
{
  w16 color1=counts[*((w16 *)a)],
      color2=counts[*((w16 *)b)];

  return ((sw32) (color1 & (  (1 | 2 | 4 | 8 | 16 | 32) << 5)))-
         ((sw32) (color2 & (  (1 | 2 | 4 | 8 | 16 | 32) << 5)));
}


static int blue_compare(const void *a, const void *b)
{
  w16 color1=counts[*((w16 *)a)],
      color2=counts[*((w16 *)b)];

  return ((sw32) (color1 & (  (1 | 2 | 4 | 8 | 16) << 0)))-
         ((sw32) (color2 & (  (1 | 2 | 4 | 8 | 16) << 0)));
}


struct box
{
  w32 index;
  w32 colors;
  w32 sum;
};

static int box_compare(const void *a, const void *b)
{
  return ((box *)b)->sum-((box *)a)->sum;
}

inline void _16_to_rgb(w32 rgb, w8 &r, w8 &g, w8 &b)
{
  b=(rgb & (1 | 2 | 4 | 8 | 16))<<3;
  rgb>>=5;

  g=(rgb & (1 | 2 | 4 | 8 | 16 | 32))<<2;
  rgb>>=6;

  r=(rgb & (1 | 2 | 4 | 8 | 16))<<3;
}

void i4_median_cut(i4_histogram_class *hist, 
                   w32 skip_colors,
                   w32 t_colors,
                   w32 *return_palette)
                                  
{
  enum { HIST_SIZE=0x10000,  // 16 bit histogram table
         MAX_COLORS=256 };
  
  counts=hist->counts;

  box *box_list=(box *)i4_malloc(sizeof(box) * MAX_COLORS, "boxes");

  // setup the initial box
  w32 total_boxes    = 1;
  box_list[0].index  = 0;
  box_list[0].colors = hist->tcolors;
  box_list[0].sum    = hist->total_pixels;

  w32 box_index;
  w32 loop_count;

  // split boxes until we have all the colors
  while ( total_boxes < t_colors-skip_colors )
  {
    // Find the first splittable box.
    for ( box_index = 0; box_index < total_boxes; ++box_index )
      if (box_list[box_index].colors >= 2)
        break;

    if ( box_index == total_boxes)
      break;	/* ran out of colors! */


    w32 start = box_list[box_index].index;
    w32 end   = start + box_list[box_index].colors;

    w8  min_r=0xff, max_r=0x00,
        min_g=0xff, max_g=0x00,
        min_b=0xff, max_b=0x00,
        r,g,b;

    
    // now find the minimum and maximum r g b values for this box
    for (loop_count = start; loop_countreference[loop_count],r,g,b);

      if (r>max_r) max_r=r;
      if (rmax_g) max_g=g;
      if (gmax_b) max_b=b;
      if (b= (max_g - min_g)) && ((max_r - min_r) >= (max_b - min_b)))
      qsort(hist->reference + start,
          end-start,             // total elements to sort
          sizeof(w16),
          red_compare);
    else if ( (max_g - min_g) >= (max_b - min_b) )
      qsort(hist->reference + start,
          end-start,             // total elements to sort
          sizeof(w16),
          green_compare);
    else
      qsort(hist->reference + start,
          end-start,             // total elements to sort
          sizeof(w16),
          blue_compare);



    // now find the division which closest divides into an equal number of pixels
    w32 low_count= counts[hist->reference[start]];
    w32 mid_number=box_list[box_index].sum/2;

    for (loop_count = start+1; loop_countreference[loop_count]];


    // now split the box
    box_list[total_boxes].index  = loop_count;
    box_list[total_boxes].colors = end-loop_count;
    box_list[total_boxes].sum    = box_list[box_index].sum-low_count;
    total_boxes++;

    box_list[box_index].colors= loop_count-start;
    box_list[box_index].sum   = low_count;

    // sort to bring the biggest boxes to the top
    qsort(box_list, total_boxes, sizeof(box), box_compare );    

    /*    for (int z=0;zreference[loop_count],r,g,b);
      
      r_tot+=r;
      g_tot+=g;
      b_tot+=b;
    }

    r_tot/=(end-start);
    g_tot/=(end-start);
    b_tot/=(end-start);

    return_palette[box_index+skip_colors] = (r_tot<<16)|
      (g_tot<<8) |
      b_tot;
  }

  for (;box_index + skip_colors