/**************************************************************************
 *{@C
 *      Copyright:      1988-2020 Paul Obermeier (obermeier@poSoft.de)
 *
 *      Module:         ImageProcessing
 *      Filename:       IP_Comp.c
 *
 *      Author:         Paul Obermeier
 *
 *	Description:	Image compositing functions.
 *
 *      Additional documentation:
 *                      None.
 *
 *	Exported functions:
 *			IP_CompositeAlpha
 *			IP_CompositeColorMatte
 *			IP_CompositeDepth
 *			IP_CrossDissolve
 *
 **************************************************************************/

#include <stdio.h>

#include "UT_Compat.h"
#include "UT_Error.h"
#include "UT_Memory.h"
#include "UT_Parallel.h"

#define USE_IMG_MACROS
#include "FF_Image.h"

#include "IP_Image.h"
#include "IP_ImagePrivate.h"

/* Determine if channel "chn" of image "img" can be used for a fast
   compositing operation, i.e. if the channel is either in FF_ImgFmtTypeNone
   or FF_ImgFmtTypeUByte format.  */

static UT_Bool isfast (IP_ImageId img, Int32 chn)
{
    return
	img->pimg.channel[chn] == FF_ImgFmtTypeNone ||
	img->pimg.channel[chn] == FF_ImgFmtTypeUByte;
}


/* Composite two images using a black and white matte: Decide whether to use
the fast or the slow compositing method, and invoke the right algorithm. */

static UT_Bool comp_bwmatte
	(IP_ImageId fgimg,
	 IP_ImageId bgimg,
	 IP_ImageId cmimg,
	 Float32 f_r, Float32 f_g, Float32 f_b,
	 Float32 b_r, Float32 b_g, Float32 b_b,
	 IP_ImageId mtimg,
	 UT_Bool fast)
{
    /* Make sure that we have a transparency channel. */

    if (mtimg)
    {
	if (!mtimg->pimg.channel[FF_ImgChanTypeMatte])
	{
	    UT_ErrSetNum (UT_ErrParamInvalid, str_mt_bwtrans);
	    return UT_False;
	}
    }
    else
    {
	if (!fgimg->pimg.channel[FF_ImgChanTypeMatte])
	{
	    UT_ErrSetNum (UT_ErrParamInvalid, str_fg_bwtrans);
	    return UT_False;
	}
    }

    /* Invoke the compositing algorithm. */

    if (mtimg)
	fast &= isfast (mtimg, FF_ImgChanTypeMatte);
    else
	fast &= isfast (fgimg, FF_ImgChanTypeMatte);
    if (IP_StateDrawMask[FF_ImgChanTypeGray] &&
	cmimg->pimg.channel[FF_ImgChanTypeGray])
    {
	fast &= isfast (fgimg, FF_ImgChanTypeGray);
	fast &= isfast (bgimg, FF_ImgChanTypeGray);
	fast &= isfast (cmimg, FF_ImgChanTypeGray);
    }
    if (IP_StateDrawMask[FF_ImgChanTypeRed] &&
	cmimg->pimg.channel[FF_ImgChanTypeRed])
    {
	fast &= isfast (fgimg, FF_ImgChanTypeRed);
	fast &= isfast (bgimg, FF_ImgChanTypeRed);
	fast &= isfast (cmimg, FF_ImgChanTypeRed);
    }
    if (IP_StateDrawMask[FF_ImgChanTypeGreen] &&
	cmimg->pimg.channel[FF_ImgChanTypeGreen])
    {
	fast &= isfast (fgimg, FF_ImgChanTypeGreen);
	fast &= isfast (bgimg, FF_ImgChanTypeGreen);
	fast &= isfast (cmimg, FF_ImgChanTypeGreen);
    }
    if (IP_StateDrawMask[FF_ImgChanTypeBlue] &&
	cmimg->pimg.channel[FF_ImgChanTypeBlue])
    {
	fast &= isfast (fgimg, FF_ImgChanTypeBlue);
	fast &= isfast (bgimg, FF_ImgChanTypeBlue);
	fast &= isfast (cmimg, FF_ImgChanTypeBlue);
    }
    if (IP_StateDrawMask[FF_ImgChanTypeMatte] &&
	cmimg->pimg.channel[FF_ImgChanTypeMatte])
    {
	fast &= isfast (fgimg, FF_ImgChanTypeMatte);
	fast &= isfast (bgimg, FF_ImgChanTypeMatte);
	fast &= isfast (cmimg, FF_ImgChanTypeMatte);
    }

    return fast?
	IP_CompFastAlpha (fgimg, bgimg, cmimg,
			       f_r, f_g, f_b, b_r, b_g, b_b, mtimg):
	IP_CompSlowAlpha (fgimg, bgimg, cmimg,
			       f_r, f_g, f_b, b_r, b_g, b_b, mtimg);
}



