/******************************************************************************
*
*  File Name   : MISC.C
*
*  Description : miscellaneous Jigsaw functions
*
*  Entry Points:
*		 CreateBitmapHdcHps()
*		 SegListUpdate()
*		 SetDVTransform()
*		 SetRect()
*		 SegListGet()
*		 DrawPiece()
*		 DoDraw()
*		 CalcBounds()
*		 CalcTransform()
*		 Redraw()
*		 Correlate()
*		 MarkIsland()
*
*  Copyright (C) 1992 IBM Corporation
*
*      DISCLAIMER OF WARRANTIES.  The following [enclosed] code is
*      sample code created by IBM Corporation. This sample code is not
*      part of any standard or IBM product and is provided to you solely
*      for  the purpose of assisting you in the development of your
*      applications.  The code is provided "AS IS", without
*      warranty of any kind.  IBM shall not be liable for any damages
*      arising out of your use of the sample code, even if they have been
*      advised of the possibility of such damages.						      *
*
******************************************************************************/

#include "jigsaw.h"
#include "globals.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

/******************************************************************************/
/*									      */
/* Create a memory DC and an associated PS.				      */
/*									      */
/******************************************************************************/
BOOL CreateBitmapHdcHps( phdc, phps)
PHDC phdc;
PHPS phps;
{
  SIZEL	   sizl;
  HDC	   hdc;
  HPS	   hps;

  hdc = DevOpenDC( habMain, OD_MEMORY, "*", 3L, (PDEVOPENDATA)&dop, NULLHANDLE);
  if( !hdc)
    return( FALSE);

  sizl.cx = sizl.cy = 1L;
  if ((hps = GpiCreatePS( habMain
			, hdc
			, &sizl
			, PU_PELS | GPIA_ASSOC | GPIT_MICRO )) == GPI_ERROR)
	     DispError(habMain,hwndClient);
  if( !hps)
    return( FALSE);

  *phdc = hdc;
  *phps = hps;
  return( TRUE);
}

