/*
 * This software is copyrighted as noted below.  It may be freely copied,
 * modified, and redistributed, provided that the copyright notice is
 * preserved on all copies.
 *
 * There is no warranty or other guarantee of fitness for this software,
 * it is provided solely "as is".  Bug reports or fixes may be sent
 * to the author, who may or may not act on them as he desires.
 *
 * You may not include this software in a program or other software product
 * without supplying the source, or without informing the end-user that the
 * source is available for no extra charge.
 *
 * If you modify this software, you should include a notice giving the
 * name of the person performing the modification, the date of modification,
 * and the reason for such modification.
 */
/*
 * mask.c - perform transformations using masks.
 *
 * Author:      Raul Rivero
 *              Mathematics Dept.
 *              University of Oviedo
 * Date:        Mon Jan 6 1992
 * Copyright (c) 1992, Raul Rivero
 *
 */

#include <lug.h>
#include <lugfnts.h>
#define BLUETOP                 175

#define mvptrs()        rb++, gb++, bb++; rm++, gm++, bm++; rs++, gs++, bs++;

chroma_mask( base, mask, super, outbitmap )
bitmap_hdr *base, *mask, *super;
bitmap_hdr *outbitmap;
{
  byte *rb, *gb, *bb;           /* base pointers */
  byte *rm, *gm, *bm;           /* base mask */
  byte *rs, *gs, *bs;           /* base super*/
  byte *r, *g, *b;
  byte *end;
  double position;
  int totalsize;

  /*
   * Fill our new header and allocate memory.
   */
  outbitmap->magic = LUGUSED;
  outbitmap->xsize = base->xsize;
  outbitmap->ysize = base->ysize;
  outbitmap->depth = base->depth;
  outbitmap->colors = base->colors;
  totalsize = outbitmap->xsize * outbitmap->ysize;
  r = outbitmap->r = (byte *) Malloc( totalsize );
  g = outbitmap->g = (byte *) Malloc( totalsize );
  b = outbitmap->b = (byte *) Malloc( totalsize );

  /*
   * Set the pointers.
   */
  rb = base->r  , gb = base->g  , bb = base->b;
  rm = mask->r  , gm = mask->g  , bm = mask->b;
  rs = super->r , gs = super->g , bs = super->b;

  end = r + totalsize;
  while ( r < end ) {
    if ( (*rm + *gm + *bm) > CHROMAMASK ) {
      /*
       * The current point has red as component, then we
       * change this point with the super current point.
       */
      *r++ = *rs;
      *g++ = *gs;
      *b++ = *bs;
      mvptrs();
    }else {
      *r++ = *rb;
      *g++ = *gb;
      *b++ = *bb;
      mvptrs();
    }
  }

  /* No errors */
  return 0;
}

chroma_shadow_mask( base, mask, super, outbitmap )
bitmap_hdr *base, *mask, *super;
bitmap_hdr *outbitmap;
{
  byte *rb, *gb, *bb;           /* base pointers */
  byte *rm, *gm, *bm;           /* base mask */
  byte *rs, *gs, *bs;           /* base super*/
  byte *r, *g, *b;
  byte *end;
  double position;
  int totalsize;

  if ( base->magic != LUGUSED || mask->magic != LUGUSED )
    error( 19 );

  /*
   * Fill our new header and allocate memory.
   */
  outbitmap->magic = LUGUSED;
  outbitmap->xsize = base->xsize;
  outbitmap->ysize = base->ysize;
  outbitmap->depth = base->depth;
  outbitmap->colors = base->colors;
  totalsize = outbitmap->xsize * outbitmap->ysize;
  r = outbitmap->r = (byte *) Malloc( totalsize );
  g = outbitmap->g = (byte *) Malloc( totalsize );
  b = outbitmap->b = (byte *) Malloc( totalsize );

  /*
   * Set the pointers.
   */
  rb = base->r  , gb = base->g  , bb = base->b;
  rm = mask->r  , gm = mask->g  , bm = mask->b;
  rs = super->r , gs = super->g , bs = super->b;

  end = r + totalsize;
  while ( r < end ) {
    if ( *rm > 0 ) {
      /*
       * The current point has red as component, then we
       * change this point with the super current point.
       */
      *r++ = *rs;
      *g++ = *gs;
      *b++ = *bs;
      mvptrs();
    }else {
      if ( *bm > BLUETOP ) {
        /*
         * If the current blue is greater than BLUETOP then
         * we change this pixel with the current base pixel.
         */
        *r++ = *rb;
        *g++ = *gb;
        *b++ = *bb;
        mvptrs();
      }else {
        /*
         * Well ... we have a shadow !!!, so we darken
         * the current base pixel.
         */
        position = *bm / 255.;
        *r++ = (byte) ( *rb * position );
        *g++ = (byte) ( *gb * position );
        *b++ = (byte) ( *bb * position );
        mvptrs();
      }
    }
  }

  /* No errors */
  return 0;
}

