/* $XConsortium: mpcomp.c,v 1.4 94/04/17 20:35:14 rws Exp $ */
/**** module mpcomp.c ****/
/******************************************************************************

Copyright (c) 1993, 1994  X Consortium

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Except as contained in this notice, the name of the X Consortium shall not be
used in advertising or otherwise to promote the sale, use or other dealings
in this Software without prior written authorization from the X Consortium.


				NOTICE
                              
This software is being provided by AGE Logic, Inc. under the
following license.  By obtaining, using and/or copying this software,
you agree that you have read, understood, and will comply with these
terms and conditions:

     Permission to use, copy, modify, distribute and sell this
     software and its documentation for any purpose and without
     fee or royalty and to grant others any or all rights granted
     herein is hereby granted, provided that you agree to comply
     with the following copyright notice and statements, including
     the disclaimer, and that the same appears on all copies and
     derivative works of the software and documentation you make.
     
     "Copyright 1993, 1994 by AGE Logic, Inc."
     
     THIS SOFTWARE IS PROVIDED "AS IS".  AGE LOGIC MAKES NO
     REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED.  By way of
     example, but not limitation, AGE LOGIC MAKE NO
     REPRESENTATIONS OR WARRANTIES OF MERCHANTABILITY OR FITNESS
     FOR ANY PARTICULAR PURPOSE OR THAT THE SOFTWARE DOES NOT
     INFRINGE THIRD-PARTY PROPRIETARY RIGHTS.  AGE LOGIC 
     SHALL BEAR NO LIABILITY FOR ANY USE OF THIS SOFTWARE.  IN NO
     EVENT SHALL EITHER PARTY BE LIABLE FOR ANY INDIRECT,
     INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOSS
     OF PROFITS, REVENUE, DATA OR USE, INCURRED BY EITHER PARTY OR
     ANY THIRD PARTY, WHETHER IN AN ACTION IN CONTRACT OR TORT OR
     BASED ON A WARRANTY, EVEN IF AGE LOGIC LICENSEES
     HEREUNDER HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH
     DAMAGES.
    
     The name of AGE Logic, Inc. may not be used in
     advertising or publicity pertaining to this software without
     specific, written prior permission from AGE Logic.

     Title to this software shall at all times remain with AGE
     Logic, Inc.
*****************************************************************************
  
	mpcomp.c -- DDXIE compare element
  
	Larry Hare -- AGE Logic, Inc. August, 1993
  
*****************************************************************************/


#define _XIEC_MPCOMP
#define _XIEC_PCOMP

/*
 *  Include files
 */
#include <stdio.h>

/*
 *  Core X Includes
 */
#include <X.h>
#include <Xproto.h>
/*
 *  XIE Includes
 */
#include <XIE.h>
#include <XIEproto.h>
/*
 *  more X server includes.
 */
#include <misc.h>
#include <dixstruct.h>
/*
 *  Server XIE Includes
 */
#include <error.h>
#include <macro.h>
#include <element.h>
#include <texstr.h>
#include <xiemd.h>

/*
 *  routines referenced by other DDXIE modules
 */
int	miAnalyzeCompare();

/*
**  Turn on NON_ROI to get non ROI based versions.  They don't really go
**  faster and cost about 20Kbytes of object code space.
*/

/*
 *  routines used internal to this module
 */
static int CreateCompare();
static int InitializeCompare();
static int ResetCompare();
static int DestroyCompare();

#if defined(NON_ROI)
static int ActivateCompareM();
static int ActivateCompareD();
#endif
static int ActivateCompareMROI();
static int ActivateCompareDROI();
static int ActivateCompareTripleM();
static int ActivateCompareTripleD();

/*
 * DDXIE Compare entry points
 */
static ddElemVecRec CompareVec = {
  CreateCompare,
  InitializeCompare,
  ActivateCompareMROI,
  (xieBoolProc)NULL,
  ResetCompare,
  DestroyCompare
  };

/*
* Local Declarations.
*/

typedef struct _mpcomparedef {
    CARD32	iconst;			/* first, in case of .asm code */
    RealPixel	fconst;			/* second, in case of .asm code */
    void	(*action) ();
    CARD32	width;
    BOOL	final;
#if defined(NON_ROI)
    void	(*action2) ();
    CARD32	endrun;
    CARD32	endix;
#endif
} mpComparePvtRec, *mpComparePvtPtr;

/*
** NOTE:  Might change constants to use dyads with prefilled constant strip
**	  to conserve code space at some small execution time expense.
** NOTE:  The ROI variants use three loops, the first to get in sync with
**	  32 bits, and the last to finish up partial words.  A more space
**	  efficient version would have one loop which would check for M
**	  wrapping in which case the old word would be written.
**	  It also requires loads of intermediate destination words which
**	  will be completely overwritten.
** NOTE:  Might do NE/GT/GE as a second pass inversion of EQ/LE/LT to
**	  save even more space at cost of another time penalty.  This 
**	  inversion would have to be applied to active ROI entries only.
** NOTE:  On some machine architectures, it may be possible to write
**	  assembly or asm() code which does a compare and then extracts
**	  some 1 bit from a condition code register.  This would reduce
**	  the multiplication of code by 6 (or 3).  Heck you could even
**	  generate assembly code yourself automagically ...
** NOTE:  Triple Compare assumes all src1 bands same height/width.
** NOTE:  Triple Compare assumes all src2 bands same height/width.
** NOTE:  Triple Compare with band_mask of 0 sets output to 1 (for
**	  equal) or 0 (for not equal) or 0 (outside ROI).  This sortof
**	  makes sense since all the selected bands were equal :-)
*/

/*------------------------------------------------------------------------
------------------------  fill in the vector  ---------------------------
------------------------------------------------------------------------*/
int miAnalyzeCompare(flo,ped)
    floDefPtr flo;
    peDefPtr  ped;
{
    ped->ddVec = CompareVec;
    return TRUE;
}

/*------------------------------------------------------------------------
---------------------------- create peTex . . . --------------------------
------------------------------------------------------------------------*/
static int CreateCompare(flo,ped)
    floDefPtr flo;
    peDefPtr  ped;
{
    /* always force syncing between inputs (is nop if only one input) */
    return MakePETex(flo,ped,
		     xieValMaxBands * sizeof(mpComparePvtRec),
		     SYNC,	/* InSync: Make sure ROI exists first */
		     NO_SYNC	/* bandSync: see InitializeCompare */
		     );
} 

/*------------------------------------------------------------------------
----------------------------- crank some data ----------------------------
------------------------------------------------------------------------*/