/*****************************************************************************/
/*									      */
/* Add (at head or tail) or delete a specified segment list member.	      */
/*									      */
/******************************************************************************/
PSEGLIST SegListUpdate(USHORT usOperation,PSEGLIST pslUpdate)
{
  PSEGLIST psl;

  switch( usOperation)
  {
    case ADD_HEAD_SEG:
      if( pslHead == NULL)
      {
	DosAllocMem((PPVOID)&pslHead,(ULONG)sizeof(SEGLIST),(ULONG)PAG_READ | PAG_WRITE | PAG_COMMIT);
	if( pslHead == NULL)
	  return( NULL);
	*pslHead = *pslUpdate;
	pslHead->pslPrev = NULL;
	pslHead->pslNext = NULL;
	pslTail = pslHead;
      } else
      {
	DosAllocMem((PPVOID)&psl,(ULONG)sizeof(SEGLIST),(ULONG)PAG_READ | PAG_WRITE | PAG_COMMIT);
	if( psl == NULL)
	  return( NULL);
	*psl = *pslUpdate;
	pslHead->pslPrev = psl;
	psl->pslNext = pslHead;
	psl->pslPrev = NULL;
	pslHead = psl;
      }
      return( pslHead);
      break;

    case ADD_TAIL_SEG:
      if( pslTail == NULL)
      {
	DosAllocMem((PPVOID)&pslHead,(ULONG)sizeof(SEGLIST),(ULONG)PAG_READ | PAG_WRITE |
		PAG_COMMIT);
	if( pslHead == NULL)
	  return( NULL);
	*pslHead = *pslUpdate;
	pslHead->pslPrev = NULL;
	pslHead->pslNext = NULL;
	pslTail = pslHead;
      } else
      {
	DosAllocMem((PPVOID)&psl,(ULONG)sizeof(SEGLIST),(ULONG)PAG_READ | PAG_WRITE |
		PAG_COMMIT);
	if( psl == NULL)
	  return( NULL);
	*psl = *pslUpdate;
	pslTail->pslNext = psl;
	psl->pslPrev = pslTail;
	psl->pslNext = NULL;
	pslTail = psl;
      }
      return( pslTail);
      break;

    case MAKE_TAIL_SEG:
      if( pslUpdate == pslTail)
	return( pslTail);
      if( pslUpdate == pslHead)
      {
	pslHead = pslHead->pslNext;
	pslHead->pslPrev = NULL;
      } else
      {
	pslUpdate->pslPrev->pslNext = pslUpdate->pslNext;
	pslUpdate->pslNext->pslPrev = pslUpdate->pslPrev;
      }
      pslTail->pslNext = pslUpdate;
      pslUpdate->pslPrev = pslTail;
      pslTail = pslUpdate;
      pslTail->pslNext = NULL;
      return( pslTail);
      break;

    case MAKE_HEAD_SEG:
      if( pslUpdate == pslHead)
	return( pslHead);
      if( pslUpdate == pslTail)
      {
	pslTail = pslTail->pslPrev;
	pslTail->pslNext = NULL;
      } else
      {
	pslUpdate->pslPrev->pslNext = pslUpdate->pslNext;
	pslUpdate->pslNext->pslPrev = pslUpdate->pslPrev;
      }
      pslHead->pslPrev = pslUpdate;
      pslUpdate->pslNext = pslHead;
      pslHead = pslUpdate;
      pslHead->pslPrev = NULL;
      return( pslHead);
      break;

    case DEL_SEG:
      for( psl = pslHead; psl != NULL; psl = psl->pslNext)
      {
	if( psl->lSegId == pslUpdate->lSegId)
	{
	  if( psl == pslHead)
	  {
	    pslHead = psl->pslNext;
	    if( pslHead == NULL)
	      pslTail = NULL;
	    else
	      pslHead->pslPrev = NULL;
	  }else if( psl == pslTail)
	  {
	    pslTail = psl->pslPrev;
	    pslTail->pslNext = NULL;
	  } else
	  {
	    (psl->pslPrev)->pslNext = psl->pslNext;
	    (psl->pslNext)->pslPrev = psl->pslPrev;
	  }
	  DosFreeMem( psl);
	  return( psl);
	  break;
	}
      }
      return( NULL);
      break;

    default:
      return( NULL);
  }
}

/******************************************************************************/
/*									      */
/* set the default viewing transform					      */
/*									      */
/******************************************************************************/
VOID SetDVTransform( fx11, fx12, fx21, fx22, l31, l32, lType)
FIXED fx11;
FIXED fx12;
FIXED fx21;
FIXED fx22;
FIXED l31;
FIXED l32;
FIXED lType;
{
  MATRIXLF  matlf;

  matlf.fxM11 = fx11;
  matlf.fxM12 = fx12;
  matlf.lM13  = 0L;
  matlf.fxM21 = fx21;
  matlf.fxM22 = fx22;
  matlf.lM23  = 0L;
  matlf.lM31  = l31;
  matlf.lM32  = l32;
  matlf.lM33  = 1L;
  if (GpiSetDefaultViewMatrix( hpsClient, 9L, &matlf, lType) == GPI_ERROR)
      DispError(habMain,hwndClient);
}

/******************************************************************************/
/*									      */
/* Determine the bounding rect of a segment.				      */
/*									      */
/* Use special knowledge that the only non-identity part of the segment	      */
/* transform is the translation part.					      */
/******************************************************************************/
VOID SetRect( psl)
PSEGLIST psl;
{
  psl->rclCurrent	  = psl->rclBitBlt;	 /* world space bounding rect */
  psl->rclCurrent.xLeft	  += psl->ptlModelXlate.x;
  psl->rclCurrent.yBottom += psl->ptlModelXlate.y;
  psl->rclCurrent.xRight  += psl->ptlModelXlate.x;
  psl->rclCurrent.yTop	  += psl->ptlModelXlate.y;
}