mask_change_color( base, mask, outbitmap, newr, newg, newb )
bitmap_hdr *base, *mask, *outbitmap;
int newr, newg, newb;
{
  byte *rb, *gb, *bb;           /* base pointers */
  byte *rm, *gm, *bm;           /* base mask */
  byte *r, *g, *b;
  byte *end;
  int totalsize;
  double newh, news, newl;
  double h, s, l;

  if ( base->xsize != mask->xsize || base->ysize != mask->ysize )
    error( 9 );

  /*
   * Translate new color ( rgb ) to hsl format.
   */
  RGB_to_HSL( newr, newg, newb, &newh, &news, &newl );

  /*
   * Fill our new header and allocate memory.
   */
  outbitmap->magic = LUGUSED;
  outbitmap->xsize = base->xsize;
  outbitmap->ysize = base->ysize;
  outbitmap->depth = base->depth;
  outbitmap->colors = base->colors;
  totalsize = outbitmap->xsize * outbitmap->ysize;
  r = outbitmap->r = (byte *) Malloc( totalsize );
  g = outbitmap->g = (byte *) Malloc( totalsize );
  b = outbitmap->b = (byte *) Malloc( totalsize );

  /*
   * Set the pointers.
   */
  rb = base->r  , gb = base->g, bb = base->b;
  rm = mask->r  , gm = mask->g, bm = mask->b;

  end = r + totalsize;
  while ( r < end ) {
    if ( ( (*rm++) + (*gm++) + (*bm++) ) > CHROMAMASK ) {
      /*
       * The mask has been actived, so we need change
       * this pixel with our new color.
       */
      RGB_to_HSL( *rb++, *gb++, *bb++, &h, &s, &l );
      HSL_to_RGB( newh, news, l, r++, g++, b++ );
    }else {
      /*
       * No mask, so we copy the base image.
       */
      *r++ = *rb++;
      *g++ = *gb++;
       *b++ = *bb++;
    }
  }

  /* No errors */
  return 0;
}

mask_change_to_bw( base, mask, outbitmap )
bitmap_hdr *base, *mask, *outbitmap;
{
  byte *rb, *gb, *bb;           /* base pointers */
  byte *rm, *gm, *bm;           /* base mask */
  byte *r, *g, *b;
  byte *end;
  int totalsize;
  int value;

  if ( base->xsize != mask->xsize || base->ysize != mask->ysize )
    error( 9 );

  /*
   * Fill our new header and allocate memory.
   */
  outbitmap->magic = LUGUSED;
  outbitmap->xsize = base->xsize;
  outbitmap->ysize = base->ysize;
  outbitmap->depth = base->depth;
  outbitmap->colors = base->colors;
  totalsize = outbitmap->xsize * outbitmap->ysize;
  r = outbitmap->r = (byte *) Malloc( totalsize );
  g = outbitmap->g = (byte *) Malloc( totalsize );
  b = outbitmap->b = (byte *) Malloc( totalsize );

  /*
   * Set the pointers.
   */
  rb = base->r  , gb = base->g, bb = base->b;
  rm = mask->r  , gm = mask->g, bm = mask->b;

  end = r + totalsize;
  while ( r < end ) {
    if ( ( (*rm++) + (*gm++) + (*bm++) ) > CHROMAMASK ) {
      /*
       * The mask has been actived, so we need change
       * this pixel with our new color.
       */
      value = RGB_to_BW( *rb++, *gb++, *bb++ );
      *r++ = value;
      *g++ = value;
      *b++ = value;
    }else {
      /*
       * No mask, so we copy the base image.
       */
      *r++ = *rb++;
      *g++ = *gb++;
      *b++ = *bb++;
    }
  }

  /* No errors */
  return 0;
}