#if defined(NON_ROI)
static int ActivateCompareM(flo,ped,pet)
     floDefPtr flo;
     peDefPtr  ped;
     peTexPtr  pet;
{
    mpComparePvtPtr pvt = (mpComparePvtPtr) pet->private;
    int band, nbands = pet->receptor[SRCt1].inFlo->bands;
    bandPtr sband = &(pet->receptor[SRCt1].band[0]);
    bandPtr dband = &(pet->emitter[0]);

    for(band = 0; band < nbands; band++, pvt++, sband++, dband++) {
	CARD32 npix = pvt->width;
	LogInt *svoid, *dvoid;

    	if (!(svoid = GetCurrentSrc(flo,pet,sband)) ||
	    !(dvoid = GetCurrentDst(flo,pet,dband))) continue;

	do {
	    /* NOTE: could pass in replicated constant strip here */
	    (*(pvt->action)) (dvoid, svoid, pvt, npix);
	    svoid = GetNextSrc(flo,pet,sband,FLUSH);
	    dvoid = GetNextDst(flo,pet,dband,FLUSH);
	} while (!ferrCode(flo) && svoid && dvoid) ;

	FreeData(flo, pet, sband, sband->current);
    }
    return TRUE;
}
#endif /* NON_ROI */

#if defined(NON_ROI)
static int ActivateCompareD(flo,ped,pet)
     floDefPtr flo;
     peDefPtr  ped;
     peTexPtr  pet;
{
    mpComparePvtPtr pvt = (mpComparePvtPtr) pet->private;
    int band, nbands = pet->receptor[SRCt1].inFlo->bands;
    bandPtr sband = &(pet->receptor[SRCt1].band[0]);
    bandPtr tband = &(pet->receptor[SRCt2].band[0]);
    bandPtr dband = &(pet->emitter[0]);

    for(band = 0; band < nbands; band++, pvt++, sband++, tband++, dband++) {
	LogInt *svoid, *tvoid, *dvoid;

    	if (!(svoid = GetCurrentSrc(flo,pet,sband)) ||
	    !(tvoid = GetCurrentSrc(flo,pet,tband)) ||
	    !(dvoid = GetCurrentDst(flo,pet,dband))   ) {
	    if (sband->final && tband->final) {
		/* Generate constant fill of 0 for remainder of image */
		while ((dband->current < dband->format->height) &&
	    	       (dvoid = GetCurrentDst(flo,pet,dband))) {
			action_clear(dvoid,dband->format->pitch,0);
			if (PutData(flo,pet,dband,dband->current+1))
			    break;
		}
	    }
	    continue;
	}

	do {
	    (*(pvt->action)) (dvoid, svoid, tvoid, pvt->endix);
	    if (pvt->action2)
		(*(pvt->action2)) (dvoid, pvt->endrun, pvt->endix);
	    svoid = GetNextSrc(flo,pet,sband,FLUSH);
	    tvoid = GetNextSrc(flo,pet,tband,FLUSH);
	    dvoid = GetNextDst(flo,pet,dband,FLUSH);
	} while (!ferrCode(flo) && svoid && tvoid && dvoid) ;

	if(!svoid && sband->final) {	/* when sr1 runs out, kill sr2 too  */
	    DisableSrc(flo,pet,tband,FLUSH);
	    pvt->final = TRUE; /* generate constant fill on future activates */
	} else if(!tvoid && tband->final) {/* when sr2 runs out, clear rest */
	    DisableSrc(flo,pet,sband,FLUSH);
	    pvt->final = TRUE; /* generate constant fill on future activates */
	} else { /* both inputs still active, keep the scheduler up to date  */
	    FreeData(flo,pet,sband,sband->current);
	    FreeData(flo,pet,tband,tband->current);
	}
    }
    return TRUE;
}
#endif /* NON_ROI */

static int ActivateCompareMROI(flo,ped,pet)
     floDefPtr flo;
     peDefPtr  ped;
     peTexPtr  pet;
{
    mpComparePvtPtr pvt = (mpComparePvtPtr) pet->private;
    int band, nbands  = pet->receptor[SRCt1].inFlo->bands;
    bandPtr sband     = &(pet->receptor[SRCt1].band[0]);
    bandPtr dband     = &(pet->emitter[0]);

    for(band = 0; band < nbands; band++, pvt++, sband++, dband++) {
	pointer svoid, dvoid;

    	if (!(svoid = GetCurrentSrc(flo,pet,sband)) ||
	    !(dvoid = GetCurrentDst(flo,pet,dband))) continue;

	while (!ferrCode(flo) && svoid && dvoid && 
				SyncDomain(flo,ped,dband,FLUSH)) {
	    INT32 run, ix = 0;
	   
	    /* bzero better for messy control planes */
	    /* bzero((char *)dvoid, dband->pitch); */
	    while (run = GetRun(flo,pet,dband)) {
		if (run > 0) {
	    	    /* NOTE: could pass in replicated constant strip here */
	    	    (*(pvt->action)) (dvoid, svoid, pvt, run, ix);
		    ix += run;
		} else {
		    /* action_clear better for non ROI or simple ROIs */
		    action_clear(dvoid, -run, ix);
		    ix -= run;
		}
	    }
	    svoid = GetNextSrc(flo,pet,sband,FLUSH);
	    dvoid = GetNextDst(flo,pet,dband,FLUSH);
	}

	FreeData(flo, pet, sband, sband->current);
    }
    return TRUE;
}