/******************************************************************************/
/*									      */
/* Return a pointer to a segment list member, based on segment id.	      */
/*									      */
/******************************************************************************/
PSEGLIST SegListGet( lSeg)
LONG lSeg;
{
  PSEGLIST  psl;

  for( psl = pslHead; psl != NULL; psl = psl->pslNext)
    if( psl->lSegId == lSeg)
      return( psl);
  return( NULL);
}


/******************************************************************************
*
*  Name	       : DrawPiece
*
*  Description : Draw one piece.
*
*  Concepts    :
*
*  API's       :
*
*  Parameters  : HPS	  hps
*		 PSEGLIST psl
*		 BOOL	  fFill
*
*  Return      : VOID
*
******************************************************************************/

VOID DrawPiece(HPS hps, PSEGLIST psl, BOOL fFill)
{
   POINTL  aptl[4];
   APIRET  rc;

   if(psl->fVisible)			      /* don't bother if not visible */
   {
      /*
       *  Setup source and target points based on model transform of this peice
       */

      aptl[2].x = aptl[2].y = 0L;		       /* source: lower left */
      aptl[3] = psl->aptlBitBlt[3];		      /* source: upper right */

							       /* target:    */
      aptl[0].x = psl->rclBitBlt.xLeft + psl->ptlModelXlate.x; /* lower left */
      aptl[0].y = psl->rclBitBlt.yBottom + psl->ptlModelXlate.y;

      rc =
      GpiConvert(hpsClient, CVTC_MODEL, CVTC_DEVICE, 1L, aptl);

      if (rc == GPI_ERROR)
	 DispError(habMain,hwndClient);

      aptl[1].x = aptl[0].x + aptl[3].x;	      /* target: upper right */
      aptl[1].y = aptl[0].y + aptl[3].y;	   /* (equal to source size) */

      /*
       *  Punch a hole
       */

      rc =
      GpiBitBlt(
	 hps,				 /* target presentation-space handle */
	 psl->hpsHole,			 /* source presentation-space handle */
	 4L,				 /* number of points in array	     */
	 aptl,				 /* address of array		     */
	 ROP_SRCAND,			 /* mixing method		     */
	 BBO_IGNORE);			 /* line/column-compression flag     */

      if (rc == GPI_ERROR)
	 DispError(habMain,hwndClient);

      if (fFill)
      {
	 /*
	  *  Fill the hole
	  */
	 rc =
	 GpiBitBlt(
	    hps,			 /* target presentation-space handle */
	    psl->hpsFill,		 /* source presentation-space handle */
	    4L,				 /* number of points in array	     */
	    aptl,			 /* address of array		     */
	    ROP_SRCPAINT,		 /* mixing method		     */
	    BBO_IGNORE);		 /* line/column-compression flag     */

	 if (rc == GPI_ERROR)
	    DispError(habMain,hwndClient);

      }	  /* end if (fFill) */

   }   /* end if(psl->fVisible) */

}   /* end DrawPiece() */

