/*$cb
 *    This file is a part of OpenMHP VDR plugin.
 *
 *    Copyright (C) 2005 Mikko Novaro <miknov@gmail.com>
 *
 *    See README file for licensing and contact information.
 $ce*/

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

/* Reduces an 8bit component of 256 possible values to 8bit/"n"
 * possible values. */
int Reduce256toN(int val, int n) {
  int step = 256/(n-1);
  int stepCnt = 0;
  while (val >= (step/2)) {
    val -= step;
    stepCnt++;
  }
  int result = step*stepCnt;
  if (result > 255) result = 255;
  return result;
}


/* Reduce number of colours using dithering.
 * Compress a 8bit colour component of 256 possible values
 * 8bit/"n" possible values (as specified by "values" argument).
 */
int Dither(int component, int values, int &error) {
  int c = Reduce256toN(component + error, values);
  error = component - c;
  return c;
}


#define MAX_IMAGE_WIDTH 750

int ReduceColors(int col, int valuesPerComponent, bool dither, int imageWidth) {

  static int ea[MAX_IMAGE_WIDTH+1];
  static int er[MAX_IMAGE_WIDTH+1];
  static int eg[MAX_IMAGE_WIDTH+1];
  static int eb[MAX_IMAGE_WIDTH+1];
  static int pos;

  int a = (col >> 24) & 0xFF;
  int r = (col >> 16) & 0xFF;
  int g = (col >> 8) & 0xFF;
  int b = col & 0xFF;

  int aq = Reduce256toN(a+ea[pos], valuesPerComponent);
  int rq = Reduce256toN(r+er[pos], valuesPerComponent);
  int gq = Reduce256toN(g+eg[pos], valuesPerComponent);
  int bq = Reduce256toN(b+eb[pos], valuesPerComponent);

  if (dither) {
    ea[pos] = a - aq;
    er[pos] = r - rq;
    eg[pos] = g - gq;
    eb[pos] = b - bq;
    
    // distribute the error from the visited pixel:
    int pos1 = (pos+1)%imageWidth+1;
    
    ea[pos1] += (ea[pos] >> 5) * 7;
    er[pos1] += (er[pos] >> 5) * 7;
    eg[pos1] += (eg[pos] >> 5) * 7;
    eb[pos1] += (eb[pos] >> 5) * 7;
    
    int pos2 = (pos+imageWidth-1)%imageWidth+1;
    
    ea[pos2] += (ea[pos] >> 5) * 3;
    er[pos2] += (er[pos] >> 5) * 3;
    eg[pos2] += (eg[pos] >> 5) * 3;
    eb[pos2] += (eb[pos] >> 5) * 3;
    
    int pos3 = (pos+imageWidth)%imageWidth+1;
    
    ea[pos3] += (ea[pos] >> 5) * 5;
    er[pos3] += (er[pos] >> 5) * 5;
    eg[pos3] += (eg[pos] >> 5) * 5;
    eb[pos3] += (eb[pos] >> 5) * 5;
    
    int pos4 = (pos+imageWidth+1)%imageWidth+1; // !! always the current position !!
    
    ea[pos4] = (ea[pos] >> 5) * 1;
    er[pos4] = (er[pos] >> 5) * 1;
    eg[pos4] = (eg[pos] >> 5) * 1;
    eb[pos4] = (eb[pos] >> 5) * 1;
    
    pos = (pos+1) % imageWidth+1;
  }

  return (aq << 24) | (rq << 16) | (gq << 8) | bq;
}