/* Composite two images using a colored matte: Decide whether to use the
fast or the slow compositing method, and invoke the right algorithm. */

static UT_Bool comp_clrmatte
	(IP_ImageId fgimg,
	 IP_ImageId bgimg,
	 IP_ImageId cmimg,
	 Float32 f_r, Float32 f_g, Float32 f_b,
	 Float32 b_r, Float32 b_g, Float32 b_b,
	 IP_ImageId mtimg,
	 UT_Bool fast)
{
    /* Make sure that we have red, green and blue transparency channels. */

    if (mtimg)
    {
	if (!mtimg->pimg.channel[FF_ImgChanTypeRedMatte] ||
	    !mtimg->pimg.channel[FF_ImgChanTypeRedMatte] ||
	    !mtimg->pimg.channel[FF_ImgChanTypeRedMatte])
	{
	    UT_ErrSetNum (UT_ErrParamInvalid, str_mt_clrtrans);
	    return UT_False;
	}
    }
    else
    {
	if (!fgimg->pimg.channel[FF_ImgChanTypeRedMatte] ||
	    !fgimg->pimg.channel[FF_ImgChanTypeRedMatte] ||
	    !fgimg->pimg.channel[FF_ImgChanTypeRedMatte])
	{
	    UT_ErrSetNum (UT_ErrParamInvalid, str_fg_clrtrans);
	    return UT_False;
	}
    }

    /* Invoke the compositing algorithm. */

    if (mtimg)
    {
	fast &= isfast (mtimg, FF_ImgChanTypeRedMatte);
	fast &= isfast (mtimg, FF_ImgChanTypeGreenMatte);
	fast &= isfast (mtimg, FF_ImgChanTypeBlueMatte);
    }
    else
    {
	fast &= isfast (fgimg, FF_ImgChanTypeRedMatte);
	fast &= isfast (fgimg, FF_ImgChanTypeGreenMatte);
	fast &= isfast (fgimg, FF_ImgChanTypeBlueMatte);
    }
    if (IP_StateDrawMask[FF_ImgChanTypeRed] &&
	cmimg->pimg.channel[FF_ImgChanTypeRed])
    {
	fast &= isfast (fgimg, FF_ImgChanTypeRed);
	fast &= isfast (bgimg, FF_ImgChanTypeRed);
	fast &= isfast (cmimg, FF_ImgChanTypeRed);
    }
    if (IP_StateDrawMask[FF_ImgChanTypeGreen] &&
	cmimg->pimg.channel[FF_ImgChanTypeGreen])
    {
	fast &= isfast (fgimg, FF_ImgChanTypeGreen);
	fast &= isfast (bgimg, FF_ImgChanTypeGreen);
	fast &= isfast (cmimg, FF_ImgChanTypeGreen);
    }
    if (IP_StateDrawMask[FF_ImgChanTypeBlue] &&
	cmimg->pimg.channel[FF_ImgChanTypeBlue])
    {
	fast &= isfast (fgimg, FF_ImgChanTypeBlue);
	fast &= isfast (bgimg, FF_ImgChanTypeBlue);
	fast &= isfast (cmimg, FF_ImgChanTypeBlue);
    }
    if (IP_StateDrawMask[FF_ImgChanTypeRedMatte] &&
	cmimg->pimg.channel[FF_ImgChanTypeRedMatte])
    {
	fast &= isfast (fgimg, FF_ImgChanTypeRedMatte);
	fast &= isfast (bgimg, FF_ImgChanTypeRedMatte);
	fast &= isfast (cmimg, FF_ImgChanTypeRedMatte);
    }
    if (IP_StateDrawMask[FF_ImgChanTypeGreenMatte] &&
	cmimg->pimg.channel[FF_ImgChanTypeGreenMatte])
    {
	fast &= isfast (fgimg, FF_ImgChanTypeGreenMatte);
	fast &= isfast (bgimg, FF_ImgChanTypeGreenMatte);
	fast &= isfast (cmimg, FF_ImgChanTypeGreenMatte);
    }
    if (IP_StateDrawMask[FF_ImgChanTypeBlueMatte] &&
	cmimg->pimg.channel[FF_ImgChanTypeBlueMatte])
    {
	fast &= isfast (fgimg, FF_ImgChanTypeBlueMatte);
	fast &= isfast (bgimg, FF_ImgChanTypeBlueMatte);
	fast &= isfast (cmimg, FF_ImgChanTypeBlueMatte);
    }

    return fast?
	IP_CompFastColorMatte (fgimg, bgimg, cmimg,
			        f_r, f_g, f_b, b_r, b_g, b_b, mtimg):
	IP_CompSlowColorMatte (fgimg, bgimg, cmimg,
			        f_r, f_g, f_b, b_r, b_g, b_b, mtimg);
}