static int ActivateCompareDROI(flo,ped,pet)
     floDefPtr flo;
     peDefPtr  ped;
     peTexPtr  pet;
{
    mpComparePvtPtr pvt = (mpComparePvtPtr) pet->private;
    int band, nbands  = pet->receptor[SRCt1].inFlo->bands;
    bandPtr sband     = &(pet->receptor[SRCt1].band[0]);
    bandPtr tband     = &(pet->receptor[SRCt2].band[0]);
    bandPtr dband     = &(pet->emitter[0]);

    for(band = 0; band < nbands; band++, pvt++, sband++, tband++, dband++) {
	pointer svoid, tvoid, dvoid;
	CARD32 w = pvt->width;

    	if (!(svoid = GetCurrentSrc(flo,pet,sband)) ||
    	    !(tvoid = GetCurrentSrc(flo,pet,tband)) ||
	    !(dvoid = GetCurrentDst(flo,pet,dband))) {
	    if (sband->final && tband->final) {
		/* Generate constant fill of 0 for remainder of image */
		while ((dband->current < dband->format->height) &&
	    	       (dvoid = GetCurrentDst(flo,pet,dband))) {
			action_clear(dvoid,dband->format->pitch,0);
			if (PutData(flo,pet,dband,dband->current+1))
			    break;
		}
	    }
	    continue;
	}

	while (!ferrCode(flo) && svoid && tvoid && dvoid && 
				SyncDomain(flo,ped,dband,FLUSH)) {
	    INT32 run, ix = 0;
	   
	    /* bzero better for messy control planes */
	    /* bzero((char *)dvoid, dband->pitch); */
	    while (run = GetRun(flo,pet,dband)) {
		if (run > 0) {
		    /* needs to clip to second source, yuck */
		    if ((ix + run) > w) {
			if (ix < w) {
			    (*(pvt->action)) (dvoid, svoid, tvoid, w - ix, ix);
			    ix = w;
			}
		        action_clear(dvoid, dband->format->width - ix, ix);
			break;
		    }
	    	    (*(pvt->action)) (dvoid, svoid, tvoid, run, ix);
		    ix += run;
		} else {
		    /* action_clear better for non ROI or simple ROIs */
		    action_clear(dvoid, -run, ix);
		    ix -= run; 
		}
	    }
	    svoid = GetNextSrc(flo,pet,sband,FLUSH);
	    tvoid = GetNextSrc(flo,pet,tband,FLUSH);
	    dvoid = GetNextDst(flo,pet,dband,FLUSH);
	}

	if(!svoid && sband->final) {
	    /* when sr1 runs out, kill sr2 too. should be done */
	    DisableSrc(flo,pet,tband,FLUSH);
	    pvt->final = TRUE;
	} else if(!tvoid && tband->final) {
	    /* when sr2 runs out, kill off sr1 also, and clear remaining dest */
	    DisableSrc(flo,pet,sband,FLUSH);
	    pvt->final = TRUE;
	} else {
	    /* both inputs still active, keep the scheduler up to date  */
	    FreeData(flo,pet,sband,sband->current);
	    FreeData(flo,pet,tband,tband->current);
	}
    }
    return TRUE;
}

static int ActivateCompareTripleM(flo,ped,pet)
     floDefPtr flo;
     peDefPtr  ped;
     peTexPtr  pet;
{
    mpComparePvtPtr pvt = (mpComparePvtPtr) pet->private;
    bandPtr	 sband = &(pet->receptor[SRCt1].band[0]);
    bandPtr	 dband = &(pet->emitter[0]);
    CARD8 	   msk = ((xieFloCompare *) ped->elemRaw)->bandMask;
    BOOL	 equal = ((xieFloCompare *) ped->elemRaw)->operator == xieValEQ;
    register pointer s0 = (pointer ) 1;
    register pointer s1 = (pointer ) 1;
    register pointer s2 = (pointer ) 1;
    register pointer dvoid;

    if ((msk & 1) && !(s0 = GetCurrentSrc(flo,pet,sband)))
	goto done; sband++;
    if ((msk & 2) && !(s1 = GetCurrentSrc(flo,pet,sband)))
	goto done; sband++;
    if ((msk & 4) && !(s2 = GetCurrentSrc(flo,pet,sband)))
	goto done; sband -= 2;
    if(!(dvoid = GetCurrentDst(flo,pet,dband)))
	goto done;

    /*
    **  An alternative algorithm might use while(GetRun) loop to
    **  set or clear the destination bits in the line; and then
    **  use SIMPLER action routines which scanned the entire line
    **  and only operate on 1 pixels; optionally followed by
    **  a while(GetRun) to invert the active bits for NE.
    */
    pvt += 2;
    while (!ferrCode(flo) && s0 && s1 && s2 && dvoid && 
			SyncDomain(flo,ped,dband,FLUSH)) {
	register INT32 run, ix = 0;

	while (run = GetRun(flo,pet,dband)) {
	    if (run > 0) {
		action_set(dvoid, run, ix);
		pvt -= 2; if (msk & 1)
			(*pvt->action) (dvoid, s0, pvt, run, ix);
		pvt++; if (msk & 2)
			(*pvt->action) (dvoid, s1, pvt, run, ix);
		pvt++; if (msk & 4)
			(*pvt->action) (dvoid, s2, pvt, run, ix);
		if (!equal)
			action_invert(dvoid, run, ix);
		ix += run;
	    } else {
		action_clear(dvoid, -run, ix);
		ix -= run;
	    }
	}

	if (msk & 1) s0 = GetNextSrc(flo,pet,sband,FLUSH); sband++;
	if (msk & 2) s1 = GetNextSrc(flo,pet,sband,FLUSH); sband++;
	if (msk & 4) s2 = GetNextSrc(flo,pet,sband,FLUSH); sband -= 2;
	dvoid = GetNextDst(flo,pet,dband,FLUSH);
    }

    if (msk & 1) FreeData(flo,pet,sband,sband->current); sband++;
    if (msk & 2) FreeData(flo,pet,sband,sband->current); sband++;
    if (msk & 4) FreeData(flo,pet,sband,sband->current); sband -= 2;
done:
    return TRUE;
}

