jedioutcast/utils/roq2/libim/imvfbcomp.c
2013-04-04 13:07:40 -05:00

1688 lines
29 KiB
C

/**
** $Header: /roq/libim/imvfbcomp.c 1 11/02/99 4:38p Zaphod $
** Copyright (c) 1989-1995 San Diego Supercomputer Center (SDSC)
** a division of General Atomics, San Diego, California, USA
**
** Users and possessors of this source code are hereby granted a
** nonexclusive, royalty-free copyright and design patent license to
** use this code in individual software. License is not granted for
** commercial resale, in whole or in part, without prior written
** permission from SDSC. This source is provided "AS IS" without express
** or implied warranty of any kind.
**
** For further information contact:
** E-Mail: info@sds.sdsc.edu
**
** Surface Mail: Information Center
** San Diego Supercomputer Center
** P.O. Box 85608
** San Diego, CA 92138-5608
** (619) 534-5000
**/
#define HEADER " $Header: /roq/libim/imvfbcomp.c 1 11/02/99 4:38p Zaphod $"
/**
** FILE
** imvfbcomp.c - image compositing
**
** PROJECT
** libim - SDSC image manipulation library
**
** DESCRIPTION
** imvfbcomp.c functions to do digital compositing on images.
**
** PUBLIC CONTENTS
** d =defined constant
** f =function
** m =defined macro
** t =typedef/struct/union
** v =variable
** ? =other
**
** ImVfbComp f composite fields of a virtual frame buffer
**
** PRIVATE CONTENTS
** imVfbCompOver f composites one image over another
** imVfbCompInside f composites one image inside another
** imVfbCompOutsidef composites one image outside another
** imVfbCompAtop f composites one image atop another
**
** HISTORY
** $Log: /roq/libim/imvfbcomp.c $
*
* 1 11/02/99 4:38p Zaphod
** Revision 1.16 1995/06/29 00:28:04 bduggan
** updated copyright year
**
** Revision 1.15 1995/06/16 08:52:27 bduggan
** removed use of 'operator'
**
** Revision 1.14 1995/01/10 23:46:32 bduggan
** added a comment
**
** Revision 1.13 1994/10/03 11:29:46 nadeau
** Updated to ANSI C and C++ compatibility.
** Removed all use of register keyword.
** Minimized use of custom SDSC types (e.g., uchar vs. unsigned char)
** Changed all float arguments to double.
** Added forward declarations.
** Added misc. casts to passify SGI and DEC compilers.
** Changed all macros and defined constants to have names
** starting with IM.
** Updated comments.
** Updated indenting on some code.
** Updated copyright message.
**
** Revision 1.12 93/05/19 19:45:51 shane
** Fixed two more bugs.
**
** Revision 1.11 93/05/19 18:52:39 shane
** Fixed two bugs.
**
** Revision 1.10 93/04/09 14:41:21 shane
** Standardized style. Optimized.
**
** Revision 1.9 93/03/30 11:59:01 shane
** Added ability to offset foreground into background... calling interface
** is all different.
**
** Revision 1.8 93/03/25 16:39:57 shane
** Re added line I accidentally deleted: "public ImVfb *" line right above
** ImVfbComp declaration
**
**
** Revision 1.7 93/03/25 16:29:09 shane
** Fixed same bug I just fixed in IM_OVER but in IM_ATOP, IM_INSIDE, and IM_OUTSIDE
**
** Revision 1.6 93/03/25 12:22:50 shane
** Fixed
** vertical stripe error, due to improper vfb pointer incrementation
**
** Revision 1.5 92/12/03 01:54:33 nadeau
** Changed names of ImRgbHsi and ImHsiRgb to new names.
**
** Revision 1.4 92/11/18 17:20:03 nadeau
** Updated and rearranged code for greater efficiencey.
** Added more error checks.
**
** Revision 1.3 92/09/04 14:06:49 vle
** Fixed minor initialization bug.
**
** Revision 1.2 92/08/31 17:37:33 vle
** Updated copyright notice.
**
** Revision 1.1 92/08/26 12:45:31 groening
** Initial revision
**
**/
/**
** CODE CREDITS
** Custom development, Chris Groening, San Diego Supercomputer Center, 1990.
**/
#include "iminternal.h"
#ifdef __STDC__
static void imVfbCompOver( ImVfb *fgVfb, int fgX, int fgY, int fgXSize, int fgYSize, int fieldMask,
int bgXInto, int bgYInto,ImVfb *bgVfb, int bgXSize, int bgYSize );
static void imVfbCompInside(ImVfb *fgVfb, int fgX, int fgY, int fgXSize, int fgYSize, int fieldMask,
int bgXInto, int bgYInto,ImVfb *bgVfb, int bgXSize, int bgYSize);
static void imVfbCompOutside(ImVfb *fgVfb, int fgX, int fgY, int fgXSize, int fgYSize, int fieldMask,
int bgXInto, int bgYInto,ImVfb *bgVfb, int bgXSize, int bgYSize);
static void imVfbCompAtop(ImVfb *fgVfb, int fgX, int fgY, int fgXSize, int fgYSize, int fieldMask,
int bgXInto, int bgYInto,ImVfb *bgVfb, int bgXSize, int bgYSize);
#else
extern ImVfb *ImVfbComp();
static void imVfbCompOver();
static void imVfbCompInside();
static void imVfbCompOutside();
static void imVfbCompAtop();
#endif
/*
* FUNCTION
* ImVfbComp - composites the fields in a virtual frame buffer.
* The result is stored in the background VFB, whose address is
* also returned.
*
* DESCRIPTION
* The two source images are composited together for each field in
* fieldMask based upon the chosen operator.
*/
ImVfb * /* Returns destination vfb */
#ifdef __STDC__
ImVfbComp( ImVfb *fgVfb, int fgX, int fgY, int fgXSize, int fgYSize, int fieldMask, int zOperator, ImVfb *bgVfb,
int bgXInto, int bgYInto )
#else
ImVfbComp( fgVfb, fgX, fgY, fgXSize, fgYSize, fieldMask, zOperator, bgVfb,
bgXInto, bgYInto )
ImVfb *fgVfb; /* incoming forground vfb */
int fgX; /* right hand edge of fgVfb */
int fgY; /* top edge of fgVfb */
int fgXSize; /* width of fgVfb */
int fgYSize; /* height of fgVfb */
int fieldMask; /* what field to replace */
int zOperator; /* what operator to to perform on field */
ImVfb *bgVfb; /* incoming bg vfb which is final dest vfb */
int bgXInto; /* x coordinate of fgVfb inside of bgVfb*/
int bgYInto; /* y coordinate of fgVfb inside of bgVfb*/
#endif
{
int fgField; /* foreground fields */
int bgField; /* background fields */
int neededFields; /* Fields needed in VFB's */
/*
* Make sure the foreground and background images are valid.
*/
if ( fgVfb == IMVFBNULL )
{
ImErrNo = IMENOVFB;
return ( IMVFBNULL );
}
if ( bgVfb == IMVFBNULL )
{
ImErrNo = IMENOVFB;
return ( IMVFBNULL );
}
/*
* Clamp values that don't make sense. It's ok to have negative
* bgXInto and bgYInto, however.
*/
if ( fgXSize < 0 )
fgXSize = 0;
else if ( fgXSize > ImVfbQWidth( fgVfb ) )
fgXSize = ImVfbQWidth( fgVfb );
if ( fgYSize < 0 )
fgYSize = 0;
else if ( fgYSize > ImVfbQHeight( fgVfb ) )
fgYSize = ImVfbQHeight( fgVfb );
if ( fgX < 0 )
fgX = 0;
else if ( fgX > ImVfbQWidth( fgVfb ) )
fgX = ImVfbQWidth( fgVfb );
if ( fgY < 0 )
fgY = 0;
else if ( fgY > ImVfbQHeight( fgVfb ) )
fgY = ImVfbQHeight( fgVfb );
if ( bgXInto > ImVfbQWidth( bgVfb ) )
bgXInto = ImVfbQWidth( bgVfb );
if ( bgYInto > ImVfbQHeight( bgVfb ) )
bgYInto = ImVfbQHeight( bgVfb );
/*
* When the user decides to use to xstart and/or ystart options,
* we must adjust the width so that we don't scan past the actual
* width of the foreground.
*/
fgXSize = ImVfbQWidth( fgVfb ) - fgX;
fgYSize = ImVfbQHeight( fgVfb ) - fgY;
/*
* Make sure the sources each have the fields listed in the
* field mask.
*/
if ( fieldMask == 0 )
{
ImErrNo = IMEFIELD;
return ( IMVFBNULL );
}
if ( fieldMask & IMVFBRGB )
fieldMask = (fieldMask & ~IMVFBRGB) | IMRED | IMGREEN | IMBLUE;
if ( fieldMask & (IMHUE | IMSATURATION | IMINTENSITY) )
neededFields = IMVFBRGB | (fieldMask & ~(IMHUE | IMSATURATION | IMINTENSITY));
else if ( fieldMask & (IMRED | IMGREEN | IMBLUE) )
neededFields = IMVFBRGB | (fieldMask & ~(IMRED | IMGREEN | IMBLUE));
else
neededFields = fieldMask;
fgField = ImVfbQFields( fgVfb );
bgField = ImVfbQFields( bgVfb );
if ( (fgField & neededFields) != neededFields )
{
ImErrNo = IMEFIELD;
return ( IMVFBNULL );
}
if ( (bgField & neededFields) != neededFields )
{
ImErrNo = IMEFIELD;
return ( IMVFBNULL );
}
/*
* Make sure the zOperator is valid and that the right set of
* alpha channels are available.
*/
switch ( zOperator )
{
case IMCOMPOVER:
if ( !(fgField & IMALPHA) )
{
ImErrNo = IMENOALPHA;
return ( IMVFBNULL );
}
break;
case IMCOMPATOP:
if ( !(fgField & IMALPHA) )
{
ImErrNo = IMENOALPHA;
return ( IMVFBNULL );
}
if ( !(bgField & IMALPHA) )
{
ImErrNo = IMENOALPHA;
return ( IMVFBNULL );
}
break;
case IMCOMPINSIDE:
case IMCOMPOUTSIDE:
if ( !(bgField & IMALPHA) )
{
ImErrNo = IMENOALPHA;
return ( IMVFBNULL );
}
break;
default:
ImErrNo = IMEOPERATION;
break;
}
/*
* If the needed fields don't match up, then is is an error.
*/
if ( (ImVfbQFields( bgVfb ) & neededFields) != neededFields )
{
ImErrNo = IMEFIELD;
return ( IMVFBNULL );
}
/*
* Composite them!
*/
switch ( zOperator )
{
case IMCOMPOVER:
imVfbCompOver( fgVfb, fgX, fgY, fgXSize, fgYSize, fieldMask,
bgXInto, bgYInto, bgVfb, ImVfbQWidth( bgVfb),
ImVfbQHeight( bgVfb ));
break;
case IMCOMPINSIDE:
imVfbCompInside( fgVfb, fgX, fgY, fgXSize, fgYSize, fieldMask,
bgXInto, bgYInto, bgVfb, ImVfbQWidth( bgVfb),
ImVfbQHeight( bgVfb ));
break;
case IMCOMPOUTSIDE:
imVfbCompOutside( fgVfb, fgX, fgY, fgXSize, fgYSize, fieldMask,
bgXInto, bgYInto, bgVfb, ImVfbQWidth( bgVfb),
ImVfbQHeight( bgVfb ));
break;
case IMCOMPATOP:
imVfbCompAtop( fgVfb, fgX, fgY, fgXSize, fgYSize, fieldMask,
bgXInto, bgYInto, bgVfb, ImVfbQWidth( bgVfb),
ImVfbQHeight( bgVfb ));
break;
}
return( bgVfb);
}
/*
* FUNCTION
* imVfbCompOver - composite using the IM_OVER operator
* imVfbCompAtop - composite using the IM_ATOP operator
* imVfbCompInside - composite using the IM_INSIDE operator
* imVfbCompOutside- composite using the IM_OUTSIDE operator
*
* DESCRIPTION
* The two source images are composited into the destination image based
* upon the operator:
*
* over:
* OutChannel = In1Channel * In1Alpha +
* In2Channel * (1.0 - In1Alpha)
*
* atop:
* OutChannel = In1Channel * In2Alpha +
* In2Channel * (1.0 - In1Alpha)
*
* inside:
* OutChannel = In1Channel * In2Alpha
*
* outside:
* OutChannel = In1Channel * (1.0 - In2Alpha)
*
* Each of the following four routines are essentially identical
* except for the application of the operator equations above.
*/
#define IM_OVER( query, set ) \
{ \
set( bgVfb, pBg, \
(float)(query( fgVfb, pFg )) * alpha1 + \
(float)(query( bgVfb, pBg )) * (1.0 - alpha1) ); \
}
#define IM_ATOP( query, set ) \
{ \
set( bgVfb, pBg, \
(float)(query( fgVfb, pFg )) * alpha2 + \
(float)(query( bgVfb, pBg )) * (1.0 - alpha1) ); \
}
#define IM_INSIDE( query, set ) \
{ \
set( bgVfb, pBg, \
(float)(query( fgVfb, pFg )) * alpha2 ); \
}
#define IM_OUTSIDE( query, set ) \
{ \
set( bgVfb, pBg, \
(float)(query( fgVfb, pFg )) * (1.0 - alpha2) ); \
}
#define IM_GETHSI( hsi, rgb, srcVfb, pSrc ) \
rgb[0] = ImVfbQRed( srcVfb, pSrc ); \
rgb[1] = ImVfbQGreen( srcVfb, pSrc ); \
rgb[2] = ImVfbQBlue( srcVfb, pSrc ); \
ImRgbToHsi( rgb, hsi );
#define IM_PUTRGB( hsi, rgb, srcVfb, pSrc ) \
ImHsiToRgb( hsi, rgb ); \
ImVfbSRed( srcVfb, pSrc, rgb[0] ); \
ImVfbSGreen( srcVfb, pSrc, rgb[1] ); \
ImVfbSBlue( srcVfb, pSrc, rgb[2] );
static void /* Returns nothin */
#ifdef __STDC__
imVfbCompOver( ImVfb *fgVfb, int fgX, int fgY, int fgXSize, int fgYSize, int fieldMask,
int bgXInto, int bgYInto,ImVfb *bgVfb, int bgXSize, int bgYSize )
#else
imVfbCompOver( fgVfb, fgX, fgY, fgXSize, fgYSize, fieldMask, bgXInto, bgYInto,
bgVfb, bgXSize, bgYSize )
ImVfb *fgVfb; /* incoming vfb foreground */
int fgX; /* X offset into foreground */
int fgY; /* Y offset into background */
int fgXSize; /* width of foreground to copy */
int fgYSize; /* height of foregroiund to copy */
int fieldMask; /* what field to replace */
int bgXInto; /* X offset of foreground into background */
int bgYInto; /* Y offset of foreground into background */
ImVfb *bgVfb; /* incoming vfb background */
int bgXSize; /* width of background */
int bgYSize; /* height of background */
#endif
{
int i,j; /* counters */
ImVfbPtr pFg; /* VFB pointer into fgVfb */
ImVfbPtr pBg; /* VFB pointer into bgVfb */
float hsi1[3], hsi2[3];/* HSI values */
int rgb1[3], rgb2[3];/* RGB values */
float alpha1; /* image 1 alpha */
int minXSize; /* minimum width between fg and bg */
int minYSize; /* minimum height between fg and bg */
/*
* Handle the case when the user wishes to offset the foreground by a
* negative amount. Set their offset to zero and modify offset into
* foreground accordingly.
*/
if (bgXInto < 0)
{
fgX -= bgXInto;
fgXSize += bgXInto;
bgXInto = 0;
}
if (bgYInto < 0)
{
fgY -= bgYInto;
fgYSize += bgYInto;
bgYInto = 0;
}
/*
*/
if ( fgX > ImVfbQWidth( fgVfb ) ) return;
if ( fgY > ImVfbQHeight( fgVfb ) ) return;
/*
* Find the minimum width and height between the fg and bg VFBs.
*/
if ( bgYSize < fgYSize ) minYSize = bgYSize;
else minYSize = fgYSize;
if ( bgXSize < fgXSize ) minXSize = bgXSize;
else minXSize = fgXSize;
/*
* Do the actual composite point by point. Whenever the forground
* overlaps of the left and lower end of the background, it is cut off.
*/
for ( i = 0; i < minYSize; i++ )
if ( (bgYInto + i) < bgYSize )
{
pFg = ImVfbQPtr( fgVfb, fgX, i+fgY );
pBg = ImVfbQPtr( bgVfb, bgXInto, i+bgYInto );
for ( j = 0; j < minXSize; j++ )
if ( (bgXInto + j) < bgXSize )
{
alpha1 = ImVfbQAlpha( fgVfb, pFg )/255.0;
if ( fieldMask & IMRED ) IM_OVER(ImVfbQRed, ImVfbSRed)
if ( fieldMask & IMGREEN ) IM_OVER(ImVfbQGreen, ImVfbSGreen)
if ( fieldMask & IMBLUE ) IM_OVER(ImVfbQBlue, ImVfbSBlue)
if ( fieldMask & IMMONO ) IM_OVER(ImVfbQMono, ImVfbSMono)
if ( fieldMask & IMINDEX8 ) IM_OVER(ImVfbQIndex8,ImVfbSIndex8)
if ( fieldMask & IMINDEX16) IM_OVER(ImVfbQIndex16,ImVfbSIndex16)
if ( fieldMask & IMWPROT ) IM_OVER(ImVfbQWProt, ImVfbSWProt)
if ( fieldMask & IMIDATA ) IM_OVER(ImVfbQIData, ImVfbSIData)
if ( fieldMask & IMFDATA ) IM_OVER(ImVfbQFData, ImVfbSFData)
if ( fieldMask & IMZ ) IM_OVER(ImVfbQZ, ImVfbSZ)
if ( fieldMask & (IMHUE | IMSATURATION | IMINTENSITY) )
{
IM_GETHSI( hsi1, rgb1, fgVfb, pFg );
IM_GETHSI( hsi2, rgb2, bgVfb, pBg );
if ( fieldMask & IMHUE )
hsi2[0] = hsi1[0] * alpha1 + hsi2[0] * (1.0 - alpha1);
if ( fieldMask & IMSATURATION )
hsi2[1] = hsi1[1] * alpha1 + hsi2[1] * (1.0 - alpha1);
if ( fieldMask & IMINTENSITY )
hsi2[2] = hsi1[2] * alpha1 + hsi2[2] * (1.0 - alpha1);
IM_PUTRGB( hsi2, rgb2, bgVfb, pBg );
}
if ( fieldMask & IMALPHA ) IM_OVER( ImVfbQAlpha, ImVfbSAlpha )
ImVfbSInc( fgVfb, pFg );
ImVfbSInc( bgVfb, pBg );
}
}
}
static void /* Returns nothin */
#ifdef __STDC__
imVfbCompAtop( ImVfb *fgVfb, int fgX, int fgY, int fgXSize, int fgYSize, int fieldMask,
int bgXInto, int bgYInto,ImVfb *bgVfb, int bgXSize, int bgYSize )
#else
imVfbCompAtop( fgVfb, fgX, fgY, fgXSize, fgYSize, fieldMask, bgXInto, bgYInto,
bgVfb, bgXSize, bgYSize )
ImVfb *fgVfb; /* incoming vfb foreground */
int fgX; /* X offset into foreground */
int fgY; /* Y offset into background */
int fgXSize; /* width of foreground to copy */
int fgYSize; /* height of foregroiund to copy */
int fieldMask; /* what field to replace */
int bgXInto; /* X offset of foreground into background */
int bgYInto; /* Y offset of foreground into background */
ImVfb *bgVfb; /* incoming vfb background */
int bgXSize; /* width of background */
int bgYSize; /* height of background */
#endif
{
int i,j; /* counters */
ImVfbPtr pFg; /* VFB pointer into fgVfb */
ImVfbPtr pBg; /* VFB pointer into bgVfb */
float hsi1[3], hsi2[3];/* HSI values */
int rgb1[3], rgb2[3];/* RGB values */
float alpha1; /* image 1 alpha */
float alpha2; /* image 2 alpha */
int minXSize; /* minimum width between fg and bg */
int minYSize; /* minimum height between fg and bg */
/*
* Handle the case when the user wishes to offset the foreground by a
* negative amount. Set their offset to zero and modify offset into
* foreground accordingly.
*/
if (bgXInto < 0)
{
fgX -= bgXInto;
fgXSize += bgXInto;
bgXInto = 0;
}
if (bgYInto < 0)
{
fgY -= bgYInto;
fgYSize += bgYInto;
bgYInto = 0;
}
/*
* Find the minimum width and height between the fg and bg VFBs.
*/
if ( bgYSize < fgYSize ) minYSize = bgYSize;
else minYSize = fgYSize;
if ( bgXSize < fgXSize ) minXSize = bgXSize;
else minXSize = fgXSize;
/*
* Do the actual composite point by point. Whenever the forground
* overlaps of the left and lower end of the background, it is cut off.
*/
for ( i = 0; i < minYSize; i++ )
if ( (bgYInto + i) < bgYSize )
{
pFg = ImVfbQPtr( fgVfb, fgX, i+fgY );
pBg = ImVfbQPtr( bgVfb, bgXInto, i+bgYInto );
for ( j = 0; j < minXSize; j++ )
if ( (bgXInto + j) < bgXSize )
{
alpha1 = ImVfbQAlpha( fgVfb, pFg )/255.0;
alpha2 = ImVfbQAlpha( bgVfb, pBg )/255.0;
if ( fieldMask & IMRED ) IM_ATOP(ImVfbQRed, ImVfbSRed)
if ( fieldMask & IMGREEN ) IM_ATOP(ImVfbQGreen, ImVfbSGreen)
if ( fieldMask & IMBLUE ) IM_ATOP(ImVfbQBlue, ImVfbSBlue)
if ( fieldMask & IMMONO ) IM_ATOP(ImVfbQMono, ImVfbSMono)
if ( fieldMask & IMINDEX8 ) IM_ATOP(ImVfbQIndex8,ImVfbSIndex8)
if ( fieldMask & IMINDEX16) IM_ATOP(ImVfbQIndex16,ImVfbSIndex16)
if ( fieldMask & IMWPROT ) IM_ATOP(ImVfbQWProt, ImVfbSWProt)
if ( fieldMask & IMIDATA ) IM_ATOP(ImVfbQIData, ImVfbSIData)
if ( fieldMask & IMFDATA ) IM_ATOP(ImVfbQFData, ImVfbSFData)
if ( fieldMask & IMZ ) IM_ATOP(ImVfbQZ, ImVfbSZ)
if ( fieldMask & (IMHUE | IMSATURATION | IMINTENSITY) )
{
IM_GETHSI( hsi1, rgb1, fgVfb, pFg );
IM_GETHSI( hsi2, rgb2, bgVfb, pBg );
if ( fieldMask & IMHUE )
hsi2[0] = hsi1[0] * alpha2 + hsi2[0] * (1.0 - alpha1);
if ( fieldMask & IMSATURATION )
hsi2[1] = hsi1[1] * alpha2 + hsi2[1] * (1.0 - alpha1);
if ( fieldMask & IMINTENSITY )
hsi2[2] = hsi1[2] * alpha2 + hsi2[2] * (1.0 - alpha1);
IM_PUTRGB( hsi2, rgb2, bgVfb, pBg );
}
if ( fieldMask & IMALPHA ) IM_ATOP( ImVfbQAlpha, ImVfbSAlpha )
ImVfbSInc( fgVfb, pFg );
ImVfbSInc( bgVfb, pBg );
}
}
}
static void /* Returns nothin */
#ifdef __STDC__
imVfbCompInside( ImVfb *fgVfb, int fgX, int fgY, int fgXSize, int fgYSize, int fieldMask,
int bgXInto, int bgYInto,ImVfb *bgVfb, int bgXSize, int bgYSize )
#else
imVfbCompInside( fgVfb, fgX, fgY, fgXSize, fgYSize, fieldMask, bgXInto, bgYInto,
bgVfb, bgXSize, bgYSize )
ImVfb *fgVfb; /* incoming vfb foreground */
int fgX; /* X offset into foreground */
int fgY; /* Y offset into background */
int fgXSize; /* width of foreground to copy */
int fgYSize; /* height of foregroiund to copy */
int fieldMask; /* what field to replace */
int bgXInto; /* X offset of foreground into background */
int bgYInto; /* Y offset of foreground into background */
ImVfb *bgVfb; /* incoming vfb background */
int bgXSize; /* width of background */
int bgYSize; /* height of background */
#endif
{
int i,j; /* counters */
ImVfbPtr pFg; /* VFB pointer into fgVfb */
ImVfbPtr pBg; /* VFB pointer into bgVfb */
float hsi1[3], hsi2[3];/* HSI values */
int rgb1[3], rgb2[3];/* RGB values */
float alpha2; /* image 2 alpha */
int minXSize; /* minimum width between fg and bg */
int minYSize; /* minimum height between fg and bg */
/*
* Handle the case when the user wishes to offset the foreground by a
* negative amount. Set their offset to zero and modify offset into
* foreground accordingly.
*/
if (bgXInto < 0)
{
fgX -= bgXInto;
fgXSize += bgXInto;
bgXInto = 0;
}
if (bgYInto < 0)
{
fgY -= bgYInto;
fgYSize += bgYInto;
bgYInto = 0;
}
/*
* Find the minimum width and height between the fg and bg VFBs.
*/
if ( bgYSize < fgYSize ) minYSize = bgYSize;
else minYSize = fgYSize;
if ( bgXSize < fgXSize ) minXSize = bgXSize;
else minXSize = fgXSize;
/*
* Do the actual composite point by point. Whenever the forground
* overlaps of the left and lower end of the background, it is cut off.
*/
for ( i = 0; i < minYSize; i++ )
if ( (bgYInto + i) < bgYSize )
{
pFg = ImVfbQPtr( fgVfb, fgX, i+fgY );
pBg = ImVfbQPtr( bgVfb, bgXInto, i+bgYInto );
for ( j = 0; j < minXSize; j++ )
if ( (bgXInto + j) < bgXSize )
{
alpha2 = ImVfbQAlpha( bgVfb, pBg )/255.0;
if ( fieldMask & IMRED ) IM_INSIDE(ImVfbQRed, ImVfbSRed)
if ( fieldMask & IMGREEN ) IM_INSIDE(ImVfbQGreen, ImVfbSGreen)
if ( fieldMask & IMBLUE ) IM_INSIDE(ImVfbQBlue, ImVfbSBlue)
if ( fieldMask & IMMONO ) IM_INSIDE(ImVfbQMono, ImVfbSMono)
if ( fieldMask & IMINDEX8 ) IM_INSIDE(ImVfbQIndex8,ImVfbSIndex8)
if ( fieldMask & IMINDEX16) IM_INSIDE(ImVfbQIndex16,ImVfbSIndex16)
if ( fieldMask & IMWPROT ) IM_INSIDE(ImVfbQWProt, ImVfbSWProt)
if ( fieldMask & IMIDATA ) IM_INSIDE(ImVfbQIData, ImVfbSIData)
if ( fieldMask & IMFDATA ) IM_INSIDE(ImVfbQFData, ImVfbSFData)
if ( fieldMask & IMZ ) IM_INSIDE(ImVfbQZ, ImVfbSZ)
if ( fieldMask & (IMHUE | IMSATURATION | IMINTENSITY) )
{
IM_GETHSI( hsi1, rgb1, fgVfb, pFg );
IM_GETHSI( hsi2, rgb2, bgVfb, pBg );
if ( fieldMask & IMHUE )
hsi2[0] = hsi1[0] * alpha2;
if ( fieldMask & IMSATURATION )
hsi2[1] = hsi1[1] * alpha2;
if ( fieldMask & IMINTENSITY )
hsi2[2] = hsi1[2] * alpha2;
IM_PUTRGB( hsi2, rgb2, bgVfb, pBg );
}
if ( fieldMask & IMALPHA ) IM_INSIDE(ImVfbQAlpha, ImVfbSAlpha)
ImVfbSInc( fgVfb, pFg );
ImVfbSInc( bgVfb, pBg );
}
}
}
static void /* Returns nothin */
#ifdef __STDC__
imVfbCompOutside( ImVfb *fgVfb, int fgX, int fgY, int fgXSize, int fgYSize, int fieldMask,
int bgXInto, int bgYInto,ImVfb *bgVfb, int bgXSize, int bgYSize )
#else
imVfbCompOutside( fgVfb, fgX, fgY, fgXSize, fgYSize, fieldMask, bgXInto,
bgYInto, bgVfb, bgXSize, bgYSize )
ImVfb *fgVfb; /* incoming vfb foreground */
int fgX; /* X offset into foreground */
int fgY; /* Y offset into background */
int fgXSize; /* width of foreground to copy */
int fgYSize; /* height of foregroiund to copy */
int fieldMask; /* what field to replace */
int bgXInto; /* X offset of foreground into background */
int bgYInto; /* Y offset of foreground into background */
ImVfb *bgVfb; /* incoming vfb background */
int bgXSize; /* width of background */
int bgYSize; /* height of background */
#endif
{
int i,j; /* counters */
ImVfbPtr pFg; /* VFB pointer into fgVfb */
ImVfbPtr pBg; /* VFB pointer into bgVfb */
float hsi1[3], hsi2[3];/* HSI values */
int rgb1[3], rgb2[3];/* RGB values */
float alpha2; /* image 2 alpha */
int minXSize; /* minimum width between fg and bg */
int minYSize; /* minimum height between fg and bg */
/*
* Handle the case when the user wishes to offset the foreground by a
* negative amount. Set their offset to zero and modify offset into
* foreground accordingly.
*/
if (bgXInto < 0)
{
fgX -= bgXInto;
fgXSize += bgXInto;
bgXInto = 0;
}
if (bgYInto < 0)
{
fgY -= bgYInto;
fgYSize += bgYInto;
bgYInto = 0;
}
/*
* Find the minimum width and height between the fg and bg VFBs.
*/
if ( bgYSize < fgYSize ) minYSize = bgYSize;
else minYSize = fgYSize;
if ( bgXSize < fgXSize ) minXSize = bgXSize;
else minXSize = fgXSize;
/*
* Do the actual composite point by point. Whenever the forground
* overlaps of the left and lower end of the background, it is cut off.
*/
for ( i = 0; i < minYSize; i++ )
if ( (bgYInto + i) < bgYSize )
{
pFg = ImVfbQPtr( fgVfb, fgX, i+fgY );
pBg = ImVfbQPtr( bgVfb, bgXInto, i+bgYInto );
for ( j = 0; j < minXSize; j++ )
if ( (bgXInto + j) < bgXSize )
{
alpha2 = ImVfbQAlpha( bgVfb, pBg )/255.0;
if ( fieldMask & IMRED ) IM_OUTSIDE(ImVfbQRed, ImVfbSRed)
if ( fieldMask & IMGREEN ) IM_OUTSIDE(ImVfbQGreen, ImVfbSGreen)
if ( fieldMask & IMBLUE ) IM_OUTSIDE(ImVfbQBlue, ImVfbSBlue)
if ( fieldMask & IMMONO ) IM_OUTSIDE(ImVfbQMono, ImVfbSMono)
if ( fieldMask & IMINDEX8 ) IM_OUTSIDE(ImVfbQIndex8,ImVfbSIndex8)
if ( fieldMask & IMINDEX16) IM_OUTSIDE(ImVfbQIndex16,ImVfbSIndex16)
if ( fieldMask & IMWPROT ) IM_OUTSIDE(ImVfbQWProt, ImVfbSWProt)
if ( fieldMask & IMIDATA ) IM_OUTSIDE(ImVfbQIData, ImVfbSIData)
if ( fieldMask & IMFDATA ) IM_OUTSIDE(ImVfbQFData, ImVfbSFData)
if ( fieldMask & IMZ ) IM_OUTSIDE(ImVfbQZ, ImVfbSZ)
if ( fieldMask & (IMHUE | IMSATURATION | IMINTENSITY) )
{
IM_GETHSI( hsi1, rgb1, fgVfb, pFg );
IM_GETHSI( hsi2, rgb2, bgVfb, pBg );
if ( fieldMask & IMHUE )
hsi2[0] = hsi1[0] * (1.0 - alpha2);
if ( fieldMask & IMSATURATION )
hsi2[1] = hsi1[1] * (1.0 - alpha2);
if ( fieldMask & IMINTENSITY )
hsi2[2] = hsi1[2] * (1.0 - alpha2);
IM_PUTRGB( hsi2, rgb2, bgVfb, pBg );
}
if ( fieldMask & IMALPHA ) IM_OUTSIDE(ImVfbQAlpha,ImVfbSAlpha)
ImVfbSInc( fgVfb, pFg );
ImVfbSInc( bgVfb, pBg );
}
}
}