/******************************************************************************/
/*									      */
/* Draw the picture, using the passed region for clipping.		      */
/* Intersect the bounding box used for the clip region with the client rect.  */
/* Test each segment to see if its bounding box intersects the bounding box   */
/* of the clipping region.  Draw only if there is an intersection.	      */
/*									      */
/******************************************************************************/
BOOL DoDraw(HPS hps,HRGN hrgn,BOOL fPaint)
{
  HRGN	    hrgnOld;
  RECTL	    rcl, rclRegion, rclDst, rclClient;
  PSEGLIST  psl;
  ULONG	    ulPostCt;

  if( fPaint && !fFirstLoad)
  {
    if (GpiSetColor( hps, CLR_BACKGROUND) == GPI_ERROR)
	DispError(habMain,hwndClient);
    if (GpiPaintRegion( hps, hrgn) == GPI_ERROR)	     /* erase region */
	DispError(habMain,hwndClient);
  }

  if (GpiQueryRegionBox( hps, hrgn, &rclRegion) == RGN_ERROR)
      DispError(habMain,hwndClient);

  WinQueryWindowRect( hwndClient, &rclClient);

  if( !WinIntersectRect( habAsync, &rclRegion, &rclRegion, &rclClient))
    return( FALSE);				     /* not in client window */

  if (GpiSetClipRegion( hps, hrgn, &hrgnOld) == RGN_ERROR) /* make the clip region */
      DispError(habMain,hwndClient);

  for( psl = pslHead; psl != NULL; psl = psl->pslNext)	  /* scan all pieces */
  {
    /**************************************************************************/
    /* get the piece bounding box in device coordinates			      */
    /**************************************************************************/
    rcl = psl->rclCurrent;
    if (GpiConvert( hpsClient, CVTC_MODEL, CVTC_DEVICE, 2L, (PPOINTL)&rcl) == GPI_ERROR)
	DispError(habMain,hwndClient);
    rcl.xRight++;
    rcl.yTop++;

    /**************************************************************************/
    /* if the piece might be visible, and drawing allowed, draw the piece     */
    /**************************************************************************/

    if( WinIntersectRect( habAsync, &rclDst, &rcl, &rclRegion))
       {
       DosQueryEventSem( hevDrawOn, &ulPostCt);		 /* drawing enabled? */
	 if( ulPostCt)						      /* yes */
	   DrawPiece( hps, psl, TRUE);
	 else
	   break;		    /* drawing is disabled; don't draw piece */
       }
  }

  if (GpiSetClipRegion( hps, NULLHANDLE, &hrgnOld) == RGN_ERROR)
      DispError(habMain,hwndClient);

  DosQueryEventSem( hevDrawOn, &ulPostCt);
  if( ulPostCt)					       /* drawing is enabled */
    if (GpiSetRegion( hpsClient, hrgnInvalid, 0L, NULL) == RGN_ERROR)
	DispError(habMain,hwndClient);

  return( TRUE);

}   /* end DoDraw() */

/******************************************************************************/
/*									      */
/* get bounding rect of whole picture in model coordinates		      */
/*									      */
/******************************************************************************/
VOID CalcBounds(VOID)
{
  PSEGLIST  psl;
  RECTL	    rclOld;
  ULONG	    ulPostKillDraw, ulPostCt;

  if( !pslHead)
    return;
  rclBounds = rclOld = pslHead->rclCurrent;

  /*
   * get start killdraw post count
   */
  DosQueryEventSem(hevKillDraw, &ulPostKillDraw);

  for( psl = pslHead->pslNext; psl != NULL; psl = psl->pslNext) {
    DosQueryEventSem(hevKillDraw, &ulPostCt);
    if (ulPostKillDraw != ulPostCt) {
	rclBounds = rclOld;
	return;
	}
    WinUnionRect(habAsync, &rclBounds, &rclBounds, &(psl->rclCurrent));
    }
}