static int ActivateCompareTripleD(flo,ped,pet)
     floDefPtr flo;
     peDefPtr  ped;
     peTexPtr  pet;
{
    mpComparePvtPtr pvt = (mpComparePvtPtr) pet->private;
    bandPtr      sband = &(pet->receptor[SRCt1].band[0]);
    bandPtr      tband = &(pet->receptor[SRCt2].band[0]);
    bandPtr      dband = &(pet->emitter[0]);
    CARD8	   msk = ((xieFloCompare *) ped->elemRaw)->bandMask;
    BOOL  	 equal = ((xieFloCompare *) ped->elemRaw)->operator == xieValEQ;
    CARD32 	     w = pvt->width;
    register pointer s0 = (pointer ) 1;
    register pointer s1 = (pointer ) 1;
    register pointer s2 = (pointer ) 1;
    register pointer t0 = (pointer ) 1;
    register pointer t1 = (pointer ) 1;
    register pointer t2 = (pointer ) 1;
    register pointer dvoid;

    if (pvt->final) {  /* generate constant fill */
	/* Generate constant fill of 0 for remainder of image */
	while ((dband->current < dband->format->height) &&
	       (dvoid = GetCurrentDst(flo,pet,dband))) {
		action_clear(dvoid,dband->format->pitch,0);
		if (PutData(flo,pet,dband,dband->current+1))
		    break;
	}
	return TRUE;
    }

    if (msk & 1) s0 = GetCurrentSrc(flo,pet,sband); sband++;
    if (msk & 2) s1 = GetCurrentSrc(flo,pet,sband); sband++;
    if (msk & 4) s2 = GetCurrentSrc(flo,pet,sband); sband -= 2;
    if (msk & 1) t0 = GetCurrentSrc(flo,pet,tband); tband++;
    if (msk & 2) t1 = GetCurrentSrc(flo,pet,tband); tband++;
    if (msk & 4) t2 = GetCurrentSrc(flo,pet,tband); tband -= 2;

    dvoid = GetCurrentDst(flo,pet,dband);

    while (!ferrCode(flo) && s0 && s1 && s2 && t0 && t1 && t2 && dvoid && 
			SyncDomain(flo,ped,dband,FLUSH)) {
	register INT32 run, ix = 0, extra;

	while (run = GetRun(flo,pet,dband)) {
	    if (run > 0) {
	        extra = 0;
		if ((ix+run) > w) { /* tband < sband */
		    if (ix >= w) { /* already off the end of src2 */ 
			action_clear(dvoid, dband->format->width - ix, ix);
			break;
		    }
		    extra = ix + run - w;
		    action_clear(dvoid, extra, w);
		    run = w - ix;
		}
		action_set(dvoid, run, ix);
		if (msk & 1) (*((pvt+0)->action)) (dvoid, s0, t0, run, ix); 
		if (msk & 2) (*((pvt+1)->action)) (dvoid, s1, t1, run, ix); 
		if (msk & 4) (*((pvt+2)->action)) (dvoid, s2, t2, run, ix); 
		if (!equal)  action_invert(dvoid, run, ix);
		ix += run + extra;
	    } else {
		action_clear(dvoid, -run, ix);
		ix -= run;
	    }
	}

	if (msk & 1) s0 = GetNextSrc(flo,pet,sband,FLUSH); sband++;
	if (msk & 2) s1 = GetNextSrc(flo,pet,sband,FLUSH); sband++;
	if (msk & 4) s2 = GetNextSrc(flo,pet,sband,FLUSH); sband -= 2;
	if (msk & 1) t0 = GetNextSrc(flo,pet,tband,FLUSH); tband++;
	if (msk & 2) t1 = GetNextSrc(flo,pet,tband,FLUSH); tband++;
	if (msk & 4) t2 = GetNextSrc(flo,pet,tband,FLUSH); tband -= 2;
	dvoid = GetNextDst(flo,pet,dband,FLUSH);
    }

    if (msk & 1) FreeData(flo,pet,sband,sband->current); sband++;
    if (msk & 2) FreeData(flo,pet,sband,sband->current); sband++;
    if (msk & 4) FreeData(flo,pet,sband,sband->current); sband -= 2;
    if (msk & 1) FreeData(flo,pet,tband,tband->current); tband++;
    if (msk & 2) FreeData(flo,pet,tband,tband->current); tband++;
    if (msk & 4) FreeData(flo,pet,tband,tband->current); tband -= 2;

    /* if dband is final, then we are done. make sure src2 disabled */
    if (dband->current >= dband->format->height) {
	if (msk & 1) DisableSrc(flo,pet,tband,FLUSH); tband++;
	if (msk & 2) DisableSrc(flo,pet,tband,FLUSH); tband++;
	if (msk & 4) DisableSrc(flo,pet,tband,FLUSH); tband -= 2;
	return TRUE;
    }

    /* if src2 finished early, then disable src1 and generate 0 fill */
    if (dband->current >= tband->format->height) {
    	/* only need to check one band since in theory all the same */ 
	if (msk & 1) DisableSrc(flo,pet,sband,FLUSH); sband++;
	if (msk & 2) DisableSrc(flo,pet,sband,FLUSH); sband++;
	if (msk & 4) DisableSrc(flo,pet,sband,FLUSH); sband -= 2;
	pvt->final = TRUE;
    }
    return TRUE;
}

/*------------------------------------------------------------------------
------------------------ get rid of run-time stuff -----------------------
------------------------------------------------------------------------*/
static int ResetCompare(flo,ped)
    floDefPtr flo;
    peDefPtr  ped;
{
    ResetReceptors(ped);
    ResetProcDomain(ped);
    ResetEmitter(ped);
    return TRUE;
}

/*------------------------------------------------------------------------
-------------------------- get rid of this element -----------------------
------------------------------------------------------------------------*/
static int DestroyCompare(flo,ped)
     floDefPtr flo;
     peDefPtr  ped;
{
    /* get rid of the peTex structure  */
    ped->peTex = (peTexPtr) XieFree(ped->peTex);

    /* zap this element's entry point vector */
    ped->ddVec.create = (xieIntProc)NULL;
    ped->ddVec.initialize = (xieIntProc)NULL;
    ped->ddVec.activate = (xieIntProc)NULL;
    ped->ddVec.reset = (xieIntProc)NULL;
    ped->ddVec.destroy = (xieIntProc)NULL;

    return TRUE;
} 

/*------------------------------------------------------------------------
---------------------  Lotsa Little Action Routines  ---------------------
------------------------------------------------------------------------*/

#if defined(NON_ROI)
/* M:	(*(pvt->action)) (dvoid, svoid, pvt, bw); */
/* D:	(*(pvt->action)) (dvoid, svoid, tvoid, bw); */

#define MakeBit(name1, name2, op) 					\
static void name1(dst,src1,pvt,nx)					\
    LogInt *dst;							\
    pointer src1;							\
    mpComparePvtPtr pvt;						\
    CARD32 nx;								\
{									\
    LogInt *src = (LogInt *) src1;					\
    LogInt S1, S2 = (pvt->iconst ? LOGONES : LOGZERO);			\
    for (nx = (nx + LOGMASK) >> LOGSHIFT; nx > 0; nx--) {		\
	S1 = *src++;							\
	*dst++ = op;							\
    }									\
}									\
static void name2(dst,src1,src2,nx)					\
    LogInt *dst;							\
    pointer src1, src2;							\
    CARD32 nx;								\
{									\
    LogInt S1, *src = (LogInt *) src1;					\
    LogInt S2, *trc = (LogInt *) src2;					\
    for (nx = (nx + LOGMASK) >> LOGSHIFT; nx > 0; nx--) {		\
	S1 = *src++;							\
	S2 = *trc++;							\
	*dst++ = op;							\
    }									\
}

