/*
 * Author:      Yoichiro Ueno (ueno@cs.titech.ac.jp)
 *
 * Copyright (C) 1991, 1992, Yoichiro Ueno.
 *
 * Permission to use, copy, modify, and distribute this software and
 * its documentation for any purpose is hereby granted by the Author without
 * fee, provided that the above copyright notice appear in all copies and
 * that both the copyright notice and this permission notice appear in
 * supporting documentation, and that the name of the Author not be used
 * in advertising or publicity pertaining to distribution of the software
 * without specific, written prior permission.  The Author makes no
 * representations about the suitability of this software for any purpose.
 * It is provided "as is" without express or implied warranty.
 *
 * THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
 * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
 *
 */

#include "video.h"
#include "dither.h"


/*
 *--------------------------------------------------------------
 *
 * MonoDitherImage --
 *
 *      Dithers image into monochrome.
 *      Dither algorithm is based on dither.c in xli.1.11.
 *
 * Results:
 *      None.
 *
 * Side effects:
 *      None.
 *
 *--------------------------------------------------------------
 */
#define MaxGrey         65280
#define Threshold       (MaxGrey/2)
#define MinGrey         0

static int      *curr = NULL;
static int      *next = NULL;
static int      *pcurr = NULL;
static int      *pnext = NULL;

void FreeMonoDither(void)
{
  MyFree(&pcurr);
  MyFree(&pnext);
}

void
MonoDitherImage(lum, cr, cb, out, h, w)
    register unsigned char *lum;
    unsigned char *cr;
    unsigned char *cb;
    register unsigned char *out;
    int w, h;
{
  int bit_r2l;
  register unsigned int bit;
  register unsigned int data;
  int i;
  register int j;
  int *swap;
  register int out_err;
  register int next1;
  register int next2;

  if(pcurr == NULL) {
    curr = pcurr = (int *)MyMalloc(sizeof(int) * (w + 2));
    curr += 1;
  }
  if(pnext == NULL) {
    next = pnext = (int *)MyMalloc(sizeof(int) * (w + 2));
    next += 1;
  }

  bzero ((char *)curr, w * sizeof(*curr));

  bit_r2l = 0x80 >> (w - 1 & 7);
  for(i = 0; i < h; i ++) {
    if(i & 0x01) {                              /* Right to Left */
      bit = bit_r2l;
      data = 0;
      out_err = curr[w-1];
      next1 = 0;
      next2 = 0;
      for (j=(w-1); j>=0; j--)
      {
        out_err = (out_err >> 4) + (lum[j] << 8);
        if(out_err > Threshold) {
          data |= bit;
          out_err -= MaxGrey;
        }
        else
          out_err -= MinGrey;

        next[j+1] = next1 +     (out_err * 3);
        next1     = next2 +     (out_err * 5);
        next2     =             (out_err * 1);
        out_err   = curr[j-1] + (out_err * 7);

        bit <<= 1;
        if(bit > 0x80) {
          out[j >> 3] = data;
          bit = 0x01;
          data = 0;
        }
      }
      next[0] = next1;
    }
    else {                                      /* Left to Right */
      bit = 0x80;
      data = 0;
      out_err = curr[0];
      next1 = 0;
      next2 = 0;
      for (j=0; j<w; j++)
      {
        out_err = (out_err >> 4) + (lum[j] << 8);
        if(out_err > Threshold) {
          data |= bit;
          out_err = out_err - MaxGrey;
        }
        else
          out_err = out_err - MinGrey;

        next[j-1] = next1 +     (out_err * 3);
        next1     = next2 +     (out_err * 5);
        next2     =             (out_err * 1);
        out_err   = curr[j+1] + (out_err * 7);

        bit >>= 1;
        if(bit == 0) {
          out[j >> 3] = data;
          bit = 0x80;
          data = 0;
        }
      }
      next[w-1] = next1;
    }
    
    lum += w;
    out += w >> 3;
    swap = curr;
    curr = next;
    next = swap;
  }
}


/*
 *--------------------------------------------------------------
 *
 * MonoThresholdImage --
 *
 *      convert image into monochrome with threshold.
 *
 * Results:
 *      None.
 *
 * Side effects:
 *      None.
 *
 *--------------------------------------------------------------
 */
void
MonoThresholdImage(lum, cr, cb, out, h, w)
    unsigned char *lum;
    unsigned char *cr;
    unsigned char *cb;
    unsigned char *out;
    int w, h;
{
  unsigned char bit;
  unsigned char data;

  bit = 0x80;
  data = 0;
  for (w*=h; w>0; w--) {
    if(*lum++>128)
      data |= bit;

    bit >>= 1;
    if(bit == 0) {
      *out ++ = data;
      bit = 0x80;
      data = 0;
    }
  }
}