/* Composite two images using depth mattes: Decide whether to use the
fast or the slow compositing method, and invoke the right algorithm. */

static UT_Bool comp_zmatte (IP_ImageId fgimg, IP_ImageId bgimg, IP_ImageId cmimg)
{
    Int32 chn;
    UT_Bool fast;

    /* Make sure that we have depth channels in both input images. */

    if (!fgimg->pimg.channel[FF_ImgChanTypeDepth])
    {
	UT_ErrSetNum (UT_ErrParamInvalid, str_fg_depth);
	return UT_False;
    }
    if (!bgimg->pimg.channel[FF_ImgChanTypeDepth])
    {
	UT_ErrSetNum (UT_ErrParamInvalid, str_bg_depth);
	return UT_False;
    }

    /* Invoke the compositing algorithm. */

    fast = UT_True;
    for (chn = FF_ImgChanTypeGray; chn <= FF_ImgChanTypeVertSnr; ++chn)
	if (IP_StateDrawMask[chn] && cmimg->pimg.channel[chn])
	{
	    fast &= fgimg->pimg.channel[chn] == bgimg->pimg.channel[chn];
	    fast &= bgimg->pimg.channel[chn] == cmimg->pimg.channel[chn];
	}
    fast &= fgimg->pimg.channel[FF_ImgChanTypeDepth] == FF_ImgFmtTypeFloat;
    fast &= bgimg->pimg.channel[FF_ImgChanTypeDepth] == FF_ImgFmtTypeFloat;

    return fast?
	IP_CompFastDepth (fgimg, bgimg, cmimg):
	IP_CompSlowDepth (fgimg, bgimg, cmimg);
}



/* Cross-dissove between two images: Decide whether to use the fast
or the slow compositing method, and invoke the right algorithm. */

static UT_Bool crossimage
	(IP_ImageId fgimg, IP_ImageId bgimg, IP_ImageId cmimg, Float32 mix)
{
    Int32 chn;
    UT_Bool fast;

    fast = UT_True;
    for (chn = FF_ImgChanTypeGray; chn <= FF_ImgChanTypeBlueMatte; ++chn)
	if (IP_StateDrawMask[chn] && cmimg->pimg.channel[chn])
	{
	    fast &= isfast (fgimg, chn);
	    fast &= isfast (bgimg, chn);
	    fast &= isfast (cmimg, chn);
	}
    fast &= mix >= 0.0;
    fast &= mix <= 1.0;

    return fast?
	IP_CrossDissolveFast (fgimg, bgimg, cmimg, mix):
	IP_CrossDissolveSlow (fgimg, bgimg, cmimg, mix);
}