/******************************************************************************/
/*									      */
/* Calculate and set the default viewing transform based on zoom and scroll   */
/*									      */
/******************************************************************************/
VOID CalcTransform( hwnd)
HWND hwnd;
{
  RECTL	    rclClient;
  POINTL    ptlCenter, ptlTrans, ptlScale, aptl[4], ptlOrg, aptlSides[12];
  PSEGLIST  psl;
  LONG	    l;
  MATRIXLF  matlf;
  ULONG	    ulPostCt, ulPostKillDraw;


  /*
   * get start killdraw post count
   */
  DosQueryEventSem(hevKillDraw, &ulPostKillDraw);


  /****************************************************************************/
  /* from bounding rect of picture get center of picture		      */
  /****************************************************************************/
  ptlCenter.x = (rclBounds.xLeft   + rclBounds.xRight) / 2;
  ptlCenter.y = (rclBounds.yBottom + rclBounds.yTop  ) / 2;

  /****************************************************************************/
  /* translate center of picture to origin				      */
  /****************************************************************************/
  SetDVTransform( (FIXED)UNITY
		, (FIXED)0
		, (FIXED)0
		, (FIXED)UNITY
		, -ptlCenter.x
		, -ptlCenter.y
		, TRANSFORM_REPLACE);

  /****************************************************************************/
  /* scale down to 1:1 of bitmap in file				      */
  /****************************************************************************/
  if (pbmp2BitmapFile->cbFix  == sizeof(BITMAPINFOHEADER))
      {
      ptlScale.x = UNITY * ((PBITMAPINFOHEADER)pbmp2BitmapFile)->cx
	      / (ptlTopRight.x - ptlBotLeft.x);
      ptlScale.y = UNITY * ((PBITMAPINFOHEADER)pbmp2BitmapFile)->cy
	      / (ptlTopRight.y - ptlBotLeft.y);
      }
  else
      {
      ptlScale.x = UNITY * pbmp2BitmapFile->cx
	      / (ptlTopRight.x - ptlBotLeft.x);
      ptlScale.y = UNITY * pbmp2BitmapFile->cy
	      / (ptlTopRight.y - ptlBotLeft.y);
      }

  /****************************************************************************/
  /* add in zoom scale							      */
  /****************************************************************************/
  ptlScale.x += ptlScale.x * lScale / (ZOOM_MAX + 1);
  ptlScale.y += ptlScale.y * lScale / (ZOOM_MAX + 1);

  SetDVTransform( (FIXED)ptlScale.x
		, (FIXED)0
		, (FIXED)0
		, (FIXED)ptlScale.y
		, 0L
		, 0L
		, TRANSFORM_ADD);

  /****************************************************************************/
  /* translate center of picture to center of client window		      */
  /****************************************************************************/
  WinQueryWindowRect( hwnd, &rclClient);
  ptlTrans.x = (rclClient.xRight - rclClient.xLeft)   / 2;
  ptlTrans.y = (rclClient.yTop	 - rclClient.yBottom) / 2;

  /****************************************************************************/
  /* add in horizontal and vertical scrolling factors			      */
  /****************************************************************************/
  ptlTrans.x -= ptsScrollPos.x - ptsHalfScrollMax.x;
  ptlTrans.y += ptsScrollPos.y - ptsHalfScrollMax.y;
  SetDVTransform( (FIXED)UNITY
		, (FIXED)0
		, (FIXED)0
		, (FIXED)UNITY
		, ptlTrans.x
		, ptlTrans.y
		, TRANSFORM_ADD);

  if (GpiQueryDefaultViewMatrix( hpsClient, 9L, &matlf) == GPI_ERROR)
      DispError(habMain,hwndClient);
  if (GpiSetDefaultViewMatrix( hpsClient, 9L, &matlf, TRANSFORM_REPLACE) == GPI_ERROR)
      DispError(habMain,hwndClient);

  /****************************************************************************/
  /* create bitmaps for pieces						      */
  /****************************************************************************/

  ptlOffset = ptlBotLeft;		   /* BottomLeft corner in dev coord  */
  if (GpiConvert( hpsClient, CVTC_WORLD, CVTC_DEVICE, 1L, &ptlOffset) == GPI_ERROR)
      DispError(habMain,hwndClient);
  if( (ptlScale.x != ptlScaleRef.x) || (ptlScale.y != ptlScaleRef.y))
  {
    ptlScaleRef = ptlScale;

    /**************************************************************************/
    /* create a shadow bitmap of the original, sized to current output size   */
    /**************************************************************************/
    aptl[0] = ptlBotLeft;		   /* current output rect, dev coord  */
    aptl[1] = ptlTopRight;
    if (GpiConvert( hpsClient, CVTC_WORLD, CVTC_DEVICE, 2L, aptl) == GPI_ERROR)
	DispError(habMain,hwndClient);
    aptl[0].x -= ptlOffset.x;		   /* put bottom left at (0,0)	      */
    aptl[0].y -= ptlOffset.y;
    aptl[1].x -= ptlOffset.x;
    aptl[1].y -= ptlOffset.y;
#ifdef fred
    aptl[1].x -= ptlOffset.x - 1;	   /* correct for coordinate convert  */
    aptl[1].y -= ptlOffset.y - 1;
#endif
    aptl[2].x = 0L;
    aptl[2].y = 0L;
  if (pbmp2BitmapFile->cbFix  == sizeof(BITMAPINFOHEADER))
     {
    aptl[3].x = ((PBITMAPINFOHEADER)pbmp2BitmapFile)->cx;  /*bitmap dimensions	 */
    aptl[3].y = ((PBITMAPINFOHEADER)pbmp2BitmapFile)->cy;
     }
  else
     {
    aptl[3].x = pbmp2BitmapFile->cx;	    /* bitmap dimensions	       */
    aptl[3].y = pbmp2BitmapFile->cy;
     }
    if (GpiSetBitmap( hpsBitmapSize, hbmBitmapSize) == (HBITMAP)BMB_ERROR)
	DispError(habMain,hwndClient);
    if (GpiBitBlt( hpsBitmapSize	       /* copy the bitmap		  */
		 , hpsBitmapFile
		 , 4L
		 , aptl
		 , ROP_SRCCOPY
		 , BBO_IGNORE) == GPI_ERROR)
	DispError(habMain,hwndClient);

    for( psl = pslHead; psl != NULL; psl = psl->pslNext)
    {
      DosQueryEventSem( hevTerminate, &ulPostCt);
      if( ulPostCt) /* exit if quit   */
	break;

      DosQueryEventSem( hevKillDraw, &ulPostCt);
      if( ulPostCt != ulPostKillDraw) {
	break;
	}

      aptl[0].x = psl->rclBitBlt.xLeft;	    /* bounding rect in world space   */
      aptl[0].y = psl->rclBitBlt.yBottom;
      aptl[1].x = psl->rclBitBlt.xRight;
      aptl[1].y = psl->rclBitBlt.yTop;
      aptl[2] = aptl[0];
      aptl[3] = aptl[1];
      if (GpiConvert( hpsClient, CVTC_WORLD, CVTC_DEVICE, 2L, &aptl[2]) == GPI_ERROR)
	  DispError(habMain,hwndClient);
      ptlOrg = aptl[2];
      aptl[3].x -= ptlOrg.x - 1;	    /* bitmap rect of piece	      */
      aptl[3].y -= ptlOrg.y - 1;
      aptl[2].x = 0L;
      aptl[2].y = 0L;
      psl->aptlBitBlt[0] = aptl[0];
      psl->aptlBitBlt[1] = aptl[1];
      psl->aptlBitBlt[2] = aptl[2];
      psl->aptlBitBlt[3] = aptl[3];

      /************************************************************************/
      /* compute the piece control points				      */
      /************************************************************************/
      for ( l = 0; l < 12; l++)
	aptlSides[l] = psl->aptlSides[l];
      if (GpiConvert( hpsClient, CVTC_WORLD, CVTC_DEVICE, 12L, aptlSides) == GPI_ERROR)
	  DispError(habMain,hwndClient);
      for ( l = 0; l < 12; l++)
      {
	aptlSides[l].x -= ptlOrg.x;
	aptlSides[l].y -= ptlOrg.y;
      }

      /************************************************************************/
      /* prepare the mask to punch a hole in the output bitmap		      */
      /************************************************************************/
      if (GpiSetClipPath( psl->hpsHole, 0L, SCP_RESET)== GPI_ERROR)/* no clip path	    */
	  DispError(habMain,hwndClient);
      if (GpiBitBlt( psl->hpsHole			 /* fill with 1's         */
		   , NULLHANDLE
		   , 2L
		   , &psl->aptlBitBlt[2]
		   , ROP_ONE
		   , BBO_IGNORE) == GPI_ERROR)
	  DispError(habMain,hwndClient);

      if (GpiBeginPath( psl->hpsHole, 1L) == GPI_ERROR)	 /* define a clip path	  */
	  DispError(habMain,hwndClient);
      if (GpiMove( psl->hpsHole, &aptlSides[11]) == GPI_ERROR)
	  DispError(habMain,hwndClient);
      if (GpiPolySpline( psl->hpsHole, 12L, aptlSides) == GPI_ERROR)
	  DispError(habMain,hwndClient);
      if (GpiEndPath( psl->hpsHole) == GPI_ERROR)
	  DispError(habMain,hwndClient);
      if (GpiSetClipPath( psl->hpsHole, 1L, SCP_AND) == GPI_ERROR)
	  DispError(habMain,hwndClient);
      if (GpiBitBlt( psl->hpsHole			 /* fill with 0's         */
		   , NULLHANDLE
		   , 2L
		   , &psl->aptlBitBlt[2]
		   , ROP_ZERO
		   , BBO_IGNORE) == GPI_ERROR)
	  DispError(habMain,hwndClient);
      if (GpiSetClipPath( psl->hpsHole, 0L, SCP_RESET) == GPI_ERROR)  /* clear the clip path   */
	  DispError(habMain,hwndClient);

      /************************************************************************/
      /* prepare the mask to fill the hole in the output bitmap		      */
      /************************************************************************/
      aptl[0] = psl->aptlBitBlt[2];
      aptl[1] = psl->aptlBitBlt[3];
      aptl[2] = aptl[0];
      if (GpiBitBlt( psl->hpsFill			 /* make inverse of hole  */
		   , psl->hpsHole
		   , 3L
		   , aptl
		   , ROP_NOTSRCCOPY
		   , BBO_IGNORE) == GPI_ERROR)
	  DispError(habMain,hwndClient);

      aptl[0] = psl->aptlBitBlt[2];
      aptl[1] = psl->aptlBitBlt[3];
      aptl[2].x = ptlOrg.x - ptlOffset.x;	     /* pick the right part   */
      aptl[2].y = ptlOrg.y - ptlOffset.y;	     /* of the sized bitmap   */
      if (GpiBitBlt( psl->hpsFill			 /* fill with data	  */
		   , hpsBitmapSize
		   , 3L
		   , aptl
		   , ROP_SRCAND
		   , BBO_IGNORE) == GPI_ERROR)
	  DispError(habMain,hwndClient);
      if (GpiSetClipPath( psl->hpsFill, 0L, SCP_RESET) == GPI_ERROR)  /* clear the clip path   */
	  DispError(habMain,hwndClient);
      if (GpiSetColor( psl->hpsFill, CLR_RED) == GPI_ERROR)/* draw the outline	    */
	  DispError(habMain,hwndClient);
      if (GpiMove( psl->hpsFill, &aptlSides[11]) == GPI_ERROR)
	  DispError(habMain,hwndClient);
      if (GpiPolySpline( psl->hpsFill, 12L, aptlSides) == GPI_ERROR)
	  DispError(habMain,hwndClient);
      DrawPiece( hpsClient, psl, TRUE);
    }
  }
}

