/* -*- c++ -*-
 * gimp.h: Header for a Qt 3 plug-in for reading GIMP XCF image files
 * Copyright (C) 2001 lignum Computing, Inc. <allen@lignumcomputing.com>
 * $Id: gimp.h,v 1.1.1.1 2001/11/03 15:30:43 allen Exp $
 *
 * This plug-in is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */

/*
 * These are the constants and functions I extracted from The GIMP source
 * code. If the reader fails to work, this is probably the place to start
 * looking for discontinuities.
 */

// From GIMP "tile.h" v1.2

const uint TILE_WIDTH = 64;	//!< Width of a tile in the XCF file.
const uint TILE_HEIGHT = 64;	//!< Height of a tile in the XCF file.

// From GIMP "paint_funcs.c" v1.2

const int RANDOM_TABLE_SIZE = 4096; //!< Size of dissolve random number table.
const int RANDOM_SEED = 314159265; //!< Seed for dissolve random number table.
const double EPSILON = 0.0001;	//!< Roundup in alpha blending.

// From GIMP "paint_funcs.h" v1.2

const uchar OPAQUE_OPACITY = 255; //!< Opaque value for 8-bit alpha component.

// From GIMP "apptypes.h" v1.2

//! Basic GIMP image type. QImage converter may produce a deeper image
//! than is specified here. For example, a grayscale image with an
//! alpha channel must (currently) use a 32-bit Qt image.

typedef enum
{
  RGB,
  GRAY,
  INDEXED
} GimpImageBaseType;

//! Type of individual layers in an XCF file.

typedef enum
{
  RGB_GIMAGE,
  RGBA_GIMAGE,
  GRAY_GIMAGE,
  GRAYA_GIMAGE,
  INDEXED_GIMAGE,
  INDEXEDA_GIMAGE
} GimpImageType;

//! Effect to apply when layers are merged together.

typedef enum 
{
  NORMAL_MODE,
  DISSOLVE_MODE,
  BEHIND_MODE,
  MULTIPLY_MODE,
  SCREEN_MODE,
  OVERLAY_MODE,
  DIFFERENCE_MODE,
  ADDITION_MODE,
  SUBTRACT_MODE,
  DARKEN_ONLY_MODE,
  LIGHTEN_ONLY_MODE,
  HUE_MODE,
  SATURATION_MODE,
  COLOR_MODE,
  VALUE_MODE,
  DIVIDE_MODE,
  ERASE_MODE,
  REPLACE_MODE,
  ANTI_ERASE_MODE
} LayerModeEffects;

// From GIMP "xcf.c" v1.2

//! Properties which can be stored in an XCF file.

typedef enum
{
  PROP_END = 0,
  PROP_COLORMAP = 1,
  PROP_ACTIVE_LAYER = 2,
  PROP_ACTIVE_CHANNEL = 3,
  PROP_SELECTION = 4,
  PROP_FLOATING_SELECTION = 5,
  PROP_OPACITY = 6,
  PROP_MODE = 7,
  PROP_VISIBLE = 8,
  PROP_LINKED = 9,
  PROP_PRESERVE_TRANSPARENCY = 10,
  PROP_APPLY_MASK = 11,
  PROP_EDIT_MASK = 12,
  PROP_SHOW_MASK = 13,
  PROP_SHOW_MASKED = 14,
  PROP_OFFSETS = 15,
  PROP_COLOR = 16,
  PROP_COMPRESSION = 17,
  PROP_GUIDES = 18,
  PROP_RESOLUTION = 19,
  PROP_TATTOO = 20,
  PROP_PARASITES = 21,
  PROP_UNIT = 22,
  PROP_PATHS = 23,
  PROP_USER_UNIT = 24
} PropType;

// From GIMP "xcf.c" v1.2

//! Compression type used in layer tiles.

typedef enum
{
  COMPRESS_NONE = 0,
  COMPRESS_RLE = 1,
  COMPRESS_ZLIB = 2,
  COMPRESS_FRACTAL = 3  /* Unused. */
} CompressionType;

// From GIMP "paint_funcs.c" v1.2

/*!
 * Multiply two color components. Really expects the arguments to be
 * 8-bit quantities.
 * \param a first minuend.
 * \param b second minuend.
 * \return product of arguments.
 */
inline int INT_MULT ( int a, int b )
{
  int c = a * b + 0x80;
  return ( ( c >> 8 ) + c ) >> 8;
}

/*!
 * Blend the two color components in the proportion alpha:
 *
 * result = alpha a + ( 1 - alpha b)
 *
 * \param a first component.
 * \param b second component.
 * \param alpha blend proportion.
 * \return blended color components.
 */

inline int INT_BLEND ( int a, int b, int alpha )
{
  return INT_MULT( a - b, alpha ) + b;
}

// Actually from GLIB

inline int MIN ( int a, int b )
{
  return ( a < b ? a : b );
}

inline int MAX ( int a, int b )
{
  return ( a > b ? a : b );
}

// From GIMP "gimpcolorspace.c" v1.2

/*!
 * Convert a color in RGB space to HSV space (Hue, Saturation, Value).
 * \param red the red component (modified in place).
 * \param green the green component (modified in place).
 * \param blue the blue component (modified in place).
 */
