
/* 
 * cam02
 *
 * Color Appearance Model, based on
 * CIECAM02, "The CIECAM02 Color Appearance Model"
 * by Nathan Moroney, Mark D. Fairchild, Robert W.G. Hunt, Changjun Li,
 * M. Ronnier Luo and Todd Newman, IS&T/SID Tenth Color Imaging
 * Conference, with the addition of a Viewing Flare+Glare
 * model, and the Helmholtz-Kohlrausch effect, using the equation
 * the Bradford-Hunt 96C model as detailed in Mark Fairchilds
 * book "Color Appearance Models". 
 *
 * Author:  Graeme W. Gill
 * Date:    17/1/2004
 * Version: 1.00
 *
 * This file is based on cam97s3.h by Graeme Gill.
 *
 * Copyright 2004 - 2014 Graeme W. Gill
 * Please refer to COPYRIGHT file for details.
 * This material is licenced under the GNU AFFERO GENERAL PUBLIC LICENSE Version 3 :-
 * see the License.txt file for licencing details.
 */

/* Definitions assumed here:

  Stimulus field is the 2 degrees field of view of the sample
	being characterised.

  Viewing/Scene/Image field is the area of the whole image or
	display surface that the stimulus is part of.

  Background field is 10-12 degree field immediately surrounding the stimulus field.
	This may be within, overlap or encompass the Viewing/Scene/Image field.

  Visual field is the 130 degree angular field that is seen by the eyes.

  Surround/Adapting field is the visual field minus the background field,
  and is what is assumed to be setting the viewers light adaptation level.

  Ambient field is general illumination from the sun or general lighting,
  and is the whole surrounding environmental light field.

  Illuminating field is the field that illuminates the reflective
  Scene/Image. It may be the same as the Ambient field or it could
  be a specific light source that is directed to the viewing scene..

  NOTE: In "Digital Color Management", Giorgianni and Madden use the term
  "Surround" to mean the same thing as "Background" in the CIECAM02 terminology.
  The ICC standard doesn't define what it means by "Surround illumination".

*/

/* Rules of Thumb: */

/* Ambient Luminance (Lamb, cd/m^2) is Ambient Illuminance (Eamb, Lux) divided by PI. */
/* i.e. Lamb = Eamb/PI */	/* (1 foot candle = 0.0929 lux) */

/* Illuminating field Luminance (Li, cd/m^2) is the Illuminating field Illuminance (Ei, Lux) */
/* divide by PI. i.e. Li = Ei/PI */

/* The Adapting/Surround Luminance is La often taken to be */
/* the 20% of the Ambient Luminance (gray world, 50% perceptual) */
/* i.e. La = Lamb/5 = Eamb/15.7 */
/* If the Illuminating field covers the Adapting/surround, the it will be 20% of the */
/* Illuminating field. */

/* For a reflective print, the Viewing/Scene/Image luminance (Lv, cd/m^2), */
/* will be the Illuminating Luminance (Li, cd/m^2) or the Ambient Luminance (Lamb, cd/m^2) */
/* reflected by the media white point (Yw) */

/* If there is no special illumination for a reflective print, */
/* then the Illuminating Luminance (Li) will be the Ambient Luminance (Lamb) */

/* An emisive display will have an independently determined Lv. */

/* The classification of the type of surround is */
/* determined by comparing the Adapting/Surround luminance (La, cd/m^2) */
/* with the average luminance of the Viewing/Scene/Image field (Lv, cd/m^2) */

/* La/Lv == 0%,   dark */
/* La/Lv 0 - 20%, dim */
/* La/Lv > 20%,   average */
/* special,       cut sheet */

/* The Background relative luminance Yb is typically assumed to */
/* be 0.18 .. 0.2, and is assumed to be grey. */

/* Flare is assumed to be stray light from light parts of the */
/* image illuminating dark parts of the image, and is display technology dependent. */
/* In theory reflective systems have little Flare ? */