#define MakePix(name1, name2, itype, cnst_name, op)			\
static void name1(dst,src1,pvt,nx)					\
    LogInt *dst;							\
    pointer src1;							\
    mpComparePvtPtr pvt;						\
    CARD32 nx;								\
{									\
    itype *src = (itype *) src1;					\
    itype con = (itype) pvt->cnst_name;					\
    LogInt M, value;							\
    for ( ; nx >= LOGSIZE; nx -= LOGSIZE, *dst++ = value) 		\
	for (value = 0, M=LOGLEFT; M ; LOGRIGHT(M))			\
	    if (*src++ op con)						\
		value |= M;						\
    if (nx > 0) {							\
	for (value = 0, M=LOGLEFT; nx; nx--, LOGRIGHT(M))		\
	    if (*src++ op con)						\
		value |= M;						\
	*dst = value;							\
    }									\
}									\
static void name2(dst,src1,src2,nx)					\
    LogInt *dst;							\
    pointer src1, src2;							\
    CARD32 nx;								\
{									\
    itype *src = (itype *) src1;					\
    itype *trc = (itype *) src2;					\
    LogInt M, value;							\
    for ( ; nx >= LOGSIZE; nx -= LOGSIZE, *dst++ = value) 		\
	for (value = 0, M=LOGLEFT; M ; LOGRIGHT(M))			\
	    if (*src++ op *trc++)					\
		value |= M;						\
    if (nx > 0) {							\
	for (value = 0, M=LOGLEFT; nx; nx--, LOGRIGHT(M))		\
	    if (*src++ op *trc++)					\
		value |= M;						\
	*dst = value;							\
    }									\
}

MakeBit	(m_bit_lt, d_bit_lt, (S2 & ~S1) )
MakeBit	(m_bit_le, d_bit_le, (S2 | ~S1) )
MakeBit	(m_bit_eq, d_bit_eq, (S1 ^ ~S2)	)
MakeBit	(m_bit_ne, d_bit_ne, (S1 ^  S2)	)
MakeBit	(m_bit_gt, d_bit_gt, (S1 & ~S2)	)
MakeBit	(m_bit_ge, d_bit_ge, (S1 | ~S2) )

MakePix	(m_byte_lt, d_byte_lt, BytePixel, iconst, <  )
MakePix	(m_byte_le, d_byte_le, BytePixel, iconst, <= )
MakePix	(m_byte_eq, d_byte_eq, BytePixel, iconst, == )
MakePix	(m_byte_ne, d_byte_ne, BytePixel, iconst, != )
MakePix	(m_byte_gt, d_byte_gt, BytePixel, iconst, >  )
MakePix	(m_byte_ge, d_byte_ge, BytePixel, iconst, >= )

MakePix	(m_pair_lt, d_pair_lt, PairPixel, iconst, <  )
MakePix	(m_pair_le, d_pair_le, PairPixel, iconst, <= )
MakePix	(m_pair_eq, d_pair_eq, PairPixel, iconst, == )
MakePix	(m_pair_ne, d_pair_ne, PairPixel, iconst, != )
MakePix	(m_pair_gt, d_pair_gt, PairPixel, iconst, >  )
MakePix	(m_pair_ge, d_pair_ge, PairPixel, iconst, >= )

MakePix	(m_quad_lt, d_quad_lt, QuadPixel, iconst, <  )
MakePix	(m_quad_le, d_quad_le, QuadPixel, iconst, <= )
MakePix	(m_quad_eq, d_quad_eq, QuadPixel, iconst, == )
MakePix	(m_quad_ne, d_quad_ne, QuadPixel, iconst, != )
MakePix	(m_quad_ge, d_quad_ge, QuadPixel, iconst, >= )
MakePix	(m_quad_gt, d_quad_gt, QuadPixel, iconst, >  )

MakePix	(m_real_lt, d_real_lt, RealPixel, fconst, <  )
MakePix	(m_real_le, d_real_le, RealPixel, fconst, <= )
MakePix	(m_real_eq, d_real_eq, RealPixel, fconst, == )
MakePix	(m_real_ne, d_real_ne, RealPixel, fconst, != )
MakePix	(m_real_gt, d_real_gt, RealPixel, fconst, >  )
MakePix	(m_real_ge, d_real_ge, RealPixel, fconst, >= )

static void (*action_mono[5][6])() = {
	m_real_lt, m_real_le, m_real_eq, m_real_ne, m_real_gt, m_real_ge,
	 m_bit_lt,  m_bit_le,  m_bit_eq,  m_bit_ne,  m_bit_gt,  m_bit_ge,
	m_byte_lt, m_byte_le, m_byte_eq, m_byte_ne, m_byte_gt, m_byte_ge,
	m_pair_lt, m_pair_le, m_pair_eq, m_pair_ne, m_pair_gt, m_pair_ge,
	m_quad_lt, m_quad_le, m_quad_eq, m_quad_ne, m_quad_gt, m_quad_ge
};
static void (*action_dyad[5][6])() = {
	d_real_lt, d_real_le, d_real_eq, d_real_ne, d_real_gt, d_real_ge,
	d_bit_lt,  d_bit_le,  d_bit_eq,  d_bit_ne,  d_bit_gt,  d_bit_ge,
	d_byte_lt, d_byte_le, d_byte_eq, d_byte_ne, d_byte_gt, d_byte_ge,
	d_pair_lt, d_pair_le, d_pair_eq, d_pair_ne, d_pair_gt, d_pair_ge,
	d_quad_lt, d_quad_le, d_quad_eq, d_quad_ne, d_quad_gt, d_quad_ge
};
#endif

/*------------------------------------------------------------------------
---------------------  ROI operations work on subranges ------------------
------------------------------------------------------------------------*/

/* MROI: (*(pvt->action)) (dvoid, src1, pvt, run, ix); */
/* DROI: (*(pvt->action)) (dvoid, src1, src2, run, ix); */

/* Currently ROI code pre-zeroes the line and then we OR into it.
** If we want to use this for the nonROI code as well, it might be
** more efficient to instead use a passive routine (when run < 0) to
** clear out the idle bits.
*/