void RGBTOHSV ( uchar& red, uchar& green, uchar& blue )
{
  int r, g, b;
  double h, s, v;
  int min, max;

  h = 0.;

  r = red;
  g = green;
  b = blue;

  if ( r > g ) {
    max = MAX( r, b );
    min = MIN( g, b );
  }
  else {
    max = MAX( g, b );
    min = MIN( r, b );
  }

  v = max;

  if ( max != 0 )
    s = ( ( max - min ) * 255 ) / (double)max;
  else
    s = 0;

  if ( s == 0 )
    h = 0;
  else {
    int delta = max - min;
    if ( r == max )
      h = ( g - b ) / (double)delta;
    else if ( g == max )
      h = 2 + ( b - r ) / (double)delta;
    else if ( b == max )
      h = 4 + ( r - g ) / (double)delta;
    h *= 42.5;

    if ( h < 0 )
      h += 255;
    if ( h > 255 )
      h -= 255;
  }

  red   = (uchar)h;
  green = (uchar)s;
  blue  = (uchar)v;
}

/*!
 * Convert a color in HSV space to RGB space.
 * \param hue the hue component (modified in place).
 * \param saturation the saturation component (modified in place).
 * \param value the value component (modified in place).
 */
void HSVTORGB ( uchar& hue, uchar& saturation, uchar& value )
{
  if ( saturation == 0 ) {
    hue        = value;
    saturation = value;
    value      = value;
  }
  else {
    double h = hue * 6. / 255.;
    double s = saturation / 255.;
    double v = value / 255.;

    double f = h - (int)h;
    double p = v * ( 1. - s );
    double q = v * ( 1. - ( s * f ) );
    double t = v * ( 1. - ( s * ( 1. - f ) ) );

    // Worth a note here that gcc 2.96 will generate different results
    // depending on optimization mode on i386.

    switch ((int)h) {
    case 0:
      hue        = (uchar)( v * 255 );
      saturation = (uchar)( t * 255 );
      value      = (uchar)( p * 255 );
      break;
    case 1:
      hue        = (uchar)( q * 255 );
      saturation = (uchar)( v * 255 );
      value      = (uchar)( p * 255 );
      break;
    case 2:
      hue        = (uchar)( p * 255 );
      saturation = (uchar)( v * 255 );
      value      = (uchar)( t * 255 );
      break;
    case 3:
      hue        = (uchar)( p * 255 );
      saturation = (uchar)( q * 255 );
      value      = (uchar)( v * 255 );
      break;
    case 4:
      hue        = (uchar)( t * 255 );
      saturation = (uchar)( p * 255 );
      value      = (uchar)( v * 255 );
      break;
    case 5:
      hue        = (uchar)( v * 255 );
      saturation = (uchar)( p * 255 );
      value      = (uchar)( q * 255 );
    }
  }
}

/*!
 * Convert a color in RGB space to HLS space (Hue, Lightness, Saturation).
 * \param red the red component (modified in place).
 * \param green the green component (modified in place).
 * \param blue the blue component (modified in place).
 */
void RGBTOHLS ( uchar& red, uchar& green, uchar& blue )
{
  int r = red;
  int g = green;
  int b = blue;

  int min, max;

  if ( r > g ) {
    max = MAX( r, b );
    min = MIN( g, b );
  }
  else {
    max = MAX( g, b );
    min = MIN( r, b );
  }

  double h;
  double l = ( max + min ) / 2.;
  double s;

  if ( max == min ) {
    s = 0.;
    h = 0.;
  }
  else {
    int delta = max - min;

    if ( l < 128 )
      s = 255 * (double)delta / (double)( max + min );
    else
      s = 255 * (double)delta / (double)( 511 - max - min );

    if ( r == max )
      h = ( g - b ) / (double)delta;
    else if ( g == max )
      h = 2 + ( b - r ) / (double)delta;
    else
      h = 4 + ( r - g ) / (double)delta;

    h *= 42.5;

    if ( h < 0 )
      h += 255;
    else if ( h > 255 )
      h -= 255;
  }

  red   = (uchar)h;
  green = (uchar)l;
  blue  = (uchar)s;
}

/*!
 * Implement the HLS "double hex-cone".
 * \param n1 lightness fraction (?)
 * \param n2 saturation fraction (?)
 * \param hue hue "angle".
 * \return HLS value.
 */
int HLSVALUE ( double n1, double n2, double hue )
{
  double value;

  if ( hue > 255 )
    hue -= 255;
  else if ( hue < 0 )
    hue += 255;

  if ( hue < 42.5 )
    value = n1 + ( n2 - n1 ) * ( hue / 42.5 );
  else if ( hue < 127.5 )
    value = n2;
  else if ( hue < 170 )
    value = n1 + ( n2 - n1 ) * ( ( 170 - hue ) / 42.5 );
  else
    value = n1;

  return (int)( value * 255 );
}

/*!
 * Convert a color in HLS space to RGB space.
 * \param hue the hue component (modified in place).
 * \param lightness the lightness component (modified in place).
 * \param saturation the saturation component (modified in place).
 */
void HLSTORGB ( uchar& hue, uchar& lightness, uchar& saturation )
{
  double h = hue;
  double l = lightness;
  double s = saturation;

  if ( s == 0 ) {
    hue        = (uchar)l;
    lightness  = (uchar)l;
    saturation = (uchar)l;
  }
  else {
    double m1, m2;

    if ( l < 128 )
      m2 = ( l * ( 255 + s ) ) / 65025.;
    else
      m2 = ( l + s - ( l * s ) / 255. ) / 255.;

    m1 = ( l / 127.5 ) - m2;

    hue        = HLSVALUE( m1, m2, h + 85 );
    lightness  = HLSVALUE( m1, m2, h );
    saturation = HLSVALUE( m1, m2, h - 85 );
  }
}