/******************************************************************************/
/*									      */
/* Redraw the entire client window.					      */
/*									      */
/******************************************************************************/
VOID Redraw(VOID)
{
  RECTL	  rclInvalid;
  HRGN	  hrgnUpdt;
  POINTL  aptlUpdtNew[3];

  WinQueryWindowRect( hwndClient, &rclInvalid);
  hrgnUpdt = GpiCreateRegion( hpsBitmapBuff, 1L, &rclInvalid);
  DoDraw( hpsBitmapBuff, hrgnUpdt, TRUE);
  if (GpiDestroyRegion( hpsBitmapBuff, hrgnUpdt) == GPI_ERROR)
     DispError(habMain,hwndClient);
  aptlUpdtNew[0].x = rclInvalid.xLeft;
  aptlUpdtNew[0].y = rclInvalid.yBottom;
  aptlUpdtNew[1].x = rclInvalid.xRight;
  aptlUpdtNew[1].y = rclInvalid.yTop;
  ROUND_DOWN_MOD( aptlUpdtNew[0].x, lByteAlignX);	  /* round down	      */
  ROUND_DOWN_MOD( aptlUpdtNew[0].y, lByteAlignY);	  /* round down	      */
  ROUND_UP_MOD(	  aptlUpdtNew[1].x, lByteAlignX);	  /* round up	      */
  ROUND_UP_MOD(	  aptlUpdtNew[1].y, lByteAlignY);	  /* round up	      */
  aptlUpdtNew[2] = aptlUpdtNew[0];

  if (!fFirstLoad)
  {
     if (GpiBitBlt( hpsClient
		  , hpsBitmapBuff
		  , 3L
		  , aptlUpdtNew
		  , ROP_SRCCOPY
		  , BBO_IGNORE ) == GPI_ERROR)
	 DispError(habMain,hwndClient);
  }   /* end if (!fFirstLoad) */
}