#define RakeBit(name1, name2, op) 					\
static void name1(dst,src1,pvt,dx,x)					\
    LogInt *dst;							\
    pointer src1;							\
    mpComparePvtPtr pvt;						\
    INT32  dx, x;							\
{									\
    CARD32 M, D, px = LOGINDX(x);					\
    LogInt S1, *src = ((LogInt *) src1) + px;				\
    LogInt S2 = (pvt->iconst ? LOGONES : LOGZERO);			\
    dst += px; 								\
    px = x & LOGMASK;							\
    if ((px + dx) >= LOGSIZE) {						\
	if (px) {							\
	    S1 = *src++; 						\
	    D = *dst;							\
	    M = BitRight(LOGONES,px);					\
	    dx -= (LOGSIZE - px);					\
	    *dst++ = D | (M & op);					\
	}								\
	for (px = dx >> LOGSHIFT; px > 0; px--) {			\
	    S1 = *src++; 						\
	    *dst++ = op;						\
	}								\
	if (dx &= LOGMASK) {						\
	    S1 = *src; 							\
	    D = *dst;							\
	    M = ~BitRight(LOGONES,dx);					\
	    *dst = D | (M & op);					\
	}								\
    } else {								\
	    S1 = *src;	 						\
	    D = *dst;							\
	    M = BitRight(LOGONES,px) & ~(BitRight(LOGONES,px+dx));	\
	    *dst = D | (M & op);					\
    }									\
}									\
static void name2(dst,src1,src2,dx,x)					\
    LogInt *dst;							\
    pointer src1, src2;							\
    INT32  dx, x;							\
{									\
    CARD32 M, D, px = LOGINDX(x);					\
    LogInt S1, *src = ((LogInt *) src1) + px;				\
    LogInt S2, *trc = ((LogInt *) src2) + px;				\
    dst += px; 								\
    px = x & LOGMASK;							\
    if ((px + dx) >= LOGSIZE) {						\
	if (px) {							\
	    S1 = *src++; S2 = *trc++;					\
	    D = *dst;							\
	    M = BitRight(LOGONES,px);					\
	    dx -= (LOGSIZE - px);					\
	    *dst++ = D | (M & op);					\
	}								\
	for (px = dx >> LOGSHIFT; px > 0; px--) {			\
	    S1 = *src++; S2 = *trc++;					\
	    *dst++ = op;						\
	}								\
	if (dx &= LOGMASK) {						\
	    S1 = *src; S2 = *trc;					\
	    D = *dst;							\
	    M = ~BitRight(LOGONES,dx);					\
	    *dst = D | (M & op);					\
	}								\
    } else {								\
	    S1 = *src; S2 = *trc;					\
	    D = *dst;							\
	    M = BitRight(LOGONES,px) & ~(BitRight(LOGONES,px+dx));	\
	    *dst = D | (M & op);					\
    }									\
}

#define RakePix(name1, name2, itype, cnst_name, op)			\
static void name1(dst,src1,pvt,dx,x)					\
    LogInt *dst;							\
    pointer src1;							\
    mpComparePvtPtr pvt;						\
    INT32  dx, x;							\
{									\
    itype *src = ((itype *) src1) + x;					\
    itype con = (itype) pvt->cnst_name;					\
    LogInt M, value;							\
    dst += LOGINDX(x); 							\
    if (x & LOGMASK) {							\
	for (value = *dst, M=LOGBIT(x); dx && M; dx--, LOGRIGHT(M))	\
	    if (*src++ op con)						\
		value |= M;						\
	    else							\
		value &= ~M;						\
	*dst++ = value;							\
    }									\
    for ( ; dx >= LOGSIZE; dx -= LOGSIZE, *dst++ = value) 		\
	for (value = 0, M=LOGLEFT; M ; LOGRIGHT(M))			\
	    if (*src++ op con)						\
		value |= M;						\
    if (dx > 0) {							\
	for (value = 0, M=LOGLEFT; dx; dx--, LOGRIGHT(M))		\
	    if (*src++ op con)						\
		value |= M;						\
	*dst = value;							\
    }									\
}									\
static void name2(dst,src1,src2,dx,x)					\
    LogInt *dst;							\
    pointer src1, src2;							\
    INT32  dx, x;							\
{									\
    itype *src = ((itype *) src1) + x;					\
    itype *trc = ((itype *) src2) + x;					\
    LogInt M, value;							\
    dst += LOGINDX(x); 							\
    if (x & LOGMASK) {							\
	for (value = *dst, M=LOGBIT(x); dx && M; dx--, LOGRIGHT(M))	\
	    if (*src++ op *trc++)					\
		value |= M;						\
	    else							\
		value &= ~M;						\
	*dst++ = value;							\
    }									\
    for ( ; dx >= LOGSIZE; dx -= LOGSIZE, *dst++ = value) 		\
	for (value = 0, M=LOGLEFT; M ; LOGRIGHT(M))			\
	    if (*src++ op *trc++)					\
		value |= M;						\
    if (dx > 0) {							\
	for (value = 0, M=LOGLEFT; dx; dx--, LOGRIGHT(M))		\
	    if (*src++ op *trc++)					\
		value |= M;						\
	*dst = value;							\
    }									\
}

/*
** Consider the following paradigm.  It adds a taken branch to 
** each loop, but reduces the amount of total code.  This mechanism
** also relies on the preclearing of the full destination while
** the above mechanism could be adapted to apply boundary masks,
** to work more efficiently with nonROI data.
**
**	for (value = 0, M = x & LOGMASK ; dx ; dx--) {
**	    if (*src++ op *trc++) value |= M;
**	    if (LOGRIGHT(M)) { *dst++ |= value; value = 0; }
**	}		
*/

RakeBit	(rm_bit_lt, rd_bit_lt, (S2 & ~S1) )
RakeBit	(rm_bit_le, rd_bit_le, (S2 | ~S1) )
RakeBit	(rm_bit_eq, rd_bit_eq, (S1 ^ ~S2) )
RakeBit	(rm_bit_ne, rd_bit_ne, (S1 ^  S2) )
RakeBit	(rm_bit_gt, rd_bit_gt, (S1 & ~S2) )
RakeBit	(rm_bit_ge, rd_bit_ge, (S1 | ~S2) )

RakePix	(rm_byte_lt, rd_byte_lt, BytePixel, iconst, <  )
RakePix	(rm_byte_le, rd_byte_le, BytePixel, iconst, <= )
RakePix	(rm_byte_eq, rd_byte_eq, BytePixel, iconst, == )
RakePix	(rm_byte_ne, rd_byte_ne, BytePixel, iconst, != )
RakePix	(rm_byte_gt, rd_byte_gt, BytePixel, iconst, >  )
RakePix	(rm_byte_ge, rd_byte_ge, BytePixel, iconst, >= )

RakePix	(rm_pair_lt, rd_pair_lt, PairPixel, iconst, <  )
RakePix	(rm_pair_le, rd_pair_le, PairPixel, iconst, <= )
RakePix	(rm_pair_eq, rd_pair_eq, PairPixel, iconst, == )
RakePix	(rm_pair_ne, rd_pair_ne, PairPixel, iconst, != )
RakePix	(rm_pair_gt, rd_pair_gt, PairPixel, iconst, >  )
RakePix	(rm_pair_ge, rd_pair_ge, PairPixel, iconst, >= )