/***************************************************************************
 *[@e
 *	Name:		IP_CompositeAlpha
 *
 *	Usage:		Composite two images, using a black and white matte.
 *
 *	Synopsis:	UT_Bool IP_CompositeAlpha
 *				(IP_ImageId fgimg,
 *				 IP_ImageId bgimg,
 *				 IP_ImageId cmimg,
 *				 Float32 f_r, Float32 f_g, Float32 f_b,
 *				 Float32 b_r, Float32 b_g, Float32 b_b,
 *				 IP_ImageId mtimg,
 *				 UT_Bool fast)
 *
 *	Description:	Image "fgimg" is composited in front of image
 *			"bgimg". The result is stored in "cmimg".
 *			If "mtimg" is NULL, the matte for compositing is
 *			taken from image "fgimg". If "mtimg" is not NULL,
 *			image "mtimg" supplies the matte.
 *			
 *			1. Any gamma-correction in the input data is
 *			   compensated by performing an inverse gamma-
 *			   correction on the pixel data from "fgimg"
 *			   and "bgimg".
 *
 *			2. The FF_ImgChanTypeRed, FF_ImgChanTypeGreen and
 *			   FF_ImgChanTypeBlue channels of all pixels from 
 *			   "fgimg" are scaled by "fr", "fg" and "fb".
 *			   The FF_ImgChanTypeRed, FF_ImgChanTypeGreen
 *			   and FF_ImgChanTypeBlue channels of all pixels from
 *			   "bgimg" are scaled by "br", "bg" and "bb".
 *
 *			3. The FF_ImgChanTypeGray, FF_ImgChanTypeRed, 
 *			   FF_ImgChanTypeGreen, and FF_ImgChanTypeBlue channels
 *			   for every pixel in "cmimg" are combined from the 
 *			   data in "fgimg" and "bgimg":
 *			    
 *			   if "mtimg" is NULL:
 *
 *			       cm.bright =
 *				    fg.bright +
 *				    bg.bright * (1-fg.trans);
 *			       cm.red =
 *				    fg.red +
 *				    bg.red * (1-fg.trans);
 *			       cm.green =
 *				    fg.green +
 *				    bg.green * (1-fg.trans);
 *			       cm.blue =
 *				    fg.blue +
 *				    bg.blue * (1-fg.trans);
 *			    else
 *
 *			       cm.bright =
 *				    fg.bright * mt.trans +
 *				    bg.bright * (1-mt.trans);
 *			       cm.red =
 *				    fg.red * mt.trans +
 *				    bg.red * (1-mt.trans);
 *			       cm.green =
 *				    fg.green * mt.trans +
 *				    bg.green * (1-mt.trans);
 *			       cm.blue =
 *				    fg.blue * mt.trans +
 *				    bg.blue * (1-mt.trans);
 *
 *			4. The FF_ImgChanTypeGray, FF_ImgChanTypeRed, 
 *			   FF_ImgChanTypeGreen and FF_ImgChanTypeBlue channels
 *			   in "cmimg" are gamma corrected according to the
 *			   image descriptor of "cmimg".
 *
 *			5. The FF_ImgChanTypeMatte channel for every pixel in
 *			   "cmimg" is computed:
 *
 *			   if "mtimg" is NULL:
 *
 *			       cm.trans = 1 - (1-fg.trans) * (1-bg.trans);
 *
 *			   else
 *
 *			       cm.trans = 1 - (1-mt.trans) * (1-bg.trans);
 *
 *			Notes:
 *
 *			- If necessary, "fgimg" or "bgimg" can be
 *			  identical to "cmimg", so that IP_CompositeAlpha
 *			  overwrites one of the input images with the result.
 *
 *			- IP_CompositeAlpha does not write to any channels in
 *			  "cmimg" for which the drawing mask is "UT_False".
 *
 *			- IP_CompositeAlpha does not write to the
 *			  FF_ImgChanTypeRedMatte, FF_ImgChanTypeGreenMatte,
 *			  FF_ImgChanTypeBlueMatte, FF_ImgChanTypeHoriSnr,
 *			  FF_ImgChanTypeVertSnr and FF_ImgChanTypeDepth channels
 *			  in "cmimg", even if the drawing mask for these 
 *			  channels is "UT_True".
 *
 *			- For compositing, "fgimg", "bgimg" and
 *			  "cmimg" are aligned at the lower left corner.
 *			  If "cmimg" is wider or higher than "fgimg" or
 *			  "bgimg", IP_CompositeAlpha does not change areas
 *			  in "cmimg" which are not covered by "fgimg" or
 *			  "bgimg".
 *
 *			- IP_CompositeAlpha can be run concurrently on
 *			  multiple processors; see IP_SetNumThreads.
 *
 *			- If the "fast" flag is set to UT_True, and all pixel
 *			  data involved in the compositing are in 
 *			  FF_ImgFmtTypeUByte format, IP_CompositeAlpha will
 *			  switch to a faster, but less general compositing 
 *			  algorithm.
 *			  The results are usually the same as with the slower
 *			  algorithm; only if one of "fr", "fg", "fb", "br",
 *			  "bg" or "bb" is greater than 1.0 or less than 0.0,
 *			  color clipping may be different.
 *
 *	Return value:	UT_True if successful, else UT_False.
 *
 *	See also:	UT_CompositeColorMatte
 *			UT_CompositeDepth
 *
 ***************************************************************************/