mask_darken_color( base, mask, outbitmap )
bitmap_hdr *base, *mask, *outbitmap;
{
  byte *rb, *gb, *bb;           /* base pointers */
  byte *rm, *gm, *bm;           /* base mask */
  byte *r, *g, *b;
  byte *end;
  int totalsize;
  double h, s, l;

  if ( base->xsize != mask->xsize || base->ysize != mask->ysize )
    error( 9 );

  /*
   * Fill our new header and allocate memory.
   */
  outbitmap->magic = LUGUSED;
  outbitmap->xsize = base->xsize;
  outbitmap->ysize = base->ysize;
  outbitmap->depth = base->depth;
  outbitmap->colors = base->colors;
  totalsize = outbitmap->xsize * outbitmap->ysize;
  r = outbitmap->r = (byte *) Malloc( totalsize );
  g = outbitmap->g = (byte *) Malloc( totalsize );
  b = outbitmap->b = (byte *) Malloc( totalsize );

  /*
   * Set the pointers.
   */
  rb = base->r  , gb = base->g, bb = base->b;
  rm = mask->r  , gm = mask->g, bm = mask->b;

  end = r + totalsize;
  while ( r < end ) {
    if ( ( (*rm++) + (*gm++) + (*bm++) ) > CHROMAMASK ) {
      /*
       * The mask has been actived, so we need change
       * this pixel with our new color.
       */
      RGB_to_HSL( *rb++, *gb++, *bb++, &h, &s, &l );
      HSL_to_RGB( h, s/2., l/1.5, r++, g++, b++ );
    }else {
      /*
       * No mask, so we copy the base image.
       */
      *r++ = *rb++;
      *g++ = *gb++;
      *b++ = *bb++;
    }
  }

  /* No errors */
  return 0;
}

fade_mask( base, super, mask, out )
bitmap_hdr *base, *super, *mask;
bitmap_hdr *out;
{
  byte *rb, *gb, *bb;           /* base pointers */
  byte *rm, *gm, *bm;           /* mask pointers */
  byte *rs, *gs, *bs;           /* super pointers */
  byte *ro, *go, *bo;
  byte *end;
  double percent, neg_percent;
  double aux;
  int totalsize = base->xsize * base->ysize;

  /* We have images really ? */
  if ( base->magic  != LUGUSED ||
       super->magic != LUGUSED ||
       mask->magic  != LUGUSED )
    error( 19 );

  /*
   * Check if the width and height of the input images are the
   * same. A trick: add all values an multiply one by 3 ( it
   * no perfect ... but almost ).
   */
  if ( (base->xsize + super->xsize + mask->xsize) != 3 * base->xsize )
    error( 12 );
  if ( (base->ysize + super->ysize + mask->ysize) != 3 * mask->ysize )
    error( 12 );

  /* Create the new image ( alloc memory, fill the header, ... ) */
  create_solid_image( out, base->xsize, base->ysize, 0, 0, 0 );

  /*
   * Set the pointers.
   */
  rb = base->r  , gb = base->g  , bb = base->b;
  rs = super->r , gs = super->g , bs = super->b;
  rm = mask->r  , gm = mask->g  , bm = mask->b;
  ro = out->r   , go = out->g   , bo = out->b;

  /* Lets go ! */
  end = rb + totalsize;
  while ( rb < end ) {
    /*
     * Calculate the percent of transparency.
     */
    percent = *rm++ / 255.;
    neg_percent = 1. - percent;

    /*
     * Ok, now we know what need from one and another image ( the
     * percent and negate percent ), so ...
     */
    aux = percent * (double) *rb++ + neg_percent * (double) *rs++;
    *ro++ = (int) aux;
    aux = percent * (double) *gb++ + neg_percent * (double) *gs++;
    *go++ = (int) aux;
    aux = percent * (double) *bb++ + neg_percent * (double) *bs++;
    *bo++ = (int) aux;
  }

  /* No errors */
  return 0;
}