RakePix	(rm_quad_lt, rd_quad_lt, QuadPixel, iconst, <  )
RakePix	(rm_quad_le, rd_quad_le, QuadPixel, iconst, <= )
RakePix	(rm_quad_eq, rd_quad_eq, QuadPixel, iconst, == )
RakePix	(rm_quad_ne, rd_quad_ne, QuadPixel, iconst, != )
RakePix	(rm_quad_ge, rd_quad_ge, QuadPixel, iconst, >= )
RakePix	(rm_quad_gt, rd_quad_gt, QuadPixel, iconst, >  )

RakePix	(rm_real_lt, rd_real_lt, RealPixel, fconst, <  )
RakePix	(rm_real_le, rd_real_le, RealPixel, fconst, <= )
RakePix	(rm_real_eq, rd_real_eq, RealPixel, fconst, == )
RakePix	(rm_real_ne, rd_real_ne, RealPixel, fconst, != )
RakePix	(rm_real_gt, rd_real_gt, RealPixel, fconst, >  )
RakePix	(rm_real_ge, rd_real_ge, RealPixel, fconst, >= )

static void (*action_monoROI[5][6])() = {
	rm_real_lt, rm_real_le, rm_real_eq, rm_real_ne, rm_real_gt, rm_real_ge,
	 rm_bit_lt,  rm_bit_le,  rm_bit_eq,  rm_bit_ne,  rm_bit_gt,  rm_bit_ge,
	rm_byte_lt, rm_byte_le, rm_byte_eq, rm_byte_ne, rm_byte_gt, rm_byte_ge,
	rm_pair_lt, rm_pair_le, rm_pair_eq, rm_pair_ne, rm_pair_gt, rm_pair_ge,
	rm_quad_lt, rm_quad_le, rm_quad_eq, rm_quad_ne, rm_quad_gt, rm_quad_ge
};
static void (*action_dyadROI[5][6])() = {
	rd_real_lt, rd_real_le, rd_real_eq, rd_real_ne, rd_real_gt, rd_real_ge,
	rd_bit_lt,  rd_bit_le,  rd_bit_eq,  rd_bit_ne,  rd_bit_gt,  rd_bit_ge,
	rd_byte_lt, rd_byte_le, rd_byte_eq, rd_byte_ne, rd_byte_gt, rd_byte_ge,
	rd_pair_lt, rd_pair_le, rd_pair_eq, rd_pair_ne, rd_pair_gt, rd_pair_ge,
	rd_quad_lt, rd_quad_le, rd_quad_eq, rd_quad_ne, rd_quad_gt, rd_quad_ge
};

/*------------------------------------------------------------------------
----------------  Triple Band Operations (with/without ROI) --------------
------------------------------------------------------------------------*/

/* mono: (*(pvt->action)) (dvoid, src1, pvt, run, ix); */
/* dyad: (*(pvt->action)) (dvoid, src1, src2, run, ix); */

#define tb_name1_body()							\
    CARD32 M, D, px = LOGINDX(x);					\
    LogInt S1, *src = ((LogInt *) src1) + px;				\
    LogInt S2 = (pvt->iconst ? LOGONES : LOGZERO);			\
    dst += px; 								\
    px = x & LOGMASK;							\
    if ((px + dx) >= LOGSIZE) {						\
	if (px) {							\
	    S1 = *src++; 						\
	    D = *dst;							\
	    M = BitRight(LOGONES,px);					\
	    dx -= (LOGSIZE - px);					\
	    *dst++ = D & ~(M & (S1 ^ S2));				\
	}								\
	for (px = dx >> LOGSHIFT; px > 0; px--) {			\
	    S1 = *src++; 						\
	    D = *dst;							\
	    /* turn off (&~) unequal (^) bits */			\
	    *dst++ = D & ~(S1 ^ S2);					\
	}								\
	if (dx &= LOGMASK) {						\
	    S1 = *src; 							\
	    D = *dst;							\
	    M = ~BitRight(LOGONES,dx);					\
	    *dst = D & ~(M & (S1 ^ S2));				\
	}								\
    } else {								\
	    S1 = *src;	 						\
	    D = *dst;							\
	    M = BitRight(LOGONES,px) & ~(BitRight(LOGONES,px+dx));	\
	    *dst = D & ~(M & (S1 ^ S2));				\
    }
/* end of tb_name1_body */

#define tb_name2_body()							\
    CARD32 M, D, px = LOGINDX(x);					\
    LogInt S1, *src = ((LogInt *) src1) + px;				\
    LogInt S2, *trc = ((LogInt *) src2) + px;				\
    dst += px; 								\
    px = x & LOGMASK;							\
    if ((px + dx) >= LOGSIZE) {						\
	if (px) {							\
	    S1 = *src++; S2 = *trc++;					\
	    D = *dst;							\
	    M = BitRight(LOGONES,px);					\
	    dx -= (LOGSIZE - px);					\
	    *dst++ = D & ~(M & (S1 ^ S2));				\
	}								\
	for (px = dx >> LOGSHIFT; px > 0; px--) {			\
	    S1 = *src++; S2 = *trc++;					\
	    D = *dst;							\
	    *dst++ = D & ~(S1 ^ S2);					\
	}								\
	if (dx &= LOGMASK) {						\
	    S1 = *src; S2 = *trc;					\
	    D = *dst;							\
	    M = ~BitRight(LOGONES,dx);					\
	    *dst = D & ~(M & (S1 ^ S2));				\
	}								\
    } else {								\
	    S1 = *src; S2 = *trc;					\
	    D = *dst;							\
	    M = BitRight(LOGONES,px) & ~(BitRight(LOGONES,px+dx));	\
	    *dst = D & ~(M & (S1 ^ S2));				\
    }		
/* end of tb_name2_body */

#define TakeBit(name1, name2)	 					\
static void name1(dst,src1,pvt,dx,x)					\
    LogInt *dst;							\
    pointer src1;							\
    mpComparePvtPtr pvt;						\
    INT32  dx, x;							\
{									\
tb_name1_body()								\
}									\
static void name2(dst,src1,src2,dx,x)					\
    LogInt *dst;							\
    pointer src1, src2;							\
    INT32  dx, x;							\
{									\
tb_name2_body()								\
}