UT_Bool IP_CompositeAlpha
	(IP_ImageId fgimg,
	 IP_ImageId bgimg,
	 IP_ImageId cmimg,
	 Float32 f_r, Float32 f_g, Float32 f_b,
	 Float32 b_r, Float32 b_g, Float32 b_b,
	 IP_ImageId mtimg,
	 UT_Bool fast)
{
    UT_MemState	memstate;
    UT_Bool	success;

    memstate = UT_MemRemember ();
    success = comp_bwmatte
	    (fgimg, bgimg, cmimg,
	     f_r, f_g, f_b,
	     b_r, b_g, b_b,
	     mtimg, fast);
    UT_MemRestore (memstate);
    return success;
}

/***************************************************************************
 *[@e
 *	Name:		IP_CompositeColorMatte
 *
 *	Usage:		Composite two images, using a colored matte.
 *
 *	Synopsis:	UT_Bool IP_CompositeColorMatte
 *				(IP_ImageId fgimg,
 *				 IP_ImageId bgimg,
 *				 IP_ImageId cmimg,
 *				 Float32 f_r, Float32 f_g, Float32 f_b,
 *				 Float32 b_r, Float32 b_g, Float32 b_b,
 *				 IP_ImageId mtimg,
 *				 UT_Bool fast)
 *
 *	Description:	Image "fgimg" is composited in front of image
 *			"bgimg". The result is stored in "cmimg".
 *			If "mtimg" is NULL, the matte for compositing is
 *			taken from image "fgimg". If "mtimg" is not NULL,
 *			image "mtimg" supplies the matte.
 *			
 *			1. Any gamma-correction in the input data is
 *			   compensated by performing an inverse gamma-
 *			   correction on the pixel data from "fgimg"
 *			   and "bgimg".
 *
 *			2. The FF_ImgChanTypeRed, FF_ImgChanTypeGreen and 
 *			   FF_ImgChanTypeBlue channels of all pixels from 
 *			   "fgimg" are scaled by "fr", "fg" and "fb".
 *			   The FF_ImgChanTypeRed, FF_ImgChanTypeGreen
 *			   and FF_ImgChanTypeBlue channels of all pixels from
 *			   "bgimg" are scaled by "br", "bg" and "bb".
 *
 *			3. The FF_ImgChanTypeRed, FF_ImgChanTypeGreen and
 *			   FF_ImgChanTypeBlue channels for every pixel in 
 *			   "cmimg" are combined from the data in "fgimg" and 
 *			   "bgimg":
 *			    
 *			   if "mtimg" is not NUL:
 *
 *			       cm.red = fg.red * mt.red_trans +
 *				    bg.red * (1-mt.red_trans);
 *
 *			       cm.green = fg.green * mt.green_trans +
 *				    bg.green * (1-mt.green_trans);
 *
 *			       cm.blue = fg.blue * mt.blue_trans +
 *				    bg.blue * (1-mt.blue_trans);
 *			   
 *			   else
 *
 *			       cm.red = fg.red +
 *				    bg.red * (1-fg.red_trans);
 *
 *			       cm.green = fg.green +
 *				    bg.green * (1-fg.green_trans);
 *
 *			       cm.blue = fg.blue +
 *				    bg.blue * (1-fg.blue_trans);
 *
 *			4. The FF_ImgChanTypeRed, FF_ImgChanTypeGreen and
 *			   FF_ImgChanTypeBlue channels in "cmimg" are gamma 
 *			   corrected according to the image descriptor of
 *			   "cmimg".
 *
 *			5. The FF_ImgChanTypeRedMatte, FF_ImgChanTypeGreenMatte
 *			   and FF_ImgChanTypeBlueMatte channels for every pixel
 *			   in "cmimg" are combined from the data in "fgimg"
 *			   and "bgimg":
 *
 *			   if "mtimg" is not NULL:
 *
 *			       cm.red_trans = 1 -
 *				    (1-mt.red_trans) * (1-bg.red_trans);
 *
 *			       cm.green_trans = 1 -
 *				    (1-mt.green_trans) * (1-bg.green_trans);
 *
 *			       cm.blue_trans = 1 -
 *				    (1-mt.blue_trans) * (1-bg.blue_trans);
 *				    
 *			   else
 *
 *			       cm.red_trans = 1 -
 *				    (1-fg.red_trans) * (1-bg.red_trans);
 *
 *			       cm.green_trans = 1 -
 *				    (1-fg.green_trans) * (1-bg.green_trans);
 *
 *			       cm.blue_trans = 1 -
 *				    (1-fg.blue_trans) * (1-bg.blue_trans);
 *				    
 *			Notes:
 *
 *			- If necessary, "fgimg" or "bgimg" can be
 *			  identical to "cmimg", so that IP_CompositeColorMatte
 *			  overwrites one of the input images with the result.
 *
 *			- IP_CompositeColorMatte does not write to any channels
 *			  in "cmimg" for which the drawing mask is "UT_False".
 *
 *			- IP_CompositeColorMatte does not write to the
 *			  FF_ImgChanTypeGray, FF_ImgChanTypeMatte, 
 *			  FF_ImgChanTypeHoriSnr, FF_ImgChanTypeVertSnr and 
 *			  FF_ImgChanTypeDepth channels in "cmimg", even if the 
 *		 	  drawing mask for these channels is "UT_True".
 *
 *			- For compositing, "fgimg", "bgimg" and
 *			  "cmimg" are aligned at the lower left corner.
 *			  If "cmimg" is wider or higher than "fgimg" or
 *			  "bgimg", IP_CompositeColorMatte does not change areas
 *			  in "cmimg" which are not covered by "fgimg" or
 *			  "bgimg".
 *
 *			- IP_CompositeColorMatte can be run concurrently on
 *			  multiple processors; see IP_SetNumThreads.
 *
 *			- If the "fast" flag is set to UT_True, and all pixel
 *			  data involved in the compositing are in
 *			  FF_ImgFmtTypeUByte format, IP_CompositeColorMatte will
 *			  switch to a faster, but less general compositing
 *			  algorithm.  
 *			  The results are usually the same as with the slower
 *			  algorithm; only if one of "fr", "fg", "fb", "br",
 *			  "bg" or "bb" is greater than 1.0 or less than 0.0,
 *			  color clipping may be different.
 *
 *	Return value:	UT_True if successful, else UT_False.
 *
 *	See also:	UT_CompositeAlpha
 *			UT_CompositeDepth
 *
 ***************************************************************************/

