2266 lines
55 KiB
C
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;
|
|
}
|
|
|
|
|
|
|