/******************************************************************************
*
*  Name	       : CorrelatePPOINTL
*
*  Description : perform bitmap-based correlation
*
*  Concepts    :
*
*  API's       :
*
*  Parameters  : PPOINTL pptl
*
*  Return      : PSEGLIST
*
******************************************************************************/

PSEGLIST Correlate(PPOINTL pptl)
{
   PSEGLIST  psl;
   POINTL    aptl[2];
   LONG	     lColor;
   RECTL     rcl;
   APIRET    rc;				    /* return code from APIs */


   aptl[0] = aptl[1] = *pptl;			  /* target lower-left point */

   aptl[1].x++;				  /* target bitmap upper-right point */
   aptl[1].y++;

   /*
    *  Set all hpsBitmapSave pels to 1.	 We're doing this so we can draw
    *  the correlated segment (if any) overtop of it.  Then, if the color
    *  didn't change, we know that we hit a clipped part of the segment
    *  (piece).
    */
   rc =
   GpiBitBlt(
      hpsBitmapSave,			 /* target presentation-space handle */
      NULLHANDLE,			 /* source presentation-space handle */
      2L,				 /* number of points in array	     */
      aptl,				 /* address of array		     */
      ROP_ONE,				 /* mixing method		     */
      BBO_IGNORE);			 /* line/column-compression flag     */

   if (rc  == GPI_ERROR)
      DispError(habMain,hwndClient);

   /*
    *  Retrieve color attribute for correlation point
    */

   lColor =						  /* should return 0 */
   GpiQueryPel(hpsBitmapSave, pptl);

   if (lColor == GPI_ALTERROR)
      DispError(habMain,hwndClient);

   /*
    *  Do a manual correlation by determining if the correlation point
    *  intersects the region occupied be each segment (piece).
    */

   for( psl = pslTail; psl != NULL; psl = psl->pslPrev)
   {
      /*
       *  get device coordinates for current segment (peice) bounding box
       */

      rcl = psl->rclCurrent;
      rc =
      GpiConvert(
	 hpsClient,		/* presentation-space handle		     */
	 CVTC_MODEL,		/* source coordinate space		     */
	 CVTC_DEVICE,		/* target coordinate space		     */
	 2L,			/* number of coordinate pairs in structure   */
	 (PPOINTL)&rcl);	/* address of structure for coordinate pairs */

      if (rc == GPI_ERROR)
	 DispError(habMain,hwndClient);

      rcl.xRight++;
      rcl.yTop++;

      /*
       *  Does the point fall inside this segment's (peice's) bounding box?
       *  If so, did the color of the pel change when we drew the piece?  If
       *  so, we selected a point inside this piece (segment) which isn't
       *  clipped.  Return it.
       */

      if (WinPtInRect(habAsync, &rcl, pptl))
      {
	  DrawPiece( hpsBitmapSave, psl, FALSE);      /* draw clipped bitmap */
	  if(GpiQueryPel( hpsBitmapSave, pptl) != lColor)   /* color change? */
	     break;						/* got a hit */
      }
   }   /* end for(all segments in our linked list) */

   return( psl);

}   /* end Correlate() */

/******************************************************************************/
/*									      */
/* mark a whole island							      */
/*									      */
/******************************************************************************/
VOID MarkIsland(PSEGLIST pslMark,BOOL fMark)
{
  PSEGLIST  psl;
  BOOL	    fFirst;

  for( psl = pslMark, fFirst = TRUE
     ; (psl != pslMark) || fFirst
     ; psl = psl->pslNextIsland, fFirst = FALSE )
      psl->fIslandMark = fMark;		      /* mark as island member	      */
}

/********************************  END MISC.C  *******************************/
