1688 lines
29 KiB
C
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 );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|