/* Glare is assumed to be stray ambient light reflecting from the display */
/* surface, dust, or entering the observers eye directly, and as a result */
/* fogging the dark parts of the image. */
/* This is typically the major source of veiling light ? */

/* By separatedly specifiying these two, the effect can be automatically */
/* scalled according to the ambient light level, modelling the effect of */
/* reduced glare in a darkened viewing environment. */

/*

Typical adapting field luminances and white luminance in reflective setup:

E = illuminance in Lux
Lv = White luminance assuming 100% reflectance
La = Adapting field luminance in cd/m^2, assuming 20% reflectance from surround
    
    E     La     Lv   Condition 
    11     0.7    4   Twilight
    32     2     10   Subdued indoor lighting
    64     4     20   Less than typical office light; sometimes recommended for
                      display-only workplaces (sRGB)
   350    22    111   Typical Office (sRGB annex D)
   500    32    160   Practical print evaluationa (ISO-3664 P2)
  1000    64    318   Good Print evaluation (CIE 116-1995)
  1000    64    318   Television Studio lighting
  1000    64    318   Overcast Outdoors
  2000   127    637   Critical print evaluation (ISO-3664 P1)
 10000   637   3183   Typical outdoors, full daylight 
 50000  3185  15915   Bright summers day 

*/

/* ---------------------------------- */

struct _cam02 {
/* Public: */
	void (*del)(struct _cam02 *s);	/* We're done with it */

	int (*set_view)(
		struct _cam02 *s,
		ViewingCondition Ev,	/* Enumerated Viewing Condition */
		double Wxyz[3],	/* Reference/Adapted White XYZ (Y scale 1.0) */
		double La,		/* Adapting/Surround Luminance cd/m^2 */
		double Yb,		/* Luminance of Background relative to reference white (range 0.0 .. 1.0) */
		double Lv,		/* Luminance of white in the Viewing/Scene/Image field (cd/m^2) */
						/* Ignored if Ev is set */
		double Yf,		/* Flare as a fraction of the reference white (range 0.0 .. 1.0) */
		double Yg,		/* Glare as a fraction of the adapting/surround (range 0.0 .. 1.0) */
		double Gxyz[3],	/* The Glare white coordinates (ie. the Ambient color) */
						/* If <= 0 will Wxyz will be used. */
		int hk,			/* Flag, NZ to use Helmholtz-Kohlrausch effect */
		double hkscale,	/* HK effect scaling factor */

		double mtaf,	/* Mid tone partial adapation factor from Wxyz to Wxyz2, <= 0.0 if none */
		double Wxyz2[3] /* Mid tone Adapted White XYZ (Y range 0.0 .. 1.0) */
	);

	/* Conversions. Return nz on error (Y scale 1.0) */
	int (*XYZ_to_cam)(struct _cam02 *s, double *out, double *in);
	int (*cam_to_XYZ)(struct _cam02 *s, double *out, double *in);

/* Private: */
	/* Scene parameters */
	ViewingCondition Ev;	/* Enumerated Viewing Condition */
	double Lv;		/* Luminance of white in the Viewing/Image cd/m^2 */
	double La;		/* Adapting/Surround Luminance cd/m^2 */
	double Wxyz[3];	/* Reference/Adapted White XYZ (Y range 0.0 .. 1.0) */
	double Yb;		/* Relative Luminance of Background to reference white (Y range 0.0 .. 1.0) */
	double Yf;		/* Flare as a fraction of the reference white (Y range 0.0 .. 1.0) */
	double Yg;		/* Glare as a fraction of the adapting/surround (Y range 0.0 .. 1.0) */
	double Gxyz[3];	/* The Glare white coordinates (typically the Ambient color) */

	/* Partial mid-tone adapation hack parameters */
	double Wxyz2[3];/* Mid tone Adapted White XYZ (Y range 0.0 .. 1.0) */
	double mtaf;	/* Mid tone blend factor between Wxyz and Wxyz2 */

