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

2266 lines
55 KiB
C

/**
** $Header: /roq/libim/imvfb.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/imvfb.c 1 11/02/99 4:38p Zaphod $"
/**
** FILE
** imvfb.c - general VFB functions
**
** PROJECT
** libim - SDSC image manipulation library
**
** DESCRIPTION
** imvfb.c contains the VFB and CLT allocation and deallocation functions
** for the IM package.
**
** PUBLIC CONTENTS
** d =defined constant
** f =function
** m =defined macro
** t =typedef/struct/union
** v =variable
** ? =other
**
** ImVfbAlloc f alocate a virtual frame buffer
** ImVfbFree f deallocate a VFB
**
** ImVfbDup f duplicate a VFB
** ImVfbCopy f copy a subarea within a virtual frame buffer.
** ImVfbClear f clear a virtual frame buffer.
** ImVfbMix f mix together two virtual frame buffers
** ImVfbFill f fill fields of a virtual frame buffer
** ImVfbRoll f rolls (wraps) a vfb.
** ImVfbPrint f print the pixels of a vfb
**
** PRIVATE CONTENTS
** IM_SIZEOF* d sizes of various things
** IM_ALLIGN* m alignment adjustments
** IM_SETPIXEL m set a pixel to a value
**
** imVfbFillRect f fill a rectangular region of a VFB
**
** HISTORY
** $Log: /roq/libim/imvfb.c $
*
* 1 11/02/99 4:38p Zaphod
** Revision 1.20 1995/06/30 22:11:11 bduggan
** fixed non-ansi declaration
**
** Revision 1.19 1995/06/29 00:28:04 bduggan
** updated copyright year
**
** Revision 1.18 1995/06/16 08:49:52 bduggan
** changed bzero to memset and bcopy to memcpy
**
** Revision 1.17 1995/05/17 23:48:17 bduggan
** Added ImVfbPrint
** Added ImGetTransparency
**
** Revision 1.16 1995/03/01 22:25:09 bduggan
** Fixed faulty ramp algorithm
**
** Revision 1.15 1994/10/03 11:29:42 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.14 92/12/03 01:53:20 nadeau
** Changed names of ImRgbHsi to ImRgbToHsi and ImHsiRgb to
** ImHsiToRgb. Moved ImVfbStat code to imvfbhist.c.
**
** Revision 1.13 92/09/02 13:15:52 vle
** Updated copyright notice.
**
** Revision 1.12 92/09/02 13:01:52 nadeau
** Rewrote ImVfbRoll to include additional error checking and be
** more efficient when copying between VFB's of identical type.
**
** Revision 1.11 92/09/01 12:26:18 nadeau
** Rearranged and partially rewrote ImVfbFill to add additional
** error checks and support filling of monochrome, write protect,
** Z-buffer, integer data, and float data fields. Changed call
** arguments to ImVfbFill to add a srcVfb.
**
** Revision 1.10 92/08/26 12:48:04 groening
** added imvfbroll to roll vfb's
**
** Revision 1.9 92/08/07 11:56:52 groening
** added imvfbdata and imvfbroll
**
** Revision 1.8 92/07/14 09:29:34 groening
** Added ImVfbMix, ImVfbFill and corresponding subroutines
** like imSetPixelField, imSetPixelFieldHSI, ImHsiToRgb, ImRgbToHsi
**
** Revision 1.7 92/06/02 16:26:24 nadeau
** Added initial versions of ImVfbMix and ImVfbFade.
**
** Revision 1.6 91/10/03 09:20:42 nadeau
** Cosmetic changes to alloc. Fixed bug in copy.
**
** Revision 1.5 91/03/08 14:35:35 nadeau
** Added comments. Added IMVFBMONO. Dropped IMVFBGRAY. Changed
** IMVFBINDEX32 to IMVFBINDEX16. Moved CLT alloc/free functions
** to a separate file (imclt.c). Moved other general VFB functions
** from separate files into this one.
**
** Revision 1.4 90/07/09 07:15:45 mjb
** *** empty log message ***
**
** Revision 1.3 90/07/02 13:22:28 nadeau
** Updated comment and added inclusion of iminternal.h
**
** Revision 1.2 90/06/25 14:29:30 nadeau
** ImVfb -> ImVfb*, ImClt -> ImClt* type changes plus minor cleanup.
**
** Revision 1.1 90/03/06 17:33:19 mjb
** Initial revision
**
**/
/**
** CODE CREDITS
** Custom development, Dave Nadeau, San Diego Supercomputer Center, 1991.
** Custom development, Michael Bailey, San Diego Supercomputer Center, 1990.
**/
#include "iminternal.h"
#ifdef __STDC__
static void imVfbFillRect( ImVfb *dstVfb, int sxl, int sxr, int syt,
int syb, double xInc, double yInc, double fillStart, int fillField );
#else
static void imVfbFillRect( );
#endif
/* sizes of various variable types: */
#define IM_SIZEOFBYTE sizeof( unsigned char )
#define IM_SIZEOFSHORT sizeof( unsigned short )
#define IM_SIZEOFINT sizeof( unsigned int )
#define IM_SIZEOFFLOAT sizeof( float )
/* ways of aligning to various types: */
#define IM_ALIGNBYTE(n)
#define IM_ALIGNINT(n) ( n += ( (m=(n%IM_SIZEOFINT) ) == 0 ? 0 : IM_SIZEOFINT-m ) )
#define IM_ALIGNFLOAT(n) ( n += ( (m=(n%IM_SIZEOFFLOAT)) == 0 ? 0 : IM_SIZEOFFLOAT-m ))
/*
* FUNCTION
* ImVfbAlloc - alocate a virtual frame buffer
*
* DESCRIPTION
* The size of the VFB is computed based upon the fields mask.
* Space is allocated and byte offsets set up in the VFB structure.
*/
ImVfb * /* Returns VFB */
#ifdef __STDC__
ImVfbAlloc( int width, int height, int fields )
#else
ImVfbAlloc( width, height, fields )
int width, height; /* size of framebuffer */
int fields; /* mask of what information to store */
#endif
{
ImVfb *v; /* ImVfb allocated */
int nbytes; /* # bytes per pixel */
ImVfbPtr p; /* pointer to the frame buffer */
int m; /* mod( nbytes, sizeof(int) ) */
int allbytes; /* TRUE if only allocating byte data */
/* check if have been asked to allocate anything: */
if ( fields == 0 )
{
ImErrNo = IMEFIELD;
return ( IMVFBNULL );
}
/* initialize: */
allbytes = TRUE;
nbytes = 0;
v = (ImVfb *) malloc( sizeof(ImVfb) );
if ( v == NULL )
{
ImErrNo = IMEMALLOC;
return ( IMVFBNULL );
}
if ( fields & IMVFBRED )
fields = (fields & ~IMVFBRED) | IMVFBRGB;
if ( fields & IMVFBGREEN )
fields = (fields & ~IMVFBGREEN) | IMVFBRGB;
if ( fields & IMVFBBLUE )
fields = (fields & ~IMVFBBLUE) | IMVFBRGB;
v->vfb_width = width;
v->vfb_height = height;
v->vfb_fields = fields;
v->vfb_clt = IMCLTNULL;
v->vfb_roff = -1;
v->vfb_goff = -1;
v->vfb_boff = -1;
v->vfb_i8off = -1;
v->vfb_i16off = -1;
v->vfb_aoff = -1;
v->vfb_wpoff = -1;
v->vfb_zoff = -1;
v->vfb_moff = -1;
v->vfb_fpoff = -1;
v->vfb_ioff = -1;
/* check each fields possibility: */
if ( fields & IMVFBRGB )
{
IM_ALIGNBYTE( nbytes );
v->vfb_roff = nbytes;
nbytes += IM_SIZEOFBYTE;
IM_ALIGNBYTE( nbytes );
v->vfb_goff = nbytes;
nbytes += IM_SIZEOFBYTE;
IM_ALIGNBYTE( nbytes );
v->vfb_boff = nbytes;
nbytes += IM_SIZEOFBYTE;
}
if ( fields & IMVFBALPHA )
{
IM_ALIGNBYTE( nbytes );
v->vfb_aoff = nbytes;
nbytes += IM_SIZEOFBYTE;
}
if ( fields & IMVFBINDEX8 )
{
IM_ALIGNBYTE( nbytes );
v->vfb_i8off = nbytes;
nbytes += IM_SIZEOFBYTE;
}
if ( fields & IMVFBMONO )
{
/* Use 1 byte for each mono value. */
IM_ALIGNBYTE( nbytes );
v->vfb_moff = nbytes;
nbytes += IM_SIZEOFBYTE;
}
if ( fields & IMVFBWPROT )
{
IM_ALIGNBYTE( nbytes );
v->vfb_wpoff = nbytes;
nbytes += IM_SIZEOFBYTE;
}
if ( fields & IMVFBINDEX16 )
{
IM_ALIGNINT( nbytes );
v->vfb_i16off = nbytes;
nbytes += IM_SIZEOFSHORT;
allbytes = FALSE;
}
if ( fields & IMVFBZ )
{
IM_ALIGNINT( nbytes );
v->vfb_zoff = nbytes;
nbytes += IM_SIZEOFINT;
allbytes = FALSE;
}
if ( fields & IMVFBFDATA )
{
IM_ALIGNFLOAT( nbytes );
v->vfb_fpoff = nbytes;
nbytes += IM_SIZEOFFLOAT;
allbytes = FALSE;
}
if ( fields & IMVFBIDATA )
{
IM_ALIGNINT( nbytes );
v->vfb_ioff = nbytes;
nbytes += IM_SIZEOFINT;
allbytes = FALSE;
}
/* pad so produces an even integer size, if necessary: */
if ( ! allbytes )
IM_ALIGNINT( nbytes );
v->vfb_nbytes = nbytes;
/* allocate the necessary frame buffer: */
p = (ImVfbPtr) malloc( width*height*nbytes );
if ( p == (ImVfbPtr)NULL )
{
free( (char *) v );
ImErrNo = IMEMALLOC;
return ( IMVFBNULL );
}
v->vfb_pfirst = p;
v->vfb_plast = p + ( nbytes * width * height ) - nbytes;
#ifdef DEBUG
fprintf( stderr, "vfb_pfirst = %0x\n", v->vfb_pfirst );
fprintf( stderr, "vfb_plast = %0x\n", v->vfb_plast );
fprintf( stderr, "vfb_width = %3d\n", v->vfb_width );
fprintf( stderr, "vfb_height = %3d\n", v->vfb_height );
fprintf( stderr, "vfb_fields = %3d\n", v->vfb_fields );
fprintf( stderr, "vfb_nbytes = %3d\n", v->vfb_nbytes );
fprintf( stderr, "vfb_roff = %3d\n", v->vfb_roff );
fprintf( stderr, "vfb_goff = %3d\n", v->vfb_goff );
fprintf( stderr, "vfb_boff = %3d\n", v->vfb_boff );
fprintf( stderr, "vfb_aoff = %3d\n", v->vfb_aoff );
fprintf( stderr, "vfb_i8off = %3d\n", v->vfb_i8off );
fprintf( stderr, "vfb_moff = %3d\n", v->vfb_moff );
fprintf( stderr, "vfb_wpoff = %3d\n", v->vfb_wpoff );
fprintf( stderr, "vfb_i16off = %3d\n", v->vfb_i16off );
fprintf( stderr, "vfb_zoff = %3d\n", v->vfb_zoff );
fprintf( stderr, "vfb_fpoff = %3d\n", v->vfb_fpoff );
fprintf( stderr, "vfb_ioff = %3d\n", v->vfb_ioff );
#endif
/* done: return the pointer to the ImVfb structure: */
return( v );
}
/*
* FUNCTION
* ImVfbFree - deallocate a VFB
*
* DESCRIPTION
* The VFB's data planes are freed, and then the VFB struct itself.
*/
void /* Returns nothing */
#ifdef __STDC__
ImVfbFree( ImVfb *v )
#else
ImVfbFree( v )
ImVfb *v; /* VFB to free */
#endif
{
if ( v != IMVFBNULL )
{
free( (char *) ImVfbQFirst(v) );
free( (char *) v );
}
}
/*
* FUNCTION
* ImVfbDup - duplicate a VFB
*
* DESCRIPTION
* A new VFB is allocated that has the same attributes as the source
* VFB. The source VFB's data is copied to the new VFB.
*
* If the source VFB has a CLT, it is copied and added to the new VFB.
*/
ImVfb * /* Returns new VFB */
#ifdef __STDC__
ImVfbDup( ImVfb* srcVfb )
#else
ImVfbDup( srcVfb )
ImVfb *srcVfb; /* VFB to duplicate */
#endif
{
ImVfb *newVfb; /* New VFB */
ImClt *srcClt; /* Original CLT */
ImClt *newClt; /* New CLT */
newVfb = ImVfbAlloc( ImVfbQWidth( srcVfb ), ImVfbQHeight( srcVfb ),
ImVfbQFields( srcVfb ) );
if( newVfb == 0 )
{
ImErrNo = IMEMALLOC;
return( IMVFBNULL );
}
memcpy( (void *)ImVfbQFirst( newVfb ), (void *)ImVfbQFirst( srcVfb ),
ImVfbQNBytes( srcVfb ) * ImVfbQHeight( srcVfb ) *
ImVfbQWidth( srcVfb ) );
srcClt = ImVfbQClt( srcVfb );
if ( srcClt != IMCLTNULL )
{
newClt = ImCltDup( srcClt );
if ( newClt == IMCLTNULL )
{
ImVfbFree( newVfb );
return ( IMVFBNULL ); /* ImErrNo already set */
}
}
ImVfbSClt( newVfb, srcClt );
return ( newVfb );
}
/*
* FUNCTION
* ImVfbCopy - copy a subarea within a virtual frame buffer.
*
* DESCRIPTION
* Copy a portion of a virtual frame buffer to a new location.
*
* When the incomming and outgoing VFB's have the same set of fields,
* we just do a memcopy(). Otherwise we have to copy each field
* explicitly.
*/
ImVfb * /* Returnes copy of source VFB */
#ifdef __STDC__
ImVfbCopy( ImVfb *srcVfb, int srcXLeft, int srcYTop, int srcDX, int srcDY, int fieldMask,
ImVfb* dstVfb, int dstXLeft, int dstYTop )
#else
ImVfbCopy( srcVfb, srcXLeft, srcYTop, srcDX, srcDY, fieldMask,
dstVfb, dstXLeft, dstYTop )
ImVfb *srcVfb; /* the vfb whose size will change */
int srcXLeft, srcYTop; /* upper left corner of copy area */
int srcDX, srcDY; /* size of copy area */
int fieldMask; /* Fields to copy */
ImVfb *dstVfb; /* the vfb to put the result in */
int dstXLeft, dstYTop; /* upper left corner of the dest. area */
#endif
{
ImVfbPtr psrc; /* pointer into source vfb */
ImVfbPtr pdst; /* pointer into destination vfb */
int i, j; /* counter and temp storage */
int nbytes; /* # bytes of vfb storage per scanline */
int f; /* vfb field description */
int sxl, sxr, syb, syt; /* copy boundaries in source vfb */
int dw, dh; /* copy size */
/* Truncate desired size, if necessary. */
sxl = srcXLeft;
if ( sxl < 0 )
sxl = 0;
if ( sxl >= ImVfbQWidth( srcVfb ) )
sxl = ImVfbQWidth( srcVfb ) - 1;
sxr = srcXLeft + srcDX - 1;
if ( sxr < 0 )
sxr = 0;
if ( sxr >= ImVfbQWidth( srcVfb ) )
sxr = ImVfbQWidth( srcVfb ) - 1;
syt = srcYTop;
if ( syt < 0 )
syt = 0;
if ( syt >= ImVfbQHeight( srcVfb ) )
syt = ImVfbQHeight( srcVfb ) - 1;
syb = srcYTop + srcDY - 1;
if ( syb < 0 )
syb = 0;
if ( syb >= ImVfbQHeight( srcVfb ) )
syb = ImVfbQHeight( srcVfb ) - 1;
/* Swap left and right, top and bottom if necessary. */
if ( sxl > sxr )
{
i = sxl; sxl = sxr; sxr = i;
}
if ( syt > syb )
{
i = syb; syb = syt; syt = i;
}
/* determine widths and see if they are legal: */
dw = sxr - sxl + 1;
if ( dw <= 0 )
{
ImErrNo = IMEWIDTH;
return( IMVFBNULL );
}
dh = syb - syt + 1;
if ( dh <= 0 )
{
ImErrNo = IMEHEIGHT;
return( IMVFBNULL );
}
/* determine the fields on this vfb: */
f = ImVfbQFields( srcVfb );
if ( fieldMask == IMVFBALL )
fieldMask = f;
else
fieldMask = f & fieldMask;
if ( fieldMask == 0 )
{
ImErrNo = IMEFIELD;
return ( IMVFBNULL );
}
if ( dstVfb == IMVFBNEW )
{
/* Allocate the new vfb. */
dstVfb = ImVfbAlloc( dw, dh, fieldMask );
if ( dstVfb == IMVFBNULL )
{
ImErrNo = IMEMALLOC;
return( IMVFBNULL );
}
}
else
{
fieldMask &= ImVfbQFields( dstVfb );
}
/* Loop through destination framebuffer, filling it as we go. */
if ( f == fieldMask && f == ImVfbQFields( dstVfb ) )
{
/* # bytes per scanline: */
nbytes = ImVfbQNBytes( srcVfb ) * dw;
psrc = ImVfbQPtr( srcVfb, sxl, syt );
pdst = ImVfbQPtr(dstVfb, dstXLeft, dstYTop);
for( i = syt; i <= syb; i++ )
{
memcpy( (void *) pdst, (void *) psrc, nbytes );
ImVfbSDown( srcVfb, psrc );
ImVfbSDown( dstVfb, pdst );
}
return( dstVfb );
}
for ( i = syt; i <= syb; i++, dstYTop++ )
{
psrc = ImVfbQPtr( srcVfb, sxl, i );
pdst = ImVfbQPtr( dstVfb, dstXLeft, dstYTop );
for ( j = sxl; j <= sxr; j++ )
{
if ( fieldMask & IMVFBMONO )
{
ImVfbSMono( dstVfb, pdst, ImVfbQMono( srcVfb, psrc ) );
}
if ( fieldMask & IMVFBINDEX8 )
{
ImVfbSIndex8( dstVfb, pdst, ImVfbQIndex8( srcVfb, psrc ) );
}
if ( fieldMask & IMVFBINDEX16 )
{
ImVfbSIndex16( dstVfb, pdst, ImVfbQIndex16( srcVfb, psrc ) );
}
if ( fieldMask & IMVFBRGB )
{
ImVfbSRed( dstVfb, pdst, ImVfbQRed( srcVfb, psrc ) );
ImVfbSGreen( dstVfb, pdst, ImVfbQGreen( srcVfb, psrc ) );
ImVfbSBlue( dstVfb, pdst, ImVfbQBlue( srcVfb, psrc ) );
}
if ( fieldMask & IMVFBALPHA )
{
ImVfbSAlpha( dstVfb, pdst, ImVfbQAlpha( srcVfb, psrc ) );
}
if ( fieldMask & IMVFBIDATA )
{
ImVfbSIData( dstVfb, pdst, ImVfbQIData( srcVfb, psrc ) );
}
if ( fieldMask & IMVFBFDATA )
{
ImVfbSFData( dstVfb, pdst, ImVfbQFData( srcVfb, psrc ) );
}
if ( fieldMask & IMVFBZ )
{
ImVfbSZ( dstVfb, pdst, ImVfbQZ( srcVfb, psrc ) );
}
if ( fieldMask & IMVFBWPROT )
{
ImVfbSWProt( dstVfb, pdst, ImVfbQWProt( srcVfb, psrc ) );
}
ImVfbSInc( srcVfb, psrc );
ImVfbSInc( dstVfb, pdst );
}
}
return( dstVfb );
}
/*
* FUNCTION
* IM_SETPIXEL - set a pixel to a value.
* ImVfbClear - clear a virtual frame buffer.
*
* DESCRIPTION
* Erases a portion of a VFB.
*/
#define IM_SETPIXEL(dstVfb,pdst,fieldMask,value) \
{ \
if ( fieldMask & IMVFBRGB ) \
{ \
ImVfbSRed( dstVfb, pdst, (value) ); \
ImVfbSGreen( dstVfb, pdst, (value) ); \
ImVfbSBlue( dstVfb, pdst, (value) ); \
} \
if ( fieldMask & IMVFBMONO ) \
ImVfbSMono( dstVfb, pdst, (value) ); \
if ( fieldMask & IMVFBINDEX8 ) \
ImVfbSIndex8( dstVfb, pdst, (value) ); \
if ( fieldMask & IMVFBINDEX16 ) \
ImVfbSIndex16( dstVfb, pdst, (value) ); \
if ( fieldMask & IMVFBALPHA ) \
ImVfbSAlpha( dstVfb, pdst, (value) ); \
if ( fieldMask & IMVFBIDATA ) \
ImVfbSIData( dstVfb, pdst, (value) ); \
if ( fieldMask & IMVFBFDATA ) \
ImVfbSFData( dstVfb, pdst, (value) ); \
if ( fieldMask & IMVFBZ ) \
ImVfbSZ( dstVfb, pdst, (value) ); \
if ( fieldMask & IMVFBWPROT ) \
ImVfbSWProt( dstVfb, pdst, (value) ); \
}
ImVfb * /* Returns cleared VFB */
#ifdef __STDC__
ImVfbClear( int fieldMask, int value, ImVfb* dstVfb )
#else
ImVfbClear( fieldMask, value, dstVfb )
int fieldMask; /* Fields to copy */
int value; /* Value to set fields to */
ImVfb *dstVfb; /* the vfb to put the result in */
#endif
{
ImVfbPtr pdst; /* pointer into destination vfb */
int i, j; /* counter and temp storage */
int nbytes; /* # bytes of vfb storage per scanline */
int f; /* vfb field description */
int width, height; /* Image width and height */
width = ImVfbQWidth( dstVfb );
height = ImVfbQHeight( dstVfb );
f = ImVfbQFields( dstVfb );
fieldMask = f & fieldMask;
/* Loop through destination framebuffer, filling it as we go. */
if ( f == fieldMask && f == ImVfbQFields( dstVfb ) && value == 0 )
{
/* # bytes per scanline: */
nbytes = ImVfbQNBytes( dstVfb ) * width;
pdst = ImVfbQFirst( dstVfb );
for( i = 0; i < height; i++ )
{
memset( (void *) pdst, 0x00, nbytes );
ImVfbSDown( dstVfb, pdst );
}
return( dstVfb );
}
pdst = ImVfbQFirst( dstVfb );
for ( i = 0; i < height; i++ )
{
for ( j = 0; j < width; j++ )
{
IM_SETPIXEL( dstVfb, pdst, fieldMask, value );
ImVfbSInc( dstVfb, pdst );
}
}
return ( dstVfb );
}
/*
* FUNCTION
* ImVfbMix - mix together two virtual frame buffers
*
* DESCRIPTION
* Pixels in the two source images are mixed together based upon the
* given weighting factors:
*
* w1 = src1Weight / (src1Weight + src2Weight)
* w2 = src2Weight / (src1Weight + src2Weight)
*
* dst = src1 * w1 + src2 * w2
*/
ImVfb * /* Returns new VFB */
#ifdef __STDC__
ImVfbMix(ImVfb* src1Vfb, double src1Weight, ImVfb* src2Vfb, double src2Weight, int fieldMask, ImVfb *dstVfb )
#else
ImVfbMix( src1Vfb, src1Weight, src2Vfb, src2Weight, fieldMask, dstVfb )
ImVfb *src1Vfb; /* First source VFB */
double src1Weight; /* First source's weighting factor */
ImVfb *src2Vfb; /* Second source VFB */
double src2Weight; /* Second source's weighting factor */
int fieldMask; /* Fields to combine */
ImVfb *dstVfb; /* Resulting VFB */
#endif
{
ImVfbPtr psrc1, psrc2; /* Source VFB pixel pointers */
ImVfbPtr pdst; /* Destination VFB pixel pointer */
int pixel1, pixel2; /* Source pixel values */
int i, j; /* Counters and temp storage */
int f; /* vfb field description */
int dw, dh; /* copy size */
float divisor; /* Weighting factor divisor */
int tempMask;
/*
* Normalize weighting factors.
*/
divisor = 1.0 / (src1Weight + src2Weight);
src1Weight *= divisor;
src2Weight *= divisor;
/*
* Determine the fields to be affected.
*/
tempMask = fieldMask;
f = ImVfbQFields( src1Vfb ) & ImVfbQFields( src2Vfb );
if ( fieldMask == IMVFBALL )
fieldMask = f;
else
fieldMask = f & fieldMask;
if ( (tempMask&IMVFBRED) && (f&IMVFBRGB)) fieldMask |= IMVFBRED ;
if ( (tempMask&IMVFBGREEN) && (f&IMVFBRGB)) fieldMask |= IMVFBGREEN ;
if ( (tempMask&IMVFBBLUE) && (f&IMVFBRGB)) fieldMask |= IMVFBBLUE ;
if ( fieldMask == 0 )
{
ImErrNo = IMEFIELD;
return ( IMVFBNULL );
}
/*
* Determine XY range of pixels to be dissolved.
*/
dw = ImVfbQWidth( src1Vfb ) < ImVfbQWidth( src2Vfb ) ?
ImVfbQWidth( src1Vfb ) : ImVfbQWidth( src2Vfb );
dh = ImVfbQHeight( src1Vfb ) < ImVfbQHeight( src2Vfb ) ?
ImVfbQHeight( src1Vfb ) : ImVfbQHeight( src2Vfb );
if ( dstVfb == IMVFBNEW )
{
/* Create a new VFB at the size of the smallest source. */
dstVfb = ImVfbAlloc( dw, dh, fieldMask );
if ( dstVfb == IMVFBNULL )
{
ImErrNo = IMEMALLOC;
return( IMVFBNULL );
}
}
else
{
if ( dw > ImVfbQWidth( dstVfb ) )
dw = ImVfbQWidth( dstVfb );
if ( dh > ImVfbQHeight( dstVfb ) )
dh = ImVfbQHeight( dstVfb );
}
if ( dw <= 0 )
{
ImErrNo = IMEWIDTH;
return( IMVFBNULL );
}
if ( dh <= 0 )
{
ImErrNo = IMEHEIGHT;
return( IMVFBNULL );
}
/*
* Loop through the VFB's, copying pixels to the destination VFB
* using the formula:
*
* dst = src1 * src1Wieght + src2 * src2Weight
*/
for ( i = 0; i < dh; i++ )
{
psrc1 = ImVfbQPtr( src1Vfb, 0, i );
psrc2 = ImVfbQPtr( src2Vfb, 0, i );
pdst = ImVfbQPtr( dstVfb, 0, i );
for ( j = 0; j < dw; j++ )
{
if ( fieldMask & IMVFBMONO )
{
pixel1 = ImVfbQMono( src1Vfb, psrc1 );
pixel2 = ImVfbQMono( src2Vfb, psrc2 );
ImVfbSMono( dstVfb, pdst,
(int)( pixel1 * src1Weight +
pixel2 * src2Weight ) );
}
if ( fieldMask & IMVFBINDEX8 )
{
pixel1 = ImVfbQIndex8( src1Vfb, psrc1 );
pixel2 = ImVfbQIndex8( src2Vfb, psrc2 );
ImVfbSIndex8( dstVfb, pdst,
(int)( pixel1 * src1Weight +
pixel2 * src2Weight ) );
}
if ( fieldMask & IMVFBINDEX16 )
{
pixel1 = ImVfbQIndex16( src1Vfb, psrc1 );
pixel2 = ImVfbQIndex16( src2Vfb, psrc2 );
ImVfbSIndex16( dstVfb, pdst,
(int)( pixel1 * src1Weight +
pixel2 * src2Weight ) );
}
if ( fieldMask & IMVFBRED )
{
pixel1 = ImVfbQRed( src1Vfb, psrc1 );
pixel2 = ImVfbQRed( src2Vfb, psrc2 );
ImVfbSRed( dstVfb, pdst,
(int)( pixel1 * src1Weight +
pixel2 * src2Weight ) );
}
if ( fieldMask & IMVFBGREEN )
{
pixel1 = ImVfbQGreen( src1Vfb, psrc1 );
pixel2 = ImVfbQGreen( src2Vfb, psrc2 );
ImVfbSGreen( dstVfb, pdst,
(int)( pixel1 * src1Weight +
pixel2 * src2Weight ) );
}
if ( fieldMask & IMVFBBLUE )
{
pixel1 = ImVfbQBlue( src1Vfb, psrc1 );
pixel2 = ImVfbQBlue( src2Vfb, psrc2 );
ImVfbSBlue( dstVfb, pdst,
(int)( pixel1 * src1Weight +
pixel2 * src2Weight ) );
}
if ( fieldMask & IMVFBRGB )
{
pixel1 = ImVfbQRed( src1Vfb, psrc1 );
pixel2 = ImVfbQRed( src2Vfb, psrc2 );
ImVfbSRed( dstVfb, pdst,
(int)( pixel1 * src1Weight +
pixel2 * src2Weight ) );
pixel1 = ImVfbQGreen( src1Vfb, psrc1 );
pixel2 = ImVfbQGreen( src2Vfb, psrc2 );
ImVfbSGreen( dstVfb, pdst,
(int)( pixel1 * src1Weight +
pixel2 * src2Weight ) );
pixel1 = ImVfbQBlue( src1Vfb, psrc1 );
pixel2 = ImVfbQBlue( src2Vfb, psrc2 );
ImVfbSBlue( dstVfb, pdst,
(int)( pixel1 * src1Weight +
pixel2 * src2Weight ) );
}
if ( fieldMask & IMVFBALPHA )
{
pixel1 = ImVfbQAlpha( src1Vfb, psrc1 );
pixel2 = ImVfbQAlpha( src2Vfb, psrc2 );
ImVfbSAlpha( dstVfb, pdst,
(int)( pixel1 * src1Weight +
pixel2 * src2Weight ) );
}
if ( fieldMask & IMVFBIDATA )
{
pixel1 = ImVfbQIData( src1Vfb, psrc1 );
pixel2 = ImVfbQIData( src2Vfb, psrc2 );
ImVfbSIData( dstVfb, pdst,
(int)( pixel1 * src1Weight +
pixel2 * src2Weight ) );
}
if ( fieldMask & IMVFBFDATA )
{
ImVfbSFData( dstVfb, pdst,
( ImVfbQFData( src1Vfb, psrc1 ) *
src1Weight +
ImVfbQFData( src2Vfb, psrc2 ) *
src2Weight ) );
}
if ( fieldMask & IMVFBZ )
{
pixel1 = ImVfbQZ( src1Vfb, psrc1 );
pixel2 = ImVfbQZ( src2Vfb, psrc2 );
ImVfbSZ( dstVfb, pdst,
(int)( pixel1 * src1Weight +
pixel2 * src2Weight ) );
}
if ( fieldMask & IMVFBWPROT )
{
pixel1 = ImVfbQWProt( src1Vfb, psrc1 );
pixel2 = ImVfbQWProt( src2Vfb, psrc2 );
ImVfbSWProt( dstVfb, pdst,
(int)( pixel1 * src1Weight +
pixel2 * src2Weight ) );
}
ImVfbSInc( src1Vfb, psrc1 );
ImVfbSInc( src2Vfb, psrc2 );
ImVfbSInc( dstVfb, pdst );
}
}
return( dstVfb );
}
/*
* FUNCTION
* ImVfbFade - fade a virtual frame buffer to 0's
*
* DESCRIPTION
* Pixels are faded towards zero in all fields using the given weighting
* factor:
*
* dst = src * weight
*/
ImVfb * /* Returns new VFB */
#ifdef __STDC__
ImVfbFade( ImVfb* srcVfb, double srcWeight, int fieldMask, ImVfb* dstVfb )
#else
ImVfbFade( srcVfb, srcWeight, fieldMask, dstVfb )
ImVfb *srcVfb; /* First source VFB */
double srcWeight; /* First source's weighting factor */
int fieldMask; /* Fields to combine */
ImVfb *dstVfb; /* Resulting VFB */
#endif
{
ImVfbPtr psrc; /* Source VFB pixel pointers */
ImVfbPtr pdst; /* Destination VFB pixel pointer */
int pixel; /* Source pixel values */
int i, j; /* Counters and temp storage */
int f; /* vfb field description */
int dw, dh; /* copy size */
/*
* Determine the fields to be affected.
*/
f = ImVfbQFields( srcVfb );
if ( fieldMask == IMVFBALL )
fieldMask = f;
else
fieldMask = f & fieldMask;
if ( fieldMask == 0 )
{
ImErrNo = IMEFIELD;
return ( IMVFBNULL );
}
/*
* Determine XY range of pixels to be faded.
*/
dw = ImVfbQWidth( srcVfb );
dh = ImVfbQHeight( srcVfb );
if ( dstVfb == IMVFBNEW )
{
/* Create a new VFB at the size of the smallest source. */
dstVfb = ImVfbAlloc( dw, dh, fieldMask );
if ( dstVfb == IMVFBNULL )
{
ImErrNo = IMEMALLOC;
return( IMVFBNULL );
}
}
else
{
fieldMask &= ImVfbQFields( dstVfb );
if ( dw > ImVfbQWidth( dstVfb ) )
dw = ImVfbQWidth( dstVfb );
if ( dh > ImVfbQHeight( dstVfb ) )
dh = ImVfbQHeight( dstVfb );
}
if ( dw <= 0 )
{
ImErrNo = IMEWIDTH;
return( IMVFBNULL );
}
if ( dh <= 0 )
{
ImErrNo = IMEHEIGHT;
return( IMVFBNULL );
}
/*
* Loop through the VFB's, copying pixels to the destination VFB
* using the formula:
*
* dst = src * srcWieght
*/
for ( i = 0; i < dh; i++ )
{
psrc = ImVfbQPtr( srcVfb, 0, i );
pdst = ImVfbQPtr( dstVfb, 0, i );
for ( j = 0; j < dw; j++ )
{
if ( fieldMask & IMVFBMONO )
{
pixel = ImVfbQMono( srcVfb, psrc );
ImVfbSMono( dstVfb, pdst,
(int)( pixel * srcWeight ) & 0x1 );
}
if ( fieldMask & IMVFBINDEX8 )
{
pixel = ImVfbQIndex8( srcVfb, psrc );
ImVfbSIndex8( dstVfb, pdst,
(int)( pixel * srcWeight ) & 0xFF );
}
if ( fieldMask & IMVFBINDEX16 )
{
pixel = ImVfbQIndex16( srcVfb, psrc );
ImVfbSIndex16( dstVfb, pdst,
(int)( pixel * srcWeight ) & 0xFFFF );
}
if ( fieldMask & IMVFBRGB )
{
pixel = ImVfbQRed( srcVfb, psrc );
ImVfbSRed( dstVfb, pdst,
(int)( pixel * srcWeight ) & 0xFF );
pixel = ImVfbQGreen( srcVfb, psrc );
ImVfbSGreen( dstVfb, pdst,
(int)( pixel * srcWeight ) & 0xFF );
pixel = ImVfbQBlue( srcVfb, psrc );
ImVfbSBlue( dstVfb, pdst,
(int)( pixel * srcWeight ) & 0xFF );
}
if ( fieldMask & IMVFBALPHA )
{
pixel = ImVfbQAlpha( srcVfb, psrc );
ImVfbSAlpha( dstVfb, pdst,
(int)( pixel * srcWeight ) & 0xFF );
}
if ( fieldMask & IMVFBIDATA )
{
pixel = ImVfbQIData( srcVfb, psrc );
ImVfbSIData( dstVfb, pdst,
(int)( pixel * srcWeight ) );
}
if ( fieldMask & IMVFBFDATA )
{
ImVfbSFData( dstVfb, pdst,
( ImVfbQFData( srcVfb, psrc ) *
srcWeight ) );
}
if ( fieldMask & IMVFBZ )
{
pixel = ImVfbQZ( srcVfb, psrc );
ImVfbSZ( dstVfb, pdst,
(int)( pixel * srcWeight ) );
}
if ( fieldMask & IMVFBWPROT )
{
pixel = ImVfbQWProt( srcVfb, psrc );
ImVfbSWProt( dstVfb, pdst,
(int)( pixel * srcWeight ) );
}
ImVfbSInc( srcVfb, psrc );
ImVfbSInc( dstVfb, pdst );
}
}
return( dstVfb );
}
/*
* FUNCTION
* ImHsiToRgb( hsi, rgb )
*
* DESCRIPTION
* convert a hue-saturation-intensity into a red-green-blue value
*/
#define IM_Round(x) ( (int)( (x) + 0.5 ) )
void /* Returns nothing */
#ifdef __STDC__
ImHsiToRgb( float hsi[3], int rgb[3] )
#else
ImHsiToRgb( hsi, rgb )
float hsi[3]; /* HSI to convert */
int rgb[3]; /* Returned RGB */
#endif
{
float h, s, i; /* hue, sat, intens */
float delta; /* change in color intens */
float r, g, b; /* red, green, blue */
int ih; /* integer hue */
/* guarantee valid input: */
h = hsi[0] /360.;
ih = (int) h;
h = h - (float)ih;
s = hsi[1];
if( s < 0. )
s = 0.;
if( s > 1. )
s = 1.;
i = hsi[2];
if( i < 0. )
i = 0.;
if( i > 1. )
i = 1.;
/* get an rgb from the hue itself: */
if( h <= (1./6.) )
{
r = 1.0;
g = 6. * h;
b = 0.;
}
else if( h <= (2./6.) )
{
r = 2. - 6. * h;
g = 1.;
b = 0.;
}
else if( h <= (3./6.) )
{
r = 0.;
g = 1.;
b = 6. * h - 2.;
}
else if( h <= (4./6.) )
{
r = 0.;
g = 4. - 6. * h;
b = 1.;
}
else if( h <= (5./6.) )
{
r = 6. * h - 4.;
g = 0.;
b = 1.;
}
else
{
r = 1.;
g = 0.;
b = 6. - 6. * h;
}
/* add in the saturation and intensity effects: */
/* red: */
delta = s * ( r - 0.5 );
if( i <= 0.5 )
r = 2.*i*( 0.5 + delta );
else
r = 0.5 + delta + (2.*i-1.)*( 0.5 - delta );
/* green: */
delta = s * ( g - 0.5 );
if( i <= 0.5 )
g = 2.*i*( 0.5 + delta );
else
g = 0.5 + delta + (2.*i-1.)*( 0.5 - delta );
/* blue: */
delta = s * ( b - 0.5 );
if( i <= 0.5 )
b = 2.*i*( 0.5 + delta );
else
b = 0.5 + delta + (2.*i-1.)*( 0.5 - delta );
/* convert to integer in the range 0-255: */
rgb[0] = IM_Round( 255. * r );
rgb[1] = IM_Round( 255. * g );
rgb[2] = IM_Round( 255. * b );
}
/*
* FUNCTION
* RgbHsi
*
* DESCRIPTION
* convert a red-green-blue value into hue-saturation-intensity
*/
void /* Returns nothing */
#ifdef __STDC__
ImRgbToHsi( int rgb[3], float hsi[3] )
#else
ImRgbToHsi( rgb, hsi )
int rgb[3]; /* RGB to convert */
float hsi[3]; /* HSI to return */
#endif
{
int r, g, b; /* red, green, blue */
int min, max; /* min and max rgb values */
float fmin, fmax, diff; /* min, max, and range of rgb vals */
float hue, sat, intens; /* h s i */
float cr, cg, cb; /* coefficients for computing hue */
/* guarantee valid input: */
r = rgb[0] & 255;
g = rgb[1] & 255;
b = rgb[2] & 255;
/* determine min and max color primary values: */
min = r;
max = r;
if( g < min ) min = g;
if( g > max ) max = g;
if( b < min ) min = b;
if( b > max ) max = b;
fmin = (float)min;
fmax = (float)max;
diff = fmax - fmin;
/* special case r==g==b==0 */
if( max == 0 )
{
hsi[0] = 0.;
hsi[1] = 0.;
hsi[2] = 0.;
return;
}
/* special case r==g==b==255 */
if( min == 255 )
{
hsi[0] = 0.;
hsi[1] = 1.;
hsi[2] = 1.;
return;
}
/* compute saturation: */
intens = ( fmin + fmax ) / (255.+255.);
if( intens <= 0.5 )
sat = diff / (fmax + fmin);
else
sat = diff / ( 255.+255. - fmax - fmin );
/* compute hue: */
if( max == min )
hue = 0.0;
else
{
cr = ( fmax-(float)r ) / diff;
cg = ( fmax-(float)g ) / diff;
cb = ( fmax-(float)b ) / diff;
if( max == r )
hue = cb - cg;
else if( max == g )
hue = 2. + cr - cb;
else if( max == b )
hue = 4. + cg - cr;
}
hue *= 60.0;
if( hue < 0.0 )
hue += 360.0;
if( hue > 360.0 )
hue -= 360.0;
/* store output values: */
hsi[0] = hue;
hsi[1] = sat;
hsi[2] = intens;
}
/*
* FUNCTION
* ImVfbRoll - roll a VFB
*
* DESCRIPTION
* If no destination VFB is given, a new destination VFB is created.
*
* The source VFB is then copied into the destination VFB, rolling
* its pixels horizontally, vertically, or both.
*/
ImVfb * /* Returns rolled VFB */
#ifdef __STDC__
ImVfbRoll( ImVfb *sourceVfb, int xPixels, int yPixels, ImVfb* dstVfb)
#else
ImVfbRoll( sourceVfb, xPixels, yPixels, dstVfb)
ImVfb *sourceVfb; /* VFB to roll */
int xPixels; /* amount of horizontal pixels to roll */
int yPixels; /* amount of vertical pixels to roll */
ImVfb *dstVfb; /* VFB to overwrite with rolled source */
#endif
{
ImVfb *sVfb; /* VFB to overwrite with rolled source */
int dw, dh; /* column, row indices */
int i,j; /* counters */
int x, y; /* New pixel location */
ImVfbPtr psrc, psrc2; /* Source VFB pixel pointers */
ImVfbPtr pdst, pdst2; /* Destination VFB pixel pointers */
int fieldMask; /* Fields to roll */
int n1, n2; /* # of bytes to copy */
/*
* Check that we've been given acceptable source and destination
* VFBs and valid pixel roll amounts.
*/
if ( sourceVfb == IMVFBNULL )
{
ImErrNo = IMENOVFB;
return ( IMVFBNULL );
}
dw = ImVfbQWidth( sourceVfb );
dh = ImVfbQHeight( sourceVfb );
fieldMask = ImVfbQFields( sourceVfb );
if ( dstVfb != IMVFBNEW )
{
if ( dw != ImVfbQWidth( dstVfb ) )
{
ImErrNo = IMEWIDTH;
return ( IMVFBNULL );
}
if ( dh != ImVfbQHeight( dstVfb ) )
{
ImErrNo = IMEHEIGHT;
return ( IMVFBNULL );
}
if ( fieldMask != ImVfbQFields( dstVfb ) )
{
ImErrNo = IMEFIELD;
return ( IMVFBNULL );
}
}
xPixels %= dw;
yPixels %= dh;
if ( xPixels < 0 )
xPixels += dw;
if ( yPixels < 0 )
yPixels += dh;
/*
* Create a new destination VFB if necessary.
* If the source and destination are the same, create a temporary
* copy of the source before doing the roll.
*/
sVfb = sourceVfb;
if ( dstVfb == IMVFBNEW )
{
if ( (dstVfb = ImVfbAlloc( dw, dh, fieldMask )) == IMVFBNULL )
{
ImErrNo = IMEMALLOC;
return( IMVFBNULL );
}
}
else if ( sourceVfb == dstVfb )
{
if ( (sVfb = ImVfbDup( sourceVfb )) == IMVFBNULL )
return ( IMVFBNULL ); /* ImErrNo already set */
}
/*
* Roll the image by copying pixels from the source to the
* destination. If the source and destination VFB's have the
* same fields, we can speed up the copy by using memcopy().
*/
if ( fieldMask == ImVfbQFields( dstVfb ) )
{
psrc = ImVfbQFirst( sVfb );
psrc2 = ImVfbQPtr( sVfb, (dw - xPixels), 0 );
pdst = ImVfbQPtr( dstVfb, xPixels, yPixels );
pdst2 = ImVfbQPtr( dstVfb, 0, yPixels );
n1 = ImVfbQNBytes( sVfb ) * (dw - xPixels);
n2 = ImVfbQNBytes( sVfb ) * xPixels;
for( i = 0, y = yPixels; i < dh; i++, y++ )
{
if ( y == dh )
{
y = 0;
pdst = ImVfbQPtr( dstVfb, xPixels, 0 );
pdst2 = ImVfbQPtr( dstVfb, 0, 0 );
}
if ( n1 != 0 )
memcpy( (void *)pdst, (void *)psrc, n1 );
if ( n2 != 0 )
memcpy( (void *)pdst2, (void *)psrc2, n2 );
ImVfbSDown( sVfb, psrc );
ImVfbSDown( sVfb, psrc2 );
ImVfbSDown( dstVfb, pdst );
ImVfbSDown( dstVfb, pdst2 );
}
if ( sourceVfb != sVfb )
ImVfbFree( sVfb );
return( dstVfb );
}
psrc = ImVfbQFirst( sVfb );
for ( i = 0, y = yPixels; i < dh; i++, y++ )
{
pdst = ImVfbQPtr( dstVfb, xPixels, y );
if ( y == dh )
{
y = 0;
pdst = ImVfbQPtr( dstVfb, xPixels, 0 );
}
for ( j = 0, x = xPixels; j < dw; j++, x++ )
{
if ( x == dw )
{
x = 0;
pdst = ImVfbQPtr( dstVfb, 0, y );
}
if ( fieldMask & IMVFBMONO )
ImVfbSMono( dstVfb, pdst, ImVfbQMono( sVfb, psrc ) );
if ( fieldMask & IMVFBINDEX8 )
ImVfbSIndex8( dstVfb, pdst, ImVfbQIndex8( sVfb, psrc ) );
if ( fieldMask & IMVFBINDEX16 )
ImVfbSIndex16( dstVfb, pdst, ImVfbQIndex16( sVfb, psrc ) );
if ( fieldMask & IMVFBRGB )
{
ImVfbSRed( dstVfb, pdst, ImVfbQRed( sVfb, psrc ) );
ImVfbSGreen( dstVfb, pdst, ImVfbQGreen( sVfb, psrc ) );
ImVfbSBlue( dstVfb, pdst, ImVfbQBlue( sVfb, psrc ) );
}
if ( fieldMask & IMVFBALPHA )
ImVfbSAlpha( dstVfb, pdst, ImVfbQAlpha( sVfb, psrc ) );
if ( fieldMask & IMVFBIDATA )
ImVfbSIData( dstVfb, pdst, ImVfbQIData( sVfb, psrc ) );
if ( fieldMask & IMVFBFDATA )
ImVfbSFData( dstVfb, pdst, ImVfbQFData( sVfb, psrc ) );
if ( fieldMask & IMVFBZ )
ImVfbSZ( dstVfb, pdst, ImVfbQZ( sVfb, psrc ) );
if ( fieldMask & IMVFBWPROT )
ImVfbSWProt( dstVfb, pdst, ImVfbQWProt( sVfb, psrc ) );
ImVfbSInc( sVfb, psrc );
ImVfbSInc( dstVfb, pdst );
}
}
if ( sourceVfb != sVfb )
ImVfbFree( sVfb );
return ( dstVfb );
}
/*
* FUNCTION
* ImVfbFill - fill a subarea within a virtual frame buffer.
*
* DESCRIPTION
* The source is copied to the destination. The rectangular region
* in the image is scanned and each pixel's fillField filled with a
* new pixel value calculated as a ramp in the 'graduate' direction
* between the fill start and end values.
*
* The majority of the code here is just to check that all the incomming
* arguments make sense!
*/
ImVfb * /* Returns filled destination vfb */
#ifdef __STDC__
ImVfbFill(ImVfb* srcVfb, int srcXLeft, int srcYTop, int srcDx, int srcDy,
int fillField, double fillStart, double fillEnd, int inOut, int graduate, ImVfb* dstVfb )
#else
ImVfbFill( srcVfb, srcXLeft, srcYTop, srcDx, srcDy,
fillField, fillStart, fillEnd, inOut, graduate, dstVfb )
ImVfb *srcVfb; /* Source vfb */
int srcXLeft; /* upper lefthand corner of area */
int srcYTop;
int srcDx; /* Width of area */
int srcDy; /* Height of area */
int fillField; /* Mask for the incoming data */
double fillStart; /* Value to start replacing in fieldmask*/
double fillEnd; /* Value to end replacing in fieldmask */
int inOut; /* whether to fill inside or outside area*/
int graduate; /* which direction to graduate in */
ImVfb *dstVfb; /* Destination vfb */
#endif
{
int i; /* Temp value holder */
int fields; /* Image fields */
int sxl, sxr, syb, syt; /* Fill region */
int x, y; /* fill area width and height */
int w, h; /* Image width and height */
float xInc, yInc; /* X and Y direction grad increments */
/*
* Clamp location and size values to the boundaries of the image.
*/
if ( srcVfb == IMVFBNULL )
{
ImErrNo = IMENOVFB;
return ( IMVFBNULL );
}
w = ImVfbQWidth( srcVfb );
sxl = srcXLeft;
if ( sxl < 0 ) sxl = 0;
if ( sxl >= w ) sxl = w - 1;
sxr = srcXLeft + srcDx - 1;
if ( sxr < 0 ) sxr = 0;
if ( sxr >= w ) sxr = w - 1;
h = ImVfbQHeight( srcVfb );
syt = srcYTop;
if ( syt < 0 ) syt = 0;
if ( syt >= h ) syt = h - 1;
syb = srcYTop + srcDy - 1;
if ( syb < 0 ) syb = 0;
if ( syb >= h ) syb = h - 1;
/*
* Swap left & right, top & bottom, if necessary.
*/
if ( sxl > sxr )
{
i = sxl; sxl = sxr; sxr = i;
}
if ( syt > syb )
{
i = syb; syb = syt; syt = i;
}
/*
* Confirm widths are legal.
*/
x = sxr - sxl + 1;
if ( x <= 0 )
{
ImErrNo = IMEWIDTH;
return( IMVFBNULL );
}
y = syb - syt + 1;
if ( y <= 0 )
{
ImErrNo = IMEHEIGHT;
return( IMVFBNULL );
}
/*
* Figure out what fields we require be in the source & destination
* and make sure they are there.
*/
fields = 0;
if ( fillField & (IMRED | IMGREEN | IMBLUE | IMHUE | IMSATURATION | IMINTENSITY) )
fields |= IMVFBRGB;
if ( fillField & IMMONO )
fields |= IMVFBMONO;
if ( fillField & IMINDEX8 )
fields |= IMVFBINDEX8;
if ( fillField & IMINDEX16 )
fields |= IMVFBINDEX16;
if ( fillField & IMALPHA )
fields |= IMVFBALPHA;
if ( fillField & IMWPROT )
fields |= IMVFBWPROT;
if ( fillField & IMZ )
fields |= IMVFBZ;
if ( fillField & IMIDATA )
fields |= IMVFBIDATA;
if ( fillField & IMFDATA )
fields |= IMVFBFDATA;
if ( (fields & ImVfbQFields( srcVfb )) != fields )
{
ImErrNo = IMEFIELD;
return ( IMVFBNULL );
}
/*
* Make sure the fill range is good.
*/
switch ( fillField )
{
case IMMONO:
if ( fillStart < 0.0 ) fillStart = 0.0;
else if ( fillStart > 1.0 ) fillStart = 1.0;
if ( fillEnd < 0.0 ) fillEnd = 0.0;
else if ( fillEnd > 1.0 ) fillEnd = 1.0;
break;
case IMRED:
case IMGREEN:
case IMBLUE:
case IMALPHA:
case IMINDEX8:
case IMWPROT:
if ( fillStart < 0.0 ) fillStart = 0.0;
else if ( fillStart > 255.0 ) fillStart = 255.0;
if ( fillEnd < 0.0 ) fillEnd = 0.0;
else if ( fillEnd > 255.0 ) fillEnd = 255.0;
break;
case IMINDEX16:
if ( fillStart < 0.0 ) fillStart = 0.0;
else if ( fillStart > 65535.0 ) fillStart = 65535.0;
if ( fillEnd < 0.0 ) fillEnd = 0.0;
else if ( fillEnd > 65535.0 ) fillEnd = 65535.0;
break;
case IMHUE:
if ( fillStart < 0.0 ) fillStart = 0.0;
else if ( fillStart > 360.0 ) fillStart = 360.0;
if ( fillEnd < 0.0 ) fillEnd = 0.0;
else if ( fillEnd > 360.0 ) fillEnd = 360.0;
break;
case IMSATURATION:
case IMINTENSITY:
if ( fillStart < 0.0 ) fillStart = 0.0;
else if ( fillStart > 1.0 ) fillStart = 1.0;
if ( fillEnd < 0.0 ) fillEnd = 0.0;
else if ( fillEnd > 1.0 ) fillEnd = 1.0;
break;
case IMZ:
if ( fillStart < 0.0 ) fillStart = 0.0;
if ( fillEnd < 0.0 ) fillEnd = 0.0;
break;
case IMIDATA:
case IMFDATA:
/* All values allowed. */
break;
default:
ImErrNo = IMEFIELD;
return ( IMVFBNULL );
}
/*
* Determine the pixel-to-pixel value increment. Could be negative.
*
* The increment is computed as follows:
* If the first pixel is color s, and the last is color e,
* and there are n pixels, and the increment is i, then
* we have s + (n-1)i = e. Or i = (e-s)/(n-1).
*/
switch ( graduate )
{
case IMGRADHORIZ: /* Horizontal graduation. */
yInc = 0.0;
xInc = fillEnd - fillStart;
switch ( inOut )
{
case IMVFBINSIDE: if (x!=1) xInc /= (x-1); break;
case IMVFBOUTSIDE: if (w!=1) xInc /= (w-1); break;
default:
ImErrNo = IMEBADINOUT;
return ( IMVFBNULL );
}
break;
case IMGRADVERT: /* Vertical graduation. */
xInc = 0.0;
yInc = fillEnd - fillStart;
switch ( inOut )
{
case IMVFBINSIDE: if (y!=1) yInc /= (y-1); break;
case IMVFBOUTSIDE: if (h!=1) yInc /= (h-1); break;
default:
ImErrNo = IMEBADINOUT;
return ( IMVFBNULL );
}
break;
case IMGRADNONE: /* No graduation. */
xInc = yInc = 0.0;
switch ( inOut )
{
case IMVFBINSIDE:
case IMVFBOUTSIDE:
break;
default:
ImErrNo = IMEBADINOUT;
return ( IMVFBNULL );
}
break;
default:
ImErrNo = IMEGRADUATION;
return( IMVFBNULL );
}
/*
* Make a destination VFB, if needed.
*/
if ( srcVfb != dstVfb )
{
dstVfb = ImVfbCopy( srcVfb, 0, 0, w, h, IMVFBALL, dstVfb,0,0);
if ( dstVfb == IMVFBNULL )
return ( IMVFBNULL ); /* ImErrNo already set */
}
/*
* Fill the image.
*/
if ( inOut == IMVFBINSIDE )
{
imVfbFillRect( dstVfb, sxl, sxr, syt, syb,
xInc, yInc, fillStart, fillField );
}
else
{
/*
* Fill 4 rectangles on the 4 sides of the area to be left
* unfilled.
*/
switch ( graduate )
{
case IMGRADHORIZ:
imVfbFillRect( dstVfb, 0, w-1, 0, syt,
xInc, yInc, fillStart, fillField );
imVfbFillRect( dstVfb, 0, sxl, syt, syb,
xInc, yInc, fillStart, fillField );
imVfbFillRect( dstVfb, 0, w-1, syb, h-1,
xInc, yInc, fillStart, fillField );
imVfbFillRect( dstVfb, sxr, w-1, syt, syb,
xInc, yInc, fillStart + sxr*xInc, fillField );
break;
case IMGRADVERT:
imVfbFillRect( dstVfb, 0, sxl, 0, h-1,
xInc, yInc, fillStart, fillField );
imVfbFillRect( dstVfb, sxl, sxr, 0, syt,
xInc, yInc, fillStart, fillField );
imVfbFillRect( dstVfb, sxr, w-1, 0, h-1,
xInc, yInc, fillStart, fillField );
imVfbFillRect( dstVfb, sxl, sxr, syb, h-1,
xInc, yInc, fillStart + syb*yInc, fillField );
break;
case IMGRADNONE:
imVfbFillRect( dstVfb, 0, w-1, 0, syt,
xInc, yInc, fillStart, fillField );
imVfbFillRect( dstVfb, 0, sxl, syt, syb,
xInc, yInc, fillStart, fillField );
imVfbFillRect( dstVfb, 0, w-1, syb, h-1,
xInc, yInc, fillStart, fillField );
imVfbFillRect( dstVfb, sxr, w-1, syt, syb,
xInc, yInc, fillStart, fillField );
break;
}
}
return ( dstVfb );
}
/*
* FUNCTION
* imVfbFillRect - fill a rectangle in a source image
*
* DESCRIPTION
* The rectangular region is looped through and each pixel's fillField
* changed to a fill value calculated based on a starting value and
* X and Y direction increments.
*/
static void /* Returns nothing */
#ifdef __STDC__
imVfbFillRect( ImVfb* dstVfb, int sxl, int sxr, int syt, int syb, double xInc, double yInc, double fillStart, int fillField )
#else
imVfbFillRect( dstVfb, sxl, sxr, syt, syb, xInc, yInc, fillStart, fillField )
ImVfb *dstVfb; /* Destination VFB */
int sxl, sxr, syt, syb; /* Rectangle to fill */
double xInc, yInc; /* Directional pixel increments */
double fillStart; /* Starting fill value */
int fillField; /* Field of VFB to fill */
#endif
{
ImVfbPtr pDst; /* VFB pixel pointer */
int i,j; /* counters */
float pixel; /* New pixel value */
float hsi[3]; /* HSI pixel value */
int rgb[3]; /* RGB pixel value */
for ( i = syt; i <= syb; i++ )
{
pDst = ImVfbQPtr( dstVfb, sxl, i );
pixel = fillStart + (i-syt) * yInc;
switch ( fillField )
{
case IMRED:
for ( j = sxl; j <= sxr; j++ )
{
ImVfbSRed( dstVfb, pDst, (int)pixel );
ImVfbSInc( dstVfb, pDst );
pixel += xInc;
}
break;
case IMGREEN:
for ( j = sxl; j <= sxr; j++ )
{
ImVfbSGreen( dstVfb, pDst, (int)pixel );
ImVfbSInc( dstVfb, pDst );
pixel += xInc;
}
break;
case IMBLUE:
for ( j = sxl; j <= sxr; j++ )
{
ImVfbSBlue( dstVfb, pDst, (int)pixel );
ImVfbSInc( dstVfb, pDst );
pixel += xInc;
}
break;
case IMINDEX8:
for ( j = sxl; j <= sxr; j++ )
{
ImVfbSIndex8( dstVfb, pDst, (int)pixel );
ImVfbSInc( dstVfb, pDst );
pixel += xInc;
}
break;
case IMINDEX16:
for ( j = sxl; j <= sxr; j++ )
{
ImVfbSIndex16( dstVfb, pDst, (int)pixel );
ImVfbSInc( dstVfb, pDst );
pixel += xInc;
}
break;
case IMMONO:
for ( j = sxl; j <= sxr; j++ )
{
ImVfbSMono( dstVfb, pDst, (int)pixel );
ImVfbSInc( dstVfb, pDst );
pixel += xInc;
}
break;
case IMHUE:
case IMSATURATION:
case IMINTENSITY:
for ( j = sxl; j <= sxr; j++ )
{
rgb[0] = ImVfbQRed( dstVfb, pDst );
rgb[1] = ImVfbQGreen( dstVfb, pDst );
rgb[2] = ImVfbQBlue( dstVfb, pDst );
ImRgbToHsi( rgb, hsi );
switch ( fillField )
{
case IMHUE: hsi[0] = pixel; break;
case IMSATURATION: hsi[1] = pixel; break;
case IMINTENSITY: hsi[2] = pixel; break;
}
ImHsiToRgb( hsi, rgb );
ImVfbSRed( dstVfb, pDst, rgb[0] );
ImVfbSGreen( dstVfb, pDst, rgb[1] );
ImVfbSBlue( dstVfb, pDst, rgb[2] );
ImVfbSInc( dstVfb, pDst );
pixel += xInc;
}
break;
case IMALPHA:
for ( j = sxl; j <= sxr; j++ )
{
ImVfbSAlpha( dstVfb, pDst, (int)pixel );
ImVfbSInc( dstVfb, pDst );
pixel += xInc;
}
break;
case IMWPROT:
for ( j = sxl; j <= sxr; j++ )
{
ImVfbSWProt( dstVfb, pDst, (int)pixel );
ImVfbSInc( dstVfb, pDst );
pixel += xInc;
}
break;
case IMZ:
for ( j = sxl; j <= sxr; j++ )
{
ImVfbSZ( dstVfb, pDst, (int)pixel );
ImVfbSInc( dstVfb, pDst );
pixel += xInc;
}
break;
case IMFDATA:
for ( j = sxl; j <= sxr; j++ )
{
ImVfbSFData( dstVfb, pDst, pixel );
ImVfbSInc( dstVfb, pDst );
pixel += xInc;
}
break;
case IMIDATA:
for ( j = sxl; j <= sxr; j++ )
{
ImVfbSIData( dstVfb, pDst, (int)pixel );
ImVfbSInc( dstVfb, pDst );
pixel += xInc;
}
break;
}
}
}
/*
* FUNCTION
* ImVfbPrint
*
* DESCRIPTION
* Print the pixels of a vfb, as floats or integers, as
* specified by the 'format' parameter. (This should be
* IMVFBPRINTFLOAT or IMVFBPRINTINT)
*
*/
void /* returns nothing */
#ifdef __STDC__
ImVfbPrint(FILE* fp, int format, ImVfb* vfb)
#else
ImVfbPrint(fp, format, vfb)
FILE* fp; /* where to direct the output */
int format; /* the format of the numbers */
ImVfb* vfb; /* the vfb */
#endif
{
int fields; /* The fields in the vfb. */
int i; /* loop index */
ImVfbPtr vfbptr; /* Points into the vfb */
/* Determine the fields in the vfb. */
fields = 0;
fields = ImVfbQFields(vfb);
vfbptr = ImVfbQPtr(vfb, 0, 0);
for (i=0; i < ImVfbQWidth(vfb) * ImVfbQHeight(vfb); i++)
{
/* Print this pixel */
if (format & IMVFBPRINTFLOAT)
{
if (fields & IMVFBRGB)
{
fprintf( fp, "%f %f %f ",
(float)(ImVfbQRed ( vfb, vfbptr )) / 255.0,
(float)(ImVfbQGreen( vfb, vfbptr )) / 255.0,
(float)(ImVfbQBlue ( vfb, vfbptr )) / 255.0 );
}
if (fields & IMVFBALPHA)
{
fprintf( fp, "%f ",
(float)(ImVfbQAlpha (vfb, vfbptr )) / 255.0 );
}
if (fields & IMVFBINDEX8)
{
fprintf( fp, "%f ",
(float)(ImVfbQIndex( vfb, vfbptr )) / 255.0 );
}
if (fields & IMVFBINDEX16)
{
fprintf( fp, "%f ",
(float)(ImVfbQIndex16( vfb, vfbptr )) / 65535.0 );
}
fprintf( fp, " ");
}
if (format & IMVFBPRINTINT)
{
if (fields & IMVFBRGB)
{
fprintf( fp, "%d %d %d ",
ImVfbQRed ( vfb, vfbptr ),
ImVfbQGreen( vfb, vfbptr ),
ImVfbQBlue ( vfb, vfbptr ));
}
if (fields & IMVFBALPHA)
{
fprintf( fp, "%d ",
ImVfbQAlpha (vfb, vfbptr ) );
}
if (fields & IMVFBINDEX8)
{
fprintf( fp, "%d ",
ImVfbQIndex( vfb, vfbptr ) );
}
if (fields & IMVFBINDEX16)
{
fprintf( fp, "%ld ",
ImVfbQIndex16( vfb, vfbptr ) );
}
}
fprintf(fp,"\n");
vfbptr = ImVfbQNext(vfb, vfbptr);
} /* End of pixel loop */
}
/*
* FUNCTION
* ImGetTransparency
*
* DESCRIPTION
* The transparency value of an image is an index in the color
* lookup table. Pixels with this index are deemed transparent.
* While RGB images use alpha channels for transparency, indexed
* images sometimes use transparency values for transparency.
*
* This routine looks in the flags table for a request,
* then looks in the tagTable for a value, and returns the
* transparency value of the image based on these two checks.
*
* The vfb passed to this routine must be of type INDEX8
* If there is a transparency value in the tagTable, or a
* request in the flagsTable, this routine figures out that
* value, and returns it.
*
* An "image transparency request" in the flags table may have one
* of the following values:
*
* "most common" <- means we choose the most common value in the image
* "index=nn" <- means pixels with nn should be transparent
* "rgb=rr gg bb" <- means pixels with rr gg bb should be tranparent
*
* If there is no transparency request in either table, we return -1.
*
*/
int /* returns an index value or -1 */
#ifdef __STDC__
ImGetTransparency(TagTable* tagTable, TagTable* flagsTable, ImVfb* vfb)
#else
ImGetTransparency(tagTable, flagsTable, vfb)
TagTable* tagTable;
TagTable* flagsTable;
ImVfb* vfb;
#endif
{
TagEntry* tagEntry; /* entry */
char* request; /* the request */
int transInt; /* transparency value as an integer */
int redInt=-1,
greenInt=0, blueInt=0; /* rgb requested values */
ImClt* clt; /* image clt */
ImCltPtr cltPtr; /* points into the clt */
ImHistTable* histogram=NULL; /* a histogram */
long int largestWeight; /* biggest weight */
long int thisWeight; /* one weight */
int field; /* mono or index8 */
char message[200]; /* message buffer */
int transColor=-1; /* The value to return */
int numPixels; /* # of pix w/ this index value */
int i;
/*
* First look for a request in the flags table
*/
if (flagsTable!=TAGTABLENULL)
tagEntry = TagTableQDirect(flagsTable, "image transparency request", 0);
else
tagEntry=TAGENTRYNULL;
/*
* then check the tagTable
*/
if (tagEntry==TAGENTRYNULL)
{
tagEntry = TagTableQDirect(tagTable, "transparency value", 0);
}
if (tagEntry==TAGENTRYNULL)
{ /* No transparency! */
return -1;
}
/*
* There is transparency.
* What should be do with it?
*/
TagEntryQValue( tagEntry, &request);
/*
* The request can be one of the following:
* "most common" <- means we choose the most common value in the image
* "index=nn" <- means pixels with nn should be transparent
* "rgb=rr gg bb" <- means pixels with rr gg bb should be tranparent
*/
if (strncmp(request,"index",5)==0)
{
sscanf(request,"index=%d",&transInt);
transColor = (unsigned char)transInt;
}
else if (strncmp(request,"rgb",3)==0)
{
/* Find the first entry with this rgb value */
sscanf(request,"rgb=%d %d %d",&redInt, &greenInt, &blueInt);
clt = ImVfbQClt(vfb);
transInt = -1;
cltPtr = ImCltQFirst(clt);
for (i=0; i< ImCltQNColors(clt); i++)
{
if ( (redInt == ImCltQRed(cltPtr)) &&
(greenInt==ImCltQGreen(cltPtr)) &&
(blueInt ==ImCltQBlue (cltPtr)))
{
transInt = i;
i = ImCltQNColors(clt)+1;
}
cltPtr = ImCltQNext (clt, cltPtr );
}
if (transInt==-1)
{
sprintf(message,"Couldn't find any %d, %d, %d pixels in the image!",
redInt, greenInt, blueInt);
ImErrorWarning(message, IMEVALOUTOFRANGE, -1);
return 1;
}
transColor = (unsigned char) transInt;
}
else if (strcmp(request,"most common")==0)
{
if (ImVfbQFields(vfb) & IMVFBINDEX8)
field = IMINDEX8;
else
field = IMMONO;
histogram = ImVfbHist( vfb, field, 0 );
/*
* Step through the histogram. Get the most frequent color.
*/
largestWeight = (long) 0;
transColor = 1;
for (i=0; i< histogram->imhist_nEntries; i++)
{
numPixels = histogram->imhist_nOccur[i];
thisWeight = numPixels;
if (thisWeight > largestWeight)
{
largestWeight = thisWeight;
if (field==IMINDEX8)
transColor = histogram->imhist_index8[i];
else /* mono */
transColor = histogram->imhist_mono[i];
}
}
ImVfbHistTableFree(histogram);
}
else
{
sprintf(message,"Unknown transparency request: '%s'",
request);
ImErrorWarning(message, IMEVALOUTOFRANGE, -1);
return -1;
}
return transColor;
}