UT_Bool IP_CompositeColorMatte
	(IP_ImageId fgimg,
	 IP_ImageId bgimg,
	 IP_ImageId cmimg,
	 Float32 f_r, Float32 f_g, Float32 f_b,
	 Float32 b_r, Float32 b_g, Float32 b_b,
	 IP_ImageId mtimg,
	 UT_Bool fast)
{
    UT_MemState	memstate;
    UT_Bool	success;

    memstate = UT_MemRemember ();
    success = comp_clrmatte
	    (fgimg, bgimg, cmimg,
	     f_r, f_g, f_b,
	     b_r, b_g, b_b,
	     mtimg, fast);
    UT_MemRestore (memstate);
    return success;
}

/***************************************************************************
 *[@e
 *	Name:		IP_CompositeDepth
 *
 *	Usage:		Composite two images, using depth mattes.
 *
 *	Synopsis:	UT_Bool IP_CompositeDepth
 *				(IP_ImageId fgimg,
 *				 IP_ImageId bgimg,
 *				 IP_ImageId cmimg)
 *
 *	Description:	Image "fgimg" and "bgimg" are combined into a new
 *			image, "cmimg". Both, "fgimg" and "bgimg", must
 *			include a FF_ImgChanTypeDepth channel, indicating the
 *			distance of the pixels from the viewer.
 *
 *			The data from "fgimg" and "bgimg" are combined as
 *			follows:
 *
 *			    if fgimg.pixel is closer than bgimg.pixel
 *
 *				cmimg.pixel = fgimg.pixel;
 *			    
 *			    else
 *				
 *				cmimg.pixel = bgimg.pixel;
 *
 *			Notes:
 *
 *			- If necessary, "fgimg" or "bgimg" can be identical to
 *			  "cmimg", so that IP_CompositeDepth overwrites one of
 *			  the input images with the result.
 *
 *			- IP_CompositeDepth does not write to any channels in
 *			  "cmimg" for which the drawing mask is "UT_False".
 *
 *			- For compositing, "fgimg", "bgimg" and "cmimg" are
 *			  aligned at the lower left corner. If "cmimg" is wider
 *			  or higher than "fgimg" or "bgimg", IP_CompositeDepth
 *			  does not change areas in "cmimg" which are not
 *			  covered by "fgimg" or "bgimg".
 *
 *			- IP_CompositeDepth can be run concurrently on
 *			  multiple processors; see IP_SetNumThreads.
 *
 *	Return value:	UT_True if successful, else UT_False.
 *
 *	See also:	UT_CompositeAlpha
 *			UT_CompositeColorMatte
 *
 ***************************************************************************/