#define TakePix(name1, name2, itype, cnst_name)				\
static void name1(dst,src1,pvt,dx,x)					\
    LogInt *dst;							\
    pointer src1;							\
    mpComparePvtPtr pvt;						\
    INT32  dx, x;							\
{									\
    itype *src = ((itype *) src1) + x;					\
    itype con = (itype) pvt->cnst_name;					\
    LogInt M, value;							\
    dst += LOGINDX(x); 							\
    if (x & LOGMASK) {							\
	for (value = 0, M=LOGBIT(x); dx && M; dx--, LOGRIGHT(M))	\
	    if (*src++ != con)						\
		value |= M;						\
	*dst++ &= ~value;						\
    }									\
    for ( ; dx >= LOGSIZE; dx -= LOGSIZE, dst++) {			\
	/* if (!*dst) { src += LOGSIZE; } else */			\
	for (value = 0, M=LOGLEFT; M ; LOGRIGHT(M))			\
	    if (*src++ != con)						\
		value |= M;						\
	*dst &= ~value;							\
    }									\
    if (dx > 0) {							\
	for (value = 0, M=LOGLEFT; dx; dx--, LOGRIGHT(M))		\
	    if (*src++ != con)						\
		value |= M;						\
	*dst &= ~value;							\
    }									\
}									\
static void name2(dst,src1,src2,dx,x)					\
    LogInt *dst;							\
    pointer src1, src2;							\
    INT32  dx, x;							\
{									\
    itype *src = ((itype *) src1) + x;					\
    itype *trc = ((itype *) src2) + x;					\
    LogInt M, value;							\
    dst += LOGINDX(x); 							\
    if (x & LOGMASK) {							\
	for (value = 0, M=LOGBIT(x); dx && M; dx--, LOGRIGHT(M))	\
	    if (*src++ != *trc++)					\
		value |= M;						\
	*dst++ &= ~value;						\
    }									\
    for ( ; dx >= LOGSIZE; dx -= LOGSIZE, dst++) {			\
	/* if (!*dst) { src += LOGSIZE; trc += LOGSIZE; } else */	\
	for (value = 0, M=LOGLEFT; M ; LOGRIGHT(M))			\
	    if (*src++ != *trc++)					\
		value |= M;						\
	*dst &= ~value;							\
    }									\
    if (dx > 0) {							\
	for (value = 0, M=LOGLEFT; dx; dx--, LOGRIGHT(M))		\
	    if (*src++ != *trc++)					\
		value |= M;						\
	*dst++ &= ~value;						\
    }									\
}

TakeBit	(tm_bit,  td_bit)
TakePix	(tm_byte, td_byte, BytePixel, iconst)
TakePix	(tm_pair, td_pair, PairPixel, iconst)
TakePix	(tm_quad, td_quad, QuadPixel, iconst)
TakePix	(tm_real, td_real, RealPixel, fconst)

static void (*action_mtrip[5])() =
	{ tm_real, tm_bit, tm_byte, tm_pair, tm_quad };

static void (*action_dtrip[5])() =
	{ td_real, td_bit, td_byte, td_pair, td_quad };

/*------------------------------------------------------------------------
---------------------------- initialize peTex . . . ----------------------
------------------------------------------------------------------------*/

static int InitializeCompare(flo,ped)
    floDefPtr flo;
    peDefPtr  ped;
{
    peTexPtr 	     pet = ped->peTex;
    xieFloCompare   *raw = (xieFloCompare *) ped->elemRaw;
    pCompareDefPtr  epvt = (pCompareDefPtr)  ped->elemPvt;
    mpComparePvtPtr  pvt = (mpComparePvtPtr) pet->private;
    receptorPtr      rcp = pet->receptor;
    CARD32	  nbands = rcp[SRCt1].inFlo->bands;
    bandPtr	   sband = &(rcp[SRCt1].band[0]);
    bandPtr 	   tband = &(rcp[SRCt2].band[0]);
    bandPtr	   dband = &(pet->emitter[0]);
    CARD8	     msk = raw->bandMask;
    BOOL	  hasROI = raw->domainPhototag != 0;
    BOOL     doingtriple = raw->combine && (nbands == 3);
    CARD32	    band;

    if (doingtriple) {
	if (raw->src2)
	    ped->ddVec.activate = ActivateCompareTripleD;
	else
	    ped->ddVec.activate = ActivateCompareTripleM;
#if defined(NON_ROI)
    } else if (!hasROI) {
	if (raw->src2)
	    ped->ddVec.activate = ActivateCompareD;
	else
	    ped->ddVec.activate = ActivateCompareM;
#endif
    } else {
	if (raw->src2)
	    ped->ddVec.activate = ActivateCompareDROI;
	else
	    ped->ddVec.activate = ActivateCompareMROI;
    }
    for (band=0; band<nbands; band++, pvt++, sband++, tband++, dband++) {
	CARD32 iclass = IndexClass(sband->format->class);
	pvt->width = sband->format->width;
	pvt->final = FALSE;
	if (raw->src2 && (pvt->width > tband->format->width))
	    pvt->width = tband->format->width;
	if (doingtriple) {
	    if (raw->src2)
		pvt->action = action_dtrip[iclass];
	    else
		pvt->action = action_mtrip[iclass];
#if defined(NON_ROI)
	} else if (!hasROI) {
	    if (raw->src2) {
		pvt->action = action_dyad[iclass][raw->operator-1];
		pvt->action2 = (void (*)()) NULL;
		pvt->endix = dband->format->width; /* pixels to do */
		if (dband->format->width > tband->format->width) {
		    pvt->action2 = action_clear;
		    pvt->endix = tband->format->width; /* pixels to do */
		    pvt->endrun = dband->format->width -
				tband->format->width; /* pixels to pad */
		}
	    } else
		pvt->action = action_mono[iclass][raw->operator-1];
#endif
	} else { /* ROI */
	    if (raw->src2)
		pvt->action = action_dyadROI[iclass][raw->operator-1];
	    else
		pvt->action = action_monoROI[iclass][raw->operator-1];
	}
	if (!raw->src2) {
	    double dub = epvt->constant[band];
	    pvt->fconst = dub;
	    pvt->iconst = ConstrainConst(dub, sband->format->levels);
	}
    }

    /* If processing domain, allow replication */
    if (hasROI && !doingtriple)
	rcp[ped->inCnt-1].band[0].replicate = msk;

    InitReceptor(flo, ped, &rcp[SRCt1], NO_DATAMAP, 1, msk, NO_BANDS);

    if (raw->src2)
	InitReceptor(flo, ped, &rcp[SRCt2], NO_DATAMAP, 1, msk, NO_BANDS);

#if defined(NON_ROI)
    if (hasROI || doingtriple)
#endif
	InitProcDomain(flo, ped, raw->domainPhototag, raw->domainOffsetX, 
							raw->domainOffsetY);
    InitEmitter(flo, ped, NO_DATAMAP, NO_INPLACE);

    pet->bandSync = doingtriple ? SYNC : NO_SYNC;

    return !ferrCode(flo);
}
	

/* end module mpcomp.c */