	/* Internal parameters */
	double  C;		/* Surround Impact */
	double Nc;		/* Chromatic Induction */
	double  F;		/* Adaptation Degree */

	/* Pre-computed values */
	double cc[3][3];	/* Forward cone and chromatic transform */
	double icc[3][3];	/* Reverse cone and chromatic transform */
	double crange[3];	/* ENABLE_COMPR compression range */
	double Va[3], Vb[3], VttA[3], Vttd[3];	/* rgba vectors */
	double dcomp[3];	/* Vttd in terms of VttA, Va, Vb */
	double Fsc;			/* Flare+Glare scale */
	double Fisc;		/* Inverse Flare+Glare scale */
	double Fsxyz[3];	/* Scaled Flare+Glare color coordinates */
	double rgbW[3];		/* Sharpened cone response white values */
	double D;			/* Degree of chromatic adaption */
	double Drgb[3];		/* Chromatic transformation value */
	double rgbcW[3];	/* Chromatically transformed white value */
	double rgbpW[3];	/* Hunt-Pointer-Estevez cone response space white */
	double n;			/* Background induction factor */
	double nn;			/* Precomuted function of n */
	double Fl;			/* Lightness contrast factor ?? */
	double Nbb;			/* Background brightness induction factors */
	double Ncb;			/* Chromatic brightness induction factors */
	double z;			/* Base exponential nonlinearity */
	double rgbaW[3];	/* Post-adapted cone response of white */
	double Aw;			/* Achromatic response of white */
	double nldxval;		/* Non-linearity output value at lower crossover to linear */
	double nldxslope;	/* Non-linearity slope at lower crossover to linear */
	double nluxval;		/* Non-linearity value at upper crossover to linear */
	double nluxslope;	/* Non-linearity slope at upper crossover to linear */
	double lA;			/* JLIMIT Limited A */

	/* Partial mid-tone adapation hack pre-computed values */
	int pmta_en;		/* NZ if enabled */
	double mtap;		/* Mid tone blend rate (power) between Wxyz and Wxyz2 */
	double rgbW2[3];	/* Mid etone sharpened cone response white values */
	double Drgb2[3];	/* Mid tone chromatic transformation value */
	double rgbcW2[3];	/* Mid tone chromatically transformed white value */
	double rgbpW2[3];	/* Mid tone hunt-Pointer-Estevez cone response space white */
	double cc2[3][3];	/* Mide tone forward cone and chromatic transform */
	double icc2[3][3];	/* Mide tone reverse cone and chromatic transform */

	/* Option flags, code not always enabled */
	int hk;				/* Use Helmholtz-Kohlrausch effect */
	int hkscale;		/* [1.0] Scale HK effect up/down from default */
	int bluelin;		/* Use blue hue linearization */
	int trace;			/* Trace values through computation */
	int retss;			/* Return ss rather than Jab */
	int range;			/* (for cam02ref.h) return on range error */ 

	double nldlimit;	/* value of NLDLIMIT, sets non-linearity lower limit */
	double nldicept;	/* value of NLDLICEPT, sets straight line intercept with 0.1 output */
	double nlulimit;	/* value of NLULIMIT, sets non-linearity upper limit (tangent) */
	double ddllimit;	/* value of DDLLIMIT, sets fwd k3 to k2 limit  */
	double ddulimit;	/* value of DDULIMIT, sets bwd k3 to k1 limit */
	double ssmincj;		/* value of SSMINJ, sets cJ minimum value */
	double jlimit;		/* value of JLIMIT, sets cutover to straight line for J point */
	double hklimit;		/* value of HKLIMIT, sets HK factor upper limit */

}; typedef struct _cam02 cam02;


/* Create a cam02 conversion class, with default viewing conditions */
cam02 *new_cam02(void);