UT_Bool IP_CompositeDepth (IP_ImageId fgimg, IP_ImageId bgimg, IP_ImageId cmimg)
{
    UT_MemState	memstate;
    UT_Bool	success;

    memstate = UT_MemRemember ();
    success = comp_zmatte (fgimg, bgimg, cmimg);
    UT_MemRestore (memstate);
    return success;
}

/***************************************************************************
 *[@e
 *	Name:		IP_CrossDissolve
 *
 *	Usage:		Cross-dissolve between two images.
 *
 *	Synopsis:	UT_Bool IP_CrossDissolve
 *				(IP_ImageId fgimg,
 *				 IP_ImageId bgimg,
 *				 IP_ImageId cmimg,
 *				 Float32 mix)
 *
 *	Description:	IP_CrossDissolve cross-dissolves between image "fgimg"
 *			and "bgimg". The result is stored in "cmimg":
 *			
 *			1. Any gamma-correction in the input data is
 *			   compensated by performing an inverse gamma-
 *			   correction on the pixel data from "fgimg"
 *			   and "bgimg".
 *
 *			2. The the pixel data for "cmimg" are combined from
 *			   the data in "fgimg" and "bgimg" ("mix" should be
 *			   in the range from 0.0 to 1.0):
 *			    
 *			       cm.pixel = fg.pixel * mix + bg.pixel * (1-mix)
 *
 *			3. The FF_ImgChanTypeGray, FF_ImgChanTypeRed,
 *			   FF_ImgChanTypeGreen, and FF_ImgChanTypeBlue channels
 *			   in "cmimg" are gamma-corrected according to the image
 *			   descriptor of "cmimg".
 *
 *			Notes:
 *
 *			- If necessary, "fgimg" or "bgimg" can be
 *			  identical to "cmimg", so that IP_CrossDissolve
 *			  overwrites one of the input images with the
 *			  result.
 *
 *			- IP_CrossDissolve does not write to any channels in
 *			  "cmimg" for which the drawing mask is "UT_False".
 *
 *			- IP_CrossDissolve does not write to the 
 *			  FF_ImgChanTypeHoriSnr, FF_ImgChanTypeVertSnr and
 *			  FF_ImgChanTypeDepth channels in "cmimg",
 *			  even if the drawing mask for these channels is
 *			  "UT_True".
 *
 *			- For cross-dissolving, "fgimg", "bgimg" and
 *			  "cmimg" are aligned at the lower left corner.
 *			  If "cmimg" is wider or higher than "fgimg" or
 *			  "bgimg", IP_CrossDissolve does not change areas
 *			  in "cmimg" which are not covered by "fgimg" or
 *			  "bgimg".
 *
 *			- IP_CrossDissolve can be run concurrently on
 *			  multiple processors; see IP_SetNumThreads.
 *
 *	Return value:	UT_True if successful, else UT_False.
 *
 *	See also:
 *
 ***************************************************************************/

UT_Bool IP_CrossDissolve
	(IP_ImageId fgimg, IP_ImageId bgimg, IP_ImageId cmimg, Float32 mix)
{
    UT_MemState	memstate;
    UT_Bool	success;

    memstate = UT_MemRemember ();
    success = crossimage (fgimg, bgimg, cmimg, mix);
    UT_MemRestore (memstate);
    return success;
}
