/* ***** BEGIN LICENSE BLOCK *****
 * Source last modified: $Id: sitetran.cpp,v 1.2.40.1 2004/07/09 01:59:28 hubbe Exp $
 * 
 * Portions Copyright (c) 1995-2004 RealNetworks, Inc. All Rights Reserved.
 * 
 * The contents of this file, and the files included with this file,
 * are subject to the current version of the RealNetworks Public
 * Source License (the "RPSL") available at
 * http://www.helixcommunity.org/content/rpsl unless you have licensed
 * the file under the current version of the RealNetworks Community
 * Source License (the "RCSL") available at
 * http://www.helixcommunity.org/content/rcsl, in which case the RCSL
 * will apply. You may also obtain the license terms directly from
 * RealNetworks.  You may not use this file except in compliance with
 * the RPSL or, if you have a valid RCSL with RealNetworks applicable
 * to this file, the RCSL.  Please see the applicable RPSL or RCSL for
 * the rights, obligations and limitations governing use of the
 * contents of the file.
 * 
 * Alternatively, the contents of this file may be used under the
 * terms of the GNU General Public License Version 2 or later (the
 * "GPL") in which case the provisions of the GPL are applicable
 * instead of those above. If you wish to allow use of your version of
 * this file only under the terms of the GPL, and not to allow others
 * to use your version of this file under the terms of either the RPSL
 * or RCSL, indicate your decision by deleting the provisions above
 * and replace them with the notice and other provisions required by
 * the GPL. If you do not delete the provisions above, a recipient may
 * use your version of this file under the terms of any one of the
 * RPSL, the RCSL or the GPL.
 * 
 * This file is part of the Helix DNA Technology. RealNetworks is the
 * developer of the Original Code and owns the copyrights in the
 * portions it created.
 * 
 * This file, and the files included with this file, is distributed
 * and made available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY
 * KIND, EITHER EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS
 * ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET
 * ENJOYMENT OR NON-INFRINGEMENT.
 * 
 * Technology Compatibility Kit Test Suite(s) Location:
 *    http://www.helixcommunity.org/content/tck
 * 
 * Contributor(s):
 * 
 * ***** END LICENSE BLOCK ***** */

#define _TRANSITIONS_ON_
//#define _TESTING_TRANITIONS_   

#ifdef _TESTING_TRANITIONS_
#define INITGUID    // this must be befor pntypes
#endif

#include "hxtypes.h" // this must be before windows.h

#ifdef _WIN32
#include "windows.h"
#endif

#define PI 3.14159265358979323846
#define Root2 1.414213562

#include <math.h>
#include <stdio.h>
#include <stdlib.h>

//#define NO_GRAPHICS

#include "hxcom.h"
#include "hxbuffer.h"
#include "hxassert.h"
#include "sitetran.h"
#include "region.h"
#include "poly.h"
#include "tranmat.h"
#include "hxstrutl.h"




//=======================================================================
//=======================================================================
//               All Transistion effects
//=======================================================================
//=======================================================================

void CopyRegion(HXREGION* dstrgn, HXREGION* rgn)
{
   if (dstrgn != rgn) /*  don't want to copy to itself */
   {  
      if (dstrgn->size < rgn->numRects)
      {
         if (dstrgn->rects)
         {
            HXBOX *prevRects = dstrgn->rects;
                
            if (! (dstrgn->rects = (HXBOX *)
                   realloc((char *) dstrgn->rects,
                           (unsigned) rgn->numRects * (sizeof(HXBOX))))) {
               free(prevRects);
               return;
            }
         }
         dstrgn->size = rgn->numRects;
      }
      dstrgn->numRects = rgn->numRects;
      dstrgn->extents.x1 = rgn->extents.x1;
      dstrgn->extents.y1 = rgn->extents.y1;
      dstrgn->extents.x2 = rgn->extents.x2;
      dstrgn->extents.y2 = rgn->extents.y2;

      memcpy((char *) dstrgn->rects, (char *) rgn->rects, /* Flawfinder: ignore */
             (int) (rgn->numRects * sizeof(HXBOX)));
   }
}


HXREGION* InvertRGN(HXREGION* in, int x, int y, int x1, int y1)
{
   HXREGION* retRGN = HXCreateRectRegion(x,y,x1 - x,y1 - y);
   HXCombineRgn(retRGN, retRGN, in, HX_RGN_DIFF);
   HXDestroyRegion(in);
   return retRGN;
}

int CompareRects(const void *arg1, const void *arg2)
{
   HXBOX* b1 = (HXBOX*)arg1;
   HXBOX* b2 = (HXBOX*)arg2;

   if (b1->y1 < b2->y1) 
      return -1;

   if (b1->y1 != b2->y1)
      return 1;

   if (b1->x1 < b2->x1)
      return -1;

   if (b1->x1 != b2->x1)
      return 1;

   return 0;
}

HXREGION* MirrorHorizontal(HXREGION* in, int y)
{
   int tmpY;

   for (int i = 0; i < in->numRects; ++i)
   {
      in->rects[i].y1 = 2 * y - in->rects[i].y1;
      in->rects[i].y2 = 2 * y - in->rects[i].y2;
        
      if (in->rects[i].y2 < in->rects[i].y1)
      {
         tmpY = in->rects[i].y1;
         in->rects[i].y1 = in->rects[i].y2;
         in->rects[i].y2 = tmpY;
      }
   }

   qsort((void*)in->rects, in->numRects, sizeof(HXBOX), CompareRects);

   return in;
}

HXREGION* MirrorVertical(HXREGION* in, int x)
{
   int tmpX;

   for (int i = 0; i < in->numRects; ++i)
   {
      in->rects[i].x1 = 2 * x - in->rects[i].x1;
      in->rects[i].x2 = 2 * x - in->rects[i].x2;
        
      if (in->rects[i].x2 < in->rects[i].x1)
      {
         tmpX = in->rects[i].x1;
         in->rects[i].x1 = in->rects[i].x2;
         in->rects[i].x2 = tmpX;
      }
      if( in->rects[i].x1 != 0 )
          in->rects[i].x1 = in->rects[i].x1 -1;
   }

   qsort((void*)in->rects, in->numRects, sizeof(HXBOX), CompareRects);

   return in;
}

void MirrorHorizontal(tranLines* lines, int y)
{
   for (int i = 0; i < lines->m_nLines; ++i)
   {
      lines->m_pLines[i].start.x = lines->m_pLines[i].start.x;
      lines->m_pLines[i].start.y = 2 * y - lines->m_pLines[i].start.y;
      lines->m_pLines[i].finish.x = lines->m_pLines[i].finish.x;
      lines->m_pLines[i].finish.y = 2 * y - lines->m_pLines[i].finish.y;
   }
}

void MirrorVertical(tranLines* lines, int x)
{
   for (int i = 0; i < lines->m_nLines; ++i)
   {
      lines->m_pLines[i].start.x = 2 * x - lines->m_pLines[i].start.x;
      lines->m_pLines[i].start.y = lines->m_pLines[i].start.y;
      lines->m_pLines[i].finish.x = 2 * x - lines->m_pLines[i].finish.x;
      lines->m_pLines[i].finish.y = lines->m_pLines[i].finish.y;
   }
}

tranLines::tranLines()
{
   m_nLines = 0;
   m_pLines = NULL;
}

tranLines::~tranLines()
{
   Destroy();
}


LineSegment::LineSegment(const LineSegment& ls)
{
   *this = ls;
}

void LineSegment::operator=(const LineSegment& right)
{
   start.x = right.start.x;
   start.y = right.start.y;
   finish.x = right.finish.x;
   finish.y = right.finish.y;
}

// returns TRUE if the line is within the boundary, FALSE if it lies completely outside
BOOL LineSegment::Clip(int left, int top, int right, int bottom)
{
   BOOL retVal = TRUE;
   double slope;

   // make sure our start is left of finish
   if (start.x > finish.x)
   {
      int tmp = start.x;
      start.x = finish.x;
      finish.x = tmp;

      tmp = start.y;
      start.y = finish.y;
      finish.y = tmp;
   }

   if (start.x > right || finish.x < left ||
       (start.y < top && finish.y < top) ||
       (start.y > bottom && finish.y > bottom))
   {
      retVal = FALSE;
      goto LineSegment_Clip_End;
   }

   slope = ((double)(finish.y - start.y + 1) / (double)(finish.x - start.x + 1));

   if (start.x < left)
   {
      start.y += int((left - start.x) * slope);
      start.x = left;
   }
   if (start.y > bottom)
   {
      start.x -= int((start.y - bottom) / slope);
      start.y = bottom;
   }
   if(start.y < top)
   {
      start.x += int((top - start.y) / slope);
      start.y = top;
   }

   if (finish.x > right)
   {
      finish.y -= int((finish.x - right) * slope);
      finish.x = right;
   }
   if (finish.y > bottom)
   {
      finish.x -= int((finish.y - bottom) / slope);
      finish.y = bottom;
   }
   if(finish.y < top)
   {
      finish.x += int((top - finish.y) / slope);
      finish.y = top;
   }

   if (start.x < left || start.x > right ||
       start.y < top || start.y > bottom ||
       finish.x < left || finish.x > right || 
       finish.y < top || finish.y > bottom)
   {
      //XXXSMJ currently there's a case were the line can exist with only
      // an endpoint on border.  This means only one pixel of the line is
      // inside the clipping region.  For now, we'll say this sucker is
      // clipped.
      retVal = FALSE;
   }

  LineSegment_Clip_End:
   return retVal;
}

tranLines* operator+(const tranLines& left, const tranLines& right)
{
   tranLines* newLines = const_cast<tranLines*>(&left);
    
   if (right.m_nLines)
   {
      newLines = new tranLines;
    
      newLines->m_nLines = left.m_nLines + right.m_nLines;
      newLines->m_pLines = new LineSegment[newLines->m_nLines];
    
      if (!newLines->m_pLines)
      {
         newLines->m_nLines = 0;
      }
      else
      {
         int i,c;
         for (i = 0, c = 0; i < left.m_nLines; ++i, ++c)
         {
            newLines->m_pLines[c] = left.m_pLines[i];
         }
         for (i = 0; i < right.m_nLines; ++i, ++c)
         {
            newLines->m_pLines[c] = right.m_pLines[i];
         }
      }
   }
   return newLines;
}

void tranLines::operator=(const tranLines& right)
{
   Copy(right);
}

void tranLines::operator+=(const tranLines& right)
{
   if (right.m_nLines)
   {
      tranLines* newLines = *this + right;
      Copy(*newLines);
    
      delete newLines;
   }
}

void tranLines::operator+=(const LineSegment& right)
{
   tranLines newLines;
    
   newLines.m_nLines = 1;
   newLines.m_pLines = new LineSegment[1];
    
   if (!newLines.m_pLines)
   {
      newLines.m_nLines = 0;
   }
   else
   {
      *newLines.m_pLines = right;
   }

   *this += newLines;
}

tranLines::tranLines(const tranLines& tl)
{
   m_nLines = 0;
   m_pLines = NULL;

   Copy(tl);
}

void tranLines::Copy(const tranLines& tl)
{
   Destroy();

   m_nLines = tl.m_nLines;

   if (m_nLines)
   {
      m_pLines = new LineSegment[m_nLines];

      for (int i = 0; i < m_nLines; ++i)
      {
         m_pLines[i] = tl.m_pLines[i];
      }
   }
}

void tranLines::Offset(int x, int y)
{
   for (int i = 0; i < m_nLines; ++i)
   {
      m_pLines[i].start.x += x;
      m_pLines[i].start.y += y;
      m_pLines[i].finish.x += x;
      m_pLines[i].finish.y += y;
   }
}

void tranLines::Destroy()
{
   if (m_pLines)
   {
      delete [] m_pLines;
      m_pLines = NULL;
   }

   m_nLines = 0;
}

void tranLines::Clip(int left, int top, int right, int bottom)
{
   int newlines = m_nLines;
   for (int i = 0; i < m_nLines; ++i)
   {
      if (!m_pLines[i].Clip(left, top, right, bottom))
      {
         // the line is not within our area so mark it for clipping
         m_pLines[i].start.x = m_pLines[i].start.y = m_pLines[i].finish.x = m_pLines[i].finish.y = -42;
         --newlines;
      }
   }

   if (newlines != m_nLines)  // do we need to remove any lines?
   {
      tranLines tmpLines;
      tmpLines.m_nLines = newlines;
      tmpLines.m_pLines = new LineSegment[newlines];

      for (int i = 0, c = 0; c < newlines; ++i)
      {
         if (m_pLines[i].start.x != -42 && m_pLines[i].start.y != -42 &&
             m_pLines[i].finish.x != -42 && m_pLines[i].finish.y != -42)
         {
            tmpLines.m_pLines[c++] = m_pLines[i];
         }
      }
   }
}

void GetDiagonalStripCoords(HXxPoint topLeft, HXxPoint topRight, HXxPoint bottomRight, HXxPoint bottomLeft, HXxPoint* topPoint, HXxPoint* bottomPoint, int completeness)
{
   int topWidth = topRight.x - topLeft.x;
   int bottomWidth = bottomRight.x - bottomLeft.x;
   int height = max(bottomLeft.y - topLeft.y, bottomRight.y - topRight.y);
   double angle;
    
   int length;
   int mark;
    
   if (topWidth > bottomWidth)
   {
      int rightHeight = topLeft.y - topRight.y;
      length = int(sqrt((double)(topWidth * topWidth + rightHeight * rightHeight)));
      mark = int(double(length * completeness) / 1000.0);
      angle = atan(double(topLeft.y - topRight.y) / double(topWidth));
        
      topPoint->x = int(topLeft.x + cos(angle) * mark);
      topPoint->y = int(topLeft.y - sin(angle) * mark);
        
      int length2 = int(sin(angle) * height);
        
      bottomPoint->x = topPoint->x + int(cos(angle) * length2 + 1);
      bottomPoint->y = topPoint->y + height - int(sin(angle) * length2);
   }
   else
   {
      int leftHeight = bottomLeft.y - bottomRight.y;
      length = int(sqrt((double)(bottomWidth * bottomWidth + leftHeight * leftHeight)));
      mark = int(double(length * completeness) / 1000.0);
      angle = atan(double(bottomLeft.y - bottomRight.y) / double(bottomWidth));
        
      bottomPoint->x = int(bottomLeft.x + cos(angle) * mark + 1);
      bottomPoint->y = int(bottomLeft.y - sin(angle) * mark);
        
      int length2 = int(sin(angle) * height);
        
      topPoint->x = bottomPoint->x - int(cos(angle) * length2 + 1);
      topPoint->y = bottomPoint->y - height + int(sin(angle) * length2);
   }
}

void PrintRgnData(HXREGION* retRGN)
{
#ifdef _WINDOWS
   FILE* f1 = ::fopen("d:\\expose.txt", "a+"); /* Flawfinder: ignore */
   LPRGNDATA    lpRgnData;
   DWORD sizeNeeed = GetRegionData((HRGN)retRGN, 0, NULL); 
   lpRgnData = (LPRGNDATA) new char[sizeNeeed];
   GetRegionData((HRGN)retRGN, sizeNeeed, lpRgnData); 
   for(int j = 0; j < (int) lpRgnData->rdh.nCount;j++)
   {
      HXRECTANGLE* pRect = (HXRECTANGLE*) lpRgnData->Buffer;
      ::fprintf(f1, "Rect (%d, %d) -(%d, %d)\n", pRect[j].x, pRect[j].y, pRect[j].width, pRect[j].height);
   }
   delete lpRgnData;
   fclose(f1);
#else
   HX_ASSERT(!"cant print rgn data");
#endif
}


//#define _TESTING_TRANITIONS_
/* 
 * Table of all transition effects
 */
//          {DefaultTransition, ""},

#ifdef _TRANSITIONS_ON_

tranStruct z_barWipeTable[] =
{
   {EdgeWipe, 1,"leftToRight"},
   {SlideVerticalEdgeWipe, 2, "topToBottom"}
};

tranStruct z_boxWipeTable[] =
{
   {TopLeftEdgeWipe, 3, "topLeft"},
   {TopRightEdgeWipe, 4, "topRight"},
   {BottomRightEdgeWipe, 5, "bottomRight"},
   {BottomLeftEdgeWipe, 6, "bottomLeft"},
   {TopCenterEdgeWipe, 23, "topCenter"},
   {CenterRightEdgeWipe, 24, "rightCenter"},
   {BottomCenterEdgeWipe, 25, "bottomCenter"},
   {LeftCenterEdgeWipe, 26, "leftCenter"}
};

tranStruct z_fourBoxTable[] =
{
   {FourCornerEdgeWipe, 7, "cornersIn"},
   {FourBoxEdgeWipe , 8, "cornersOut"}
};

tranStruct z_barnDoorTable[] =
{
   {BarnVerticalEdgeWipe , 21, "vertical"},
   {BarnHorizontalEdgeWipe, 22, "horizontal"},
   {DiagonaLeftOutEdgeWipe, 45, "diagonalBottomLeft"},
   {DiagonaRightOutEdgeWipe, 46, "diagonalTopLeft"}
};    

tranStruct z_diagonalTable[] =
{
   {DiagonalLeftDownEdgeWipe, 41, "topLeft"},
   {DiagonalRightDownEdgeWipe, 42, "topRight"}
};

tranStruct z_bowTieTable[] =
{
   {VerticalBowTieEdgeWipe, 43, "vertical"},
   {HorizontalBowTieEdgeWipe, 44, "horizontal"}
};

tranStruct z_miscDiagonalTable[] =
{
   {DiagonaCrossEdgeWipe, 47, "doubleBarnDoor"},
   {DiagonalBoxEdgeWipe, 48, "doubleDiamond"}
};

tranStruct z_veeTable[] =
{
   {FilledVEdgeWipe, 61, "down"},
   {FilledVRightEdgeWipe, 62, "left"},
   {FilledVBottomEdgeWipe, 63, "up"},
   {FilledVLeftEdgeWipe, 64, "right"}
};

tranStruct z_barnVeeTable[] =
{
   {HollowVEdgeWipe, 65, "down"},
   {HollowVRightEdgeWipe, 66, "left"},
   {HollowVBottomEdgeWipe , 67, "up"},
   {HollowVLeftEdgeWipe, 68, "right"}
};

tranStruct z_zigZagTable[] =
{
   {VerticalZigZagEdgeWipe, 71, "leftToRight"},
   {HorizontalZigZagEdgeWipe, 72, "topToBottom"}
};

tranStruct z_barnZigZagTable[] =
{
   {VerticalBarnZigZagEdgeWipe, 73, "vertical"},
   {HorizontalBarnZigZagEdgeWipe, 74, "horizontal"}
};

//-----------------------------------------------------------------------
tranStruct z_irisTable[] =
{
   {RectangleIris, 101, "rectangle"},
   {DiamondIris, 102, "diamond"}
};

tranStruct z_triangleTable[] =
{
   {TriangleIris, 103, "up"},
   {TriangleRightIris, 104, "right"},
   {TriangleUpsideDownIris, 105, "down"},
   {TriangleLeftIris, 106, "left"}
};

tranStruct z_arrowHeadTable[] =
{
   {ArrowHeadIris, 107, "up"},
   {ArrowHeadRightIris, 108, "right"},
   {ArrowHeadUpsideDownIris, 109, "down"},
   {ArrowHeadLeftIris, 110, "left"}
};

tranStruct z_pentagonTable[] =
{
   {PentagonIris, 111, "up"},
   {PentagonUpsideDownLeftIris, 112, "down"}
};

tranStruct z_hexagonTable[] =
{
   {HexagonSideIris, 113, "horizontal"},
   {HexagonIris, 114, "vertical"}
};

tranStruct z_ellipseTable[] =
{
   {CircleIris, 119, "circle"},
   {OvalIris, 120, "horizontal"},
   {OvalSideIris, 121, "vertical"}
};

tranStruct z_eyeTable[] =
{
   {CatEyeIris, 122, "horizontal"},
   {CatEyeSideIris, 123, "vertical"}
};

tranStruct z_roundRectTable[] =
{
   {RoundRectHorizontal, 124, "horizontal"},
   {RoundRectVeritical, 125, "vertical"}
};

tranStruct z_starTable[] =
{
   {FourPointStarIris, 127, "fourPoint"},
   {FivePointStarIris, 128, "fivePoint"},
   {SixPointStarIris, 129, "sixPoint"}
};

tranStruct z_miscShapeTable[] =
{
   {HeartIris, 130, "heart"},
   {KeyHoleIris, 131, "keyhole"}
};

//-----------------------------------------------------------------------
tranStruct z_clockTable[] =
{
   {RotatingTopRadial, 201, "clockwiseTwelve"},
   {RotatingRightRadial, 202, "clockwiseThree"},
   {RotatingBottomRadial , 203, "clockwiseSix"},
   {RotatingLeftRadial, 204, "clockwiseNine"}
};

tranStruct z_pinWheelTable[] =
{
   {RotatingTopBottomRadial, 205, "twoBladeVertical"},
   {RotatingLeftRightRadial, 206, "twoBladeHorizontal"},
   {RotatingQuadrantRadial, 207, "fourBlade"}
};

tranStruct z_singleSweepTable[] =
{
   {Top180Radial, 221, "clockwiseTop"},
   {Right180Radial, 222, "clockwiseRight"},
   {Bottom180Radial, 223, "clockwiseBottom"},
   {Left180Radial, 224, "clockwiseLeft"},
   {RotatingTopLeftRadial, 241, "clockwiseTopLeft"},
   {RotatingBottomLeftRadial, 242, "counterClockwiseBottomLeft"},
   {RotatingBottomRightRadial, 243, "clockwiseBottomRight"},
   {RotatingTopRightRadial, 244, "counterClockwiseTopRight"}
};

tranStruct z_fanTable[] =
{
    
   {TopBottom180Radial, 211, "centerTop"},
   {RightToLeft180Radial, 212, "centerRight"},
   {OpenVTopRadial, 231, "top"},
   {OpenVRightRadial, 232, "right"},
   {OpenVBottomRadial, 233, "bottom"},
   {OpenVLeftRadial, 234, "left"},
};

tranStruct z_doubleFanTable[] =
{
   {topBottom90Radial, 213, "fanOutVertical"},
   {RightToLeft90Radial, 214, "fanOutHorizontal"},
   {OpenVTopBottomRadial, 235, "fanInVertical"},
   {OpenVLeftRightRadial, 236, "fanInHorizontal"}
};

tranStruct z_doubleSweepTable[] =
{
   {CounterRotatingTopBottomRadial, 225, "parallelVertical"},
   {CounterRotatingLeftRightRadial, 226, "parallelDiagonal"},
   {DoubleRotatingTopBottomRadial, 227, "oppositeVertical"},
   {DoubleRotatingLeftRightRadial, 228, "oppositeHorizontal"},
   {RotatingTopLeftBottomRightRadial, 245, "parallelDiagonalTopLeft"},
   {RotatingBottomLeftTopRightRadial, 246, "parallelDiagonalBottomLeft"}
};

tranStruct z_saloonDoorTable[] =
{
   {RotatingTopLeftRightRadial, 251, "top"},
   {RotatingLeftTopBottomRadial, 252, "left"},
   {RotatingBottomLeftRightRadial, 253, "bottom"},
   {RotatingRightTopBottomRadial, 254, "right"}
};

tranStruct z_windshieldTable[] =
{
   {RotatingDoubleCenterRightRadial, 261, "right"},
   {RotatingDoubleCenterTopRadial, 262, "up"},
   {RotatingDoubleCenterTopBottomRadial, 263, "vertical"},
   {RotatingDoubleCenterLeftRightRadial, 264, "horizontal"}
};

//-----------------------------------------------------------------------
tranStruct z_snakeTable[] =
{
   {HorizontalMatrix, 301, "topLeftHorizontal"},
   {VerticalMatrix, 302, "topLeftVertical"},
   {TopLeftDiagonalMatrix, 303, "topLeftDiagonal"},
   {TopRightDiagonalMatrix, 304, "topRightDiagonal"},
   {BottomRightDiagonalMatrix, 305, "bottomRightDiagonal"},
   {BottomLeftDiagonalMatrix, 306, "bottomLeftDiagonal"}
};

tranStruct z_spiralTable[] =
{
   {ClockwiseTopLeftMatrix, 310, "topLeftClockwise"},
   {ClockwiseTopRightMatrix, 311, "topRightClockwise"},
   {ClockwiseBottomRightMatrix, 312, "bottomRightClockwise"},
   {ClockwiseBottomLeftMatrix, 313, "bottomLeftClockwise"},
   {CounterClockwiseTopLeftMatrix, 314, "topLeftCounterClockwise"},
   {CounterClockwiseTopRightMatrix, 315, "topRightCounterClockwise"},
   {CounterClockwiseBottomRightMatrix, 316, "bottomRightCounterClockwise"},
   {CounterClockwiseBottomLeftMatrix, 317, "bottomLeftCounterClockwise"}
};

tranStruct z_parallelSnakesTable[] =
{
   {VerticalStartTopMatrix, 320, "verticalTopSame"},
   {VerticalStartBottomMatrix, 321, "verticalBottomSame"},
   {VerticalStartTopOppositeMatrix, 322, "verticalTopLeftOpposite"},
   {VerticalStartBottomOppositeMatrix, 323, "verticalBottomLeftOpposite"},
   {HorizontalStartLeftMatrix, 324, "horizontalLeftSame"},
   {HorizontalStartRightMatrix, 325, "horizontalRightSame"},
   {HorizontalStartLeftOppositeMatrix, 326, "horizontalTopLeftOpposite"},
   {HorizontalStartRightOppositeMatrix, 327, "horizontalTopRightOpposite"},
   {DoubleDiagonalBottom, 328, "diagonalBottomLeftOpposite"},
   {DoubleDiagonalTop, 329, "diagonalTopLeftOpposite"}
};

tranStruct z_boxSnakesTable[] =
{
   {DoubleSpiralTopMatrix, 340, "twoBoxTop"},
   {DoubleSpiralBottomMatrix, 341, "twoBoxBottom"},
   {DoubleSpiralLeftMatrix, 342, "twoBoxLeft"},
   {DoubleSpiralRightMatrix, 343, "twoBoxRight"},
   {QuadSpiralVerticalMatrix, 344, "fourBoxVertical"},
   {QuadSpiralHorizontalMatrix, 345, "fourBoxHorizontal"}
};

tranStruct z_waterfallTable[] =
{
   {VerticalWaterfallLeftMatrix, 350, "verticalLeft"},
   {VerticalWaterfallRightMatrix, 351, "verticalRight"},
   {HorizontalWaterfallLeftMatrix, 352, "horizontalLeft"},
   {HorizontalWaterfallRightMatrix, 353, "horizontalRight"}
};

//-----------------------------------------------------------------------
tranStruct z_slideTable[] =
{
   {SlideFromLeft, -1, "fromLeft"},
   {SlideFromTop, -1, "fromTop"},
   {SlideFromRight, -1, "fromRight"},
   {SlideFromBottom, -1, "fromBottom"}
};

tranStruct z_fadeTable[] =
{
   {Crossfade,     -1, "crossfade"},
   {FadeToColor,   -1, "fadeToColor"},
   {FadeFromColor, -1, "fadeFromColor"}
};

tranStruct z_defaultTable[] =
{
   {DefaultTransition, -1, "DefaultTransition"}
};


//////////////////////////////////////
#endif  //_TRANSITIONS_ON_



tranType z_TransitionTable[] = 
{
   {z_defaultTable, "noTransition", sizeof(z_defaultTable) / sizeof(z_defaultTable[0])},
        
#ifdef _TRANSITIONS_ON_
        
   {z_barWipeTable, "barWipe", sizeof(z_barWipeTable) / sizeof(z_barWipeTable[0])},
   {z_boxWipeTable, "boxWipe", sizeof(z_boxWipeTable) / sizeof(z_boxWipeTable[0])},
   {z_fourBoxTable, "fourBoxWipe", sizeof(z_fourBoxTable) / sizeof(z_fourBoxTable[0])},
   {z_barnDoorTable, "barnDoorWipe", sizeof(z_barnDoorTable) / sizeof(z_barnDoorTable[0])},
   {z_diagonalTable, "diagonalWipe", sizeof(z_diagonalTable) / sizeof(z_diagonalTable[0])},
   {z_bowTieTable, "bowTieWipe", sizeof(z_bowTieTable) / sizeof(z_bowTieTable[0])},
   {z_miscDiagonalTable, "miscDiagonalWipe", sizeof(z_miscDiagonalTable) / sizeof(z_miscDiagonalTable[0])},
   {z_veeTable, "veeWipe", sizeof(z_veeTable) / sizeof(z_veeTable[0])},
   {z_barnVeeTable, "barnVeeWipe", sizeof(z_barnVeeTable) / sizeof(z_barnVeeTable[0])},
   {z_zigZagTable, "zigZagWipe", sizeof(z_zigZagTable) / sizeof(z_zigZagTable[0])},
   {z_barnZigZagTable, "barnZigZagWipe", sizeof(z_barnZigZagTable) / sizeof(z_barnZigZagTable[0])},
   {z_irisTable, "irisWipe", sizeof(z_irisTable) / sizeof(z_irisTable[0])},
   {z_triangleTable, "triangleWipe", sizeof(z_triangleTable) / sizeof(z_triangleTable[0])},
   {z_arrowHeadTable, "arrowHeadWipe", sizeof(z_arrowHeadTable) / sizeof(z_arrowHeadTable[0])},
   {z_pentagonTable, "pentagonWipe", sizeof(z_pentagonTable) / sizeof(z_pentagonTable[0])},
   {z_hexagonTable, "hexagonWipe", sizeof(z_hexagonTable) / sizeof(z_hexagonTable[0])},
   {z_ellipseTable, "ellipseWipe", sizeof(z_ellipseTable) / sizeof(z_ellipseTable[0])},
   {z_eyeTable, "eyeWipe", sizeof(z_eyeTable) / sizeof(z_eyeTable[0])},
   {z_roundRectTable, "roundRectWipe", sizeof(z_roundRectTable) / sizeof(z_roundRectTable[0])},
   {z_starTable, "starWipe", sizeof(z_starTable) / sizeof(z_starTable[0])},
   {z_miscShapeTable, "miscShapeWipe", sizeof(z_miscShapeTable) / sizeof(z_miscShapeTable[0])},
   {z_clockTable, "clockWipe", sizeof(z_clockTable) / sizeof(z_clockTable[0])},
   {z_pinWheelTable, "pinWheelWipe", sizeof(z_pinWheelTable) / sizeof(z_pinWheelTable[0])},
   {z_singleSweepTable, "singleSweepWipe", sizeof(z_singleSweepTable) / sizeof(z_singleSweepTable[0])},
   {z_fanTable, "fanWipe", sizeof(z_fanTable) / sizeof(z_fanTable[0])},
   {z_doubleFanTable, "doubleFanWipe", sizeof(z_doubleFanTable) / sizeof(z_doubleFanTable[0])},
   {z_doubleSweepTable, "doubleSweepWipe", sizeof(z_doubleSweepTable) / sizeof(z_doubleSweepTable[0])},
   {z_saloonDoorTable, "saloonDoorWipe", sizeof(z_saloonDoorTable) / sizeof(z_saloonDoorTable[0])},
   {z_windshieldTable, "windshieldWipe", sizeof(z_windshieldTable) / sizeof(z_windshieldTable[0])},
   {z_snakeTable, "snakeWipe", sizeof(z_snakeTable) / sizeof(z_snakeTable[0])},
   {z_spiralTable, "spiralWipe", sizeof(z_spiralTable) / sizeof(z_spiralTable[0])},
   {z_parallelSnakesTable, "parallelSnakesWipe", sizeof(z_parallelSnakesTable) / sizeof(z_parallelSnakesTable[0])},
   {z_boxSnakesTable, "boxSnakesWipe", sizeof(z_boxSnakesTable) / sizeof(z_boxSnakesTable[0])},
   {z_waterfallTable, "waterfallWipe", sizeof(z_waterfallTable) / sizeof(z_waterfallTable[0])},
   {z_slideTable, "slideWipe", sizeof(z_slideTable) / sizeof(z_slideTable[0])},
   {z_fadeTable, "fade", sizeof(z_fadeTable) / sizeof(z_fadeTable[0])}
#endif //_TRANSITIONS_ON_
};

INT32 z_nNumberTransitionTypes = sizeof(z_TransitionTable) / sizeof(z_TransitionTable[0]);

#ifdef _TRANSITIONS_ON_


void CalcMatrixLines(tranLines* lines, LineSegment* src, LineSegment* mod, BOOL* blocked)
{
   LineSegment ls;

   *blocked = TRUE;

   lines->Destroy();

   if (src->start.y == src->finish.y) // horizontal lines
   {
      if (mod->start.x <= src->start.x && mod->finish.x >= src->start.x && mod->finish.x < src->finish.x)
      {
         ls.start.x = mod->finish.x;
         ls.finish.x = src->finish.x;
         ls.start.y = ls.finish.y = src->start.y;

         *lines += ls;
      }
      else if (mod->start.x <= src->finish.x && mod->start.x > src->start.x && mod->finish.x >= src->finish.x)
      {
         ls.start.x = src->start.x;
         ls.finish.x = mod->start.x;
         ls.start.y = ls.finish.y = src->start.y;

         *lines += ls;
      }
      else if (mod->start.x > src->start.x && mod->finish.x < src->finish.x)
      {
         ls.start.x = mod->finish.x;
         ls.finish.x = src->finish.x;
         ls.start.y = ls.finish.y = src->start.y;

         *lines += ls;

         ls.start.x = src->start.x;
         ls.finish.x = mod->start.x;
         ls.start.y = ls.finish.y = src->start.y;

         *lines += ls;
      }
      else if (mod->start.x >= src->finish.x || mod->finish.x <= src->start.x)
      {
         *blocked = FALSE;
      }
   }
   else                            // vertical lines
   {
      if (mod->start.y < src->start.y && mod->finish.y >= src->start.y && mod->finish.y < src->finish.y)
      {
         ls.start.y = mod->finish.y;
         ls.finish.y = src->finish.y;
         ls.start.x = ls.finish.x = src->start.x;

         *lines += ls;
      }
      else if (mod->start.y < src->finish.y && mod->start.y > src->start.y && mod->finish.y >= src->finish.y)
      {
         ls.start.y = src->start.y;
         ls.finish.y = mod->start.y;
         ls.start.x = ls.finish.x = src->start.x;

         *lines += ls;
      }
      else if (mod->start.y > src->start.y && mod->finish.y < src->finish.y)
      {
         ls.start.y = mod->finish.y;
         ls.finish.y = src->finish.y;
         ls.start.x = ls.finish.x = src->start.x;

         *lines += ls;

         ls.start.y = src->start.y;
         ls.finish.y = mod->start.y;
         ls.start.x = ls.finish.x = src->start.x;

         *lines += ls;
      }
      else if (mod->start.y >= src->finish.y || mod->finish.y <= src->start.y)
      {
         *blocked = FALSE;
      }
   }
}

void CalcMatrixLines(tranLines* newLines, tranLines* src, LineSegment* mod, BOOL* blocked)
{
   tranLines tmpLines;

   newLines->Destroy();

   //XXXSMJ this is not foolproof but will be good enough for our current needs
   for (int i = 0; i < src->m_nLines; ++i)
   {
      CalcMatrixLines(&tmpLines,&src->m_pLines[i],mod,blocked);

      if (!tmpLines.m_nLines) // this happens when lines don't obstruct each other
         *newLines += src->m_pLines[i];
      else
         *newLines += tmpLines;
   }
}

void CalcMatrixBlockCoords(int left, int top, int right, int bottom, MatrixTransitionData *pData, int block, int* blockLeft, int* blockTop, int* blockRight, int* blockBottom)
{
   double blockX = double(right - left + 1) / double(pData->GetWidth());
   double blockY = double(bottom - top + 1) / double(pData->GetHeight());
    
   *blockLeft = int(left + blockX * (block % pData->GetWidth()));
   *blockTop = int(top + blockY * (block / pData->GetWidth()));
   *blockRight = int(left + blockX * (block % pData->GetWidth() + 1));
   *blockBottom = int(top + blockY * (block / pData->GetWidth() + 1));
 
   if (*blockLeft < left) *blockRight = left;
   if (*blockTop < top) *blockBottom = top;
   if (*blockRight > right) *blockRight = right;
   if (*blockBottom > bottom) *blockBottom = bottom;
}

HXREGION* MatrixTransition(int left, int top, int right, int bottom, int completeness, MatrixTransitionData *pData, tranLines* lines)
{
   HXREGION* retRGN = HXCreateRegion();
   HXREGION* rgn1;
    
   int bLeft,bTop,bRight,bBottom;
   double frameLength = 1000.0 / pData->GetTransitionLength();
   int frame = (int)((float)completeness/(frameLength+0.1));
   MatrixBlockTransitionList* blockTransList = pData->GetTransactionListPtr();
   for (int i = 0; i < frame; ++i)
   {
      MatrixBlockTransition* transList = blockTransList[i].GetListPtr();
      for (int j = 0; j < blockTransList[i].GetSize(); ++j)
      {
         // these will all be completed blocks
         CalcMatrixBlockCoords(left,top,right,bottom,pData,transList[j].block,&bLeft,&bTop,&bRight,&bBottom);
         rgn1 = HXCreateRectRegion(bLeft,bTop,bRight-bLeft,bBottom-bTop);
         HXCombineRgn(retRGN, rgn1, retRGN, HX_RGN_OR);
         HXDestroyRegion(rgn1);
      }
   }
    
   int tmpCompleteness = int((completeness - frameLength * frame) / frameLength * 1000);
   MatrixBlockTransition* transList = blockTransList[frame].GetListPtr();
   for (int j = 0; j < blockTransList[frame].GetSize(); ++j)
   {
      CalcMatrixBlockCoords(left,top,right,bottom,pData,transList[j].block,&bLeft,&bTop,&bRight,&bBottom);
        
      if (transList[j].invert)
      {
         rgn1 = transList[j].transition(bLeft,bTop,bRight,bBottom,1000 - tmpCompleteness,lines);
         rgn1 = InvertRGN(rgn1,bLeft,bTop,bRight,bBottom);
      }
      else
      {
         rgn1 = transList[j].transition(bLeft,bTop,bRight,bBottom,tmpCompleteness,lines);
      }
            
      HXCombineRgn(retRGN, rgn1, retRGN, HX_RGN_OR);
      HXDestroyRegion(rgn1);
   }

   if (lines)
   {
      BOOL blocked,tmpBlock;
      LineSegment lineSeg1, lineSeg2;
      tranLines tmpLines;

      for (int x = 0; x < retRGN->numRects; ++x)
      {
         // top
         if (retRGN->rects[x].y1 > top)
         {
            tranLines   tl;
            blocked = tmpBlock = FALSE;

            lineSeg1.start.x = retRGN->rects[x].x1;
            lineSeg1.start.y = retRGN->rects[x].y1;
            lineSeg1.finish.x = retRGN->rects[x].x2;
            lineSeg1.finish.y = retRGN->rects[x].y1;

            for (int y = 0; y < x; ++y)
            {
               if (retRGN->rects[y].y2 == retRGN->rects[x].y1)
               {
                  lineSeg2.start.x = retRGN->rects[y].x1;
                  lineSeg2.start.y = retRGN->rects[y].y2;
                  lineSeg2.finish.x = retRGN->rects[y].x2;
                  lineSeg2.finish.y = retRGN->rects[y].y2;

                  if (tl.m_nLines)
                  {
                     CalcMatrixLines(&tmpLines, &tl, &lineSeg2, &tmpBlock);
                     tl = tmpLines;
                  }
                  else
                  {
                     CalcMatrixLines(&tmpLines, &lineSeg1, &lineSeg2, &tmpBlock);
                     tl += tmpLines;
                  }

                  // once we're blocked we don't want to be changed
                  if (tmpBlock)
                     blocked = TRUE;
               }
            }
            if (!blocked && !tl.m_nLines)
            {
               tl += lineSeg1;
            }
            *lines += tl;
         }
         // right
         if (retRGN->rects[x].x2 < right)
         {
            tranLines   tl;
            blocked = tmpBlock = FALSE;

            lineSeg1.start.x = retRGN->rects[x].x2;
            lineSeg1.start.y = retRGN->rects[x].y1;
            lineSeg1.finish.x = retRGN->rects[x].x2;
            lineSeg1.finish.y = retRGN->rects[x].y2;

            for (int y = 0; y < retRGN->numRects; ++y)
            {
               if (retRGN->rects[y].x1 == retRGN->rects[x].x2)
               {
                  lineSeg2.start.x = retRGN->rects[y].x1;
                  lineSeg2.start.y = retRGN->rects[y].y1;
                  lineSeg2.finish.x = retRGN->rects[y].x1;
                  lineSeg2.finish.y = retRGN->rects[y].y2;

                  if (tl.m_nLines)
                  {
                     CalcMatrixLines(&tmpLines, &tl, &lineSeg2, &tmpBlock);
                     tl = tmpLines;
                  }
                  else
                  {
                     CalcMatrixLines(&tmpLines, &lineSeg1, &lineSeg2, &tmpBlock);
                     tl += tmpLines;
                  }

                  // once we're blocked we don't want to be changed
                  if (tmpBlock)
                     blocked = TRUE;
               }
            }
            if (!blocked && !tl.m_nLines)
            {
               tl += lineSeg1;
            }
            *lines += tl;
         }
         // bottom
         if (retRGN->rects[x].y2 < bottom)
         {
            tranLines   tl;
            blocked = tmpBlock = FALSE;

            lineSeg1.start.x = retRGN->rects[x].x1;
            lineSeg1.start.y = retRGN->rects[x].y2;
            lineSeg1.finish.x = retRGN->rects[x].x2;
            lineSeg1.finish.y = retRGN->rects[x].y2;

            for (int y = 0; y < retRGN->numRects; ++y)
            {
               if (retRGN->rects[y].y1 == retRGN->rects[x].y2)
               {
                  lineSeg2.start.x = retRGN->rects[y].x1;
                  lineSeg2.start.y = retRGN->rects[y].y1;
                  lineSeg2.finish.x = retRGN->rects[y].x2;
                  lineSeg2.finish.y = retRGN->rects[y].y1;

                  if (tl.m_nLines)
                  {
                     CalcMatrixLines(&tmpLines, &tl, &lineSeg2, &tmpBlock);
                     tl = tmpLines;
                  }
                  else
                  {
                     CalcMatrixLines(&tmpLines, &lineSeg1, &lineSeg2, &tmpBlock);
                     tl += tmpLines;
                  }

                  // once we're blocked we don't want to be changed
                  if (tmpBlock)
                     blocked = TRUE;
               }
            }
            if (!blocked && !tl.m_nLines)
            {
               tl += lineSeg1;
            }
            *lines += tl;
         }
         // left
         if (retRGN->rects[x].x1 > left)
         {
            tranLines   tl;
            blocked = tmpBlock = FALSE;

            lineSeg1.start.x = retRGN->rects[x].x1;
            lineSeg1.start.y = retRGN->rects[x].y1;
            lineSeg1.finish.x = retRGN->rects[x].x1;
            lineSeg1.finish.y = retRGN->rects[x].y2;

            for (int y = 0; y < retRGN->numRects; ++y)
            {
               if (retRGN->rects[y].x2 == retRGN->rects[x].x1)
               {
                  lineSeg2.start.x = retRGN->rects[y].x2;
                  lineSeg2.start.y = retRGN->rects[y].y1;
                  lineSeg2.finish.x = retRGN->rects[y].x2;
                  lineSeg2.finish.y = retRGN->rects[y].y2;

                  if (tl.m_nLines)
                  {
                     CalcMatrixLines(&tmpLines, &tl, &lineSeg2, &tmpBlock);
                     tl = tmpLines;
                  }
                  else
                  {
                     CalcMatrixLines(&tmpLines, &lineSeg1, &lineSeg2, &tmpBlock);
                     tl += tmpLines;
                  }

                  // once we're blocked we don't want to be changed
                  if (tmpBlock)
                     blocked = TRUE;
               }
            }
            if (!blocked && !tl.m_nLines)
            {
               tl += lineSeg1;
            }
            *lines += tl;
         }
      }
   }
    
   return retRGN;
}

HXREGION* HorizontalMatrix(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   static CHXBuffer* z_HorizontalMatrixDataBuffer = NULL;
        
   if (!z_HorizontalMatrixDataBuffer || completeness == MATRIX_TRANSITION_INIT)
   {
      MatrixTransitionData* HorizontalMatrixTransition = new MatrixTransitionData(8,8,64);
      MatrixBlockTransitionList* blockTransList = HorizontalMatrixTransition->GetTransactionListPtr();
                
      for (int i = 0; i < 64; ++i)
      {
         blockTransList[i].CreateList(1);
         MatrixBlockTransition* list = blockTransList[i].GetListPtr();

         list->invert = ((i / 8) & 1);
         if (list->invert)      // determine if row we're in is odd; the top row is row 0
            list->block = ((i / 8) + 1) * 8 - (i % 8) - 1;  // if we're odd we're moving right to left
         else
            list->block = i;  // otherwise left to right

         list->transition = EdgeWipe;
      }
                
      z_HorizontalMatrixDataBuffer = new CHXBuffer();
      z_HorizontalMatrixDataBuffer->AddRef();
      z_HorizontalMatrixDataBuffer->Set((UCHAR*)&HorizontalMatrixTransition, sizeof(UCHAR*));
   }
   else if (completeness == MATRIX_TRANSITION_DELETE)
   {
      delete *((MatrixTransitionData**)z_HorizontalMatrixDataBuffer->GetBuffer());
      if (!z_HorizontalMatrixDataBuffer->Release())
      {
         z_HorizontalMatrixDataBuffer = NULL;
         return HXCreateRegion();
      }
   }
        
   return MatrixTransition(left,top,right,bottom,completeness,
                           *((MatrixTransitionData**)z_HorizontalMatrixDataBuffer->GetBuffer()),lines);
}

HXREGION* VerticalMatrix(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   static CHXBuffer* z_VerticalMatrixDataBuffer = NULL;
        
   if (!z_VerticalMatrixDataBuffer || completeness == MATRIX_TRANSITION_INIT)
   {
      MatrixTransitionData* VerticalMatrixTransition = new MatrixTransitionData(8,8,64);
      MatrixBlockTransitionList* blockTransList = VerticalMatrixTransition->GetTransactionListPtr();
                
      for (int i = 0; i < 64; ++i)
      {
         blockTransList[i].CreateList(1);
         MatrixBlockTransition* list = blockTransList[i].GetListPtr();
                        
         list->invert = (i / 8) & 1;
                        
         if (list->invert)      // determine if column we're in is odd; the left col is col 0
            list->block = ((7 - i % 8) % 8) * 8 + i / 8;
         else
            list->block = (i % 8) * 8 + i / 8;
                        
         list->transition = SlideVerticalEdgeWipe;
      }
                
      z_VerticalMatrixDataBuffer = new CHXBuffer();
      z_VerticalMatrixDataBuffer->AddRef();
      z_VerticalMatrixDataBuffer->Set((UCHAR*)&VerticalMatrixTransition, sizeof(UCHAR*));
   }
   else if (completeness == MATRIX_TRANSITION_DELETE)
   {
      delete *((MatrixTransitionData**)z_VerticalMatrixDataBuffer->GetBuffer());
      if (!z_VerticalMatrixDataBuffer->Release())
      {
         z_VerticalMatrixDataBuffer = NULL;
         return HXCreateRegion();
      }
   }
        
   return MatrixTransition(left,top,right,bottom,completeness,*((MatrixTransitionData**)z_VerticalMatrixDataBuffer->GetBuffer()),lines);
}

void GetTopLeftDiagonalCoords(int left, int top, int right, int bottom, int completeness, HXxPoint p[7], tranLines* lines)
{
   int width = right - left;
   int height = bottom - top;
   double x = double(width) / 8.0;
   double y = double(height) / 8.0;
        
   int area = 0, lastArea = 0;
   int i;
        
   memset(p,0,sizeof(HXxPoint) * 7);
        
   int areaComplete = int(double(width * height * completeness) / 1000.0);
        
   for (i = 0; i < 16; ++i)
   {
      if (i < 8)
      {
         area = int((x * i + x) * (y * i + y) / 2);
      }
      else
      {
         area = width * height - int((x * (14 - i) + x) * (y * (14 - i) + y) / 2);
      }
                
      if (areaComplete < area)
         break;
                
      lastArea = area;
   }
   if (i == 16) --i;
        
   int tmpCompleteness = 1000 - int(double(area - areaComplete) / double(area - lastArea) * 1000);
        
   HXxPoint topPt, bottomPt;
        
   if (i < 8)
   {
      p[0].x = left;
      p[0].y = int(top + i * y);
      p[1].x = int(left + i * x);
      p[1].y = top;
      p[2].x = int(left + (i + 1) * x);
      p[2].y = top;
      p[3].x = left;
      p[3].y = int(top + (i + 1) * y);
   }
   else
   {
      int tmp = i - 8;
                
      p[0].x = int(left + tmp * x);
      p[0].y = bottom;
      p[1].x = right;
      p[1].y = int(top + tmp * y);
      p[2].x = right;
      p[2].y = int(top + (tmp + 1) * y);
      p[3].x = int(left + (tmp + 1) * x);
      p[3].y = bottom;
   }
        
   if (i & 1)
      tmpCompleteness = 1000 - tmpCompleteness;
        
   GetDiagonalStripCoords(p[0],p[1],p[2],p[3],&topPt,&bottomPt,tmpCompleteness);
        
   p[0].x = left;
   p[0].y = top;
   p[1].y = top;
        
   if (i < 8)
   {
      if (i & 1)
      {
         p[1].x = int(left + x * i + x);
         p[2].x = bottomPt.x;
         p[2].y = bottomPt.y;
         p[3].x = topPt.x;
         p[3].y = topPt.y;
         p[4].y = int(top + y * i);
      }
      else
      {
         p[1].x = int(left + x * i);
         p[2].x = topPt.x;
         p[2].y = topPt.y;
         p[3].x = bottomPt.x;
         p[3].y = bottomPt.y;
         p[4].y = int(top + y * i + y);
      }
      p[4].x = left;
   }
   else
   {
      p[1].x = right;
      p[2].x = right;
      p[5].y = bottom;
      p[6].x = left;
      p[6].y = bottom;
                
      if (i & 1)
      {
         p[2].y = int(top + y * (i - 8) + y);
         p[3].x = bottomPt.x;
         p[3].y = bottomPt.y;
         p[4].x = topPt.x;
         p[4].y = topPt.y;
         p[5].x = int(left + x * (i - 8));
      }
      else
      {
         p[2].y = int(top + y * (i - 8));
         p[3].x = topPt.x;
         p[3].y = topPt.y;
         p[4].x = bottomPt.x;
         p[4].y = bottomPt.y;
         p[5].x = int(left + x * (i - 8) + x);
      }
   }
   if (lines)
   {
      lines->m_nLines = 3;
      lines->m_pLines = new LineSegment[3];

      if(!lines->m_pLines)
      {
         lines->m_nLines = 0;
      }
      else
      {
         int pt = (i < 8) ? 1 : 2;
         lines->m_pLines[0].start.x = p[pt].x;
         lines->m_pLines[0].start.y= p[pt].y;
         lines->m_pLines[0].finish.x = p[pt+1].x;
         lines->m_pLines[0].finish.y= p[pt+1].y;
         lines->m_pLines[1].start.x = p[pt+1].x;
         lines->m_pLines[1].start.y= p[pt+1].y;
         lines->m_pLines[1].finish.x = p[pt+2].x;
         lines->m_pLines[1].finish.y= p[pt+2].y;
         lines->m_pLines[2].start.x = p[pt+2].x;
         lines->m_pLines[2].start.y= p[pt+2].y;
         lines->m_pLines[2].finish.x = p[pt+3].x;
         lines->m_pLines[2].finish.y= p[pt+3].y;
      }
   }
}

HXREGION* TopLeftDiagonalMatrix(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   HXxPoint p[7];
        
   GetTopLeftDiagonalCoords(left,top,right,bottom,completeness,p,lines);
   return HXPolygonRegion(p, 7, WindingRule);
}

HXREGION* TopRightDiagonalMatrix(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   HXREGION* retRGN = MirrorVertical(TopLeftDiagonalMatrix(left,top,right,bottom,completeness,lines),left + (right - left + 1) / 2);
   if (lines)
      MirrorVertical(lines,(right - left) / 2);

   return retRGN;
}

HXREGION* BottomRightDiagonalMatrix(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   HXREGION* retRGN = MirrorHorizontal(MirrorVertical(TopLeftDiagonalMatrix(left,top,right,bottom,completeness,lines),left + (right - left + 1) / 2),top + (bottom - top + 1) / 2);
   if (lines)
   {
      MirrorVertical(lines,(right - left) / 2);
      MirrorHorizontal(lines,top + (bottom - top + 1) / 2);
   }

   return retRGN;
}

HXREGION* BottomLeftDiagonalMatrix(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   HXREGION* retRGN = MirrorHorizontal(TopLeftDiagonalMatrix(left,top,right,bottom,completeness,lines),top + (bottom - top + 1) / 2);
   if (lines)
      MirrorHorizontal(lines,top + (bottom - top + 1) / 2);

   return retRGN;
}

HXREGION* ClockwiseTopLeftMatrix(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   static CHXBuffer* z_cwTopLeftDataBuffer = NULL;
        
   if (!z_cwTopLeftDataBuffer || completeness == MATRIX_TRANSITION_INIT)
   {
      MatrixTransitionData* VerticalMatrixTransition = new MatrixTransitionData(8,8,64);
      MatrixBlockTransitionList* blockTransList = VerticalMatrixTransition->GetTransactionListPtr();
                
      int blockIdx = 0;
                
      for (int i = 8; i > 0; i -= 2)
      {
         int j;
         int horzOffset = ((8 - i) / 2) * 9;
         int vertOffset = (9 - i) / 2;
         int vertOffsetRt = i / 2 + 2;
                        
         for (j = 0; j < i; ++j, ++blockIdx)
         {
            blockTransList[blockIdx].CreateList(1);
            MatrixBlockTransition* list = blockTransList[blockIdx].GetListPtr();
                                
            list->block = j + horzOffset;
            list->invert = 0;
            list->transition = EdgeWipe;
         }
         for (j = 0; j < i - 2; ++j, ++blockIdx)
         {
            blockTransList[blockIdx].CreateList(1);
            MatrixBlockTransition* list = blockTransList[blockIdx].GetListPtr();
                                
            list->block = (j + 2 + vertOffset) * 8 - (vertOffset + 1);
            list->invert = 0;
            list->transition = SlideVerticalEdgeWipe;
         }
         for (j = 0; j < i; ++j, ++blockIdx)
         {
            blockTransList[blockIdx].CreateList(1);
            MatrixBlockTransition* list = blockTransList[blockIdx].GetListPtr();
                                
            list->block = 63 - j - horzOffset;
            list->invert = 1;
            list->transition = EdgeWipe;
         }
         for (j = 0; j < i - 2; ++j, ++blockIdx)
         {
            blockTransList[blockIdx].CreateList(1);
            MatrixBlockTransition* list = blockTransList[blockIdx].GetListPtr();
                                
            list->block = (vertOffsetRt - j) * 8 + (vertOffset);
            list->invert = 1;
            list->transition = SlideVerticalEdgeWipe;
         }
      }
                
      z_cwTopLeftDataBuffer = new CHXBuffer();
      z_cwTopLeftDataBuffer->AddRef();
      z_cwTopLeftDataBuffer->Set((UCHAR*)&VerticalMatrixTransition, sizeof(UCHAR*));
   }
   else if (completeness == MATRIX_TRANSITION_DELETE)
   {
      delete *((MatrixTransitionData**)z_cwTopLeftDataBuffer->GetBuffer());
      if (!z_cwTopLeftDataBuffer->Release())
      {
         z_cwTopLeftDataBuffer = NULL;
         return HXCreateRegion();
      }
   }
        
   return MatrixTransition(left,top,right,bottom,completeness,*((MatrixTransitionData**)z_cwTopLeftDataBuffer->GetBuffer()),lines);
}

HXREGION* ClockwiseTopRightMatrix(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   HXREGION* retRGN = MirrorVertical(
      CounterClockwiseTopLeftMatrix(left,top,right,bottom,completeness,lines),
      left + (right - left+1) / 2
      );
   if (lines)
      MirrorVertical(lines,(left + right) / 2);

   return retRGN;
}

HXREGION* ClockwiseBottomRightMatrix(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   HXREGION* retRGN = MirrorHorizontal(MirrorVertical(ClockwiseTopLeftMatrix(left,top,right,bottom,completeness,lines),left + (right - left + 1) / 2),(top + bottom) / 2);
   if (lines)
   {
      MirrorVertical(lines,left + (right - left + 1) / 2);
      MirrorHorizontal(lines,(top + bottom) / 2);
   }
   return retRGN;
}

HXREGION* ClockwiseBottomLeftMatrix(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   HXREGION* retRGN = MirrorHorizontal(CounterClockwiseTopLeftMatrix(left,top,right,bottom,completeness,lines),top + (bottom - top + 1) / 2);
   if (lines)
      MirrorHorizontal(lines,top + (bottom - top + 1) / 2);
   return retRGN;
}

HXREGION* CounterClockwiseTopLeftMatrix(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   static CHXBuffer* z_ccwTopLeftDataBuffer = NULL;
        
   if (!z_ccwTopLeftDataBuffer || completeness == MATRIX_TRANSITION_INIT)
   {
      MatrixTransitionData* VerticalMatrixTransition = new MatrixTransitionData(8,8,64);
      MatrixBlockTransitionList* blockTransList = VerticalMatrixTransition->GetTransactionListPtr();
                
      int blockIdx = 0;
                
      for (int i = 8; i > 0; i -= 2)
      {
         int j;
         int horzOffset = (int)(5.0 - i / 2);
         int vertOffset = (int)((9.0 - i) / 2);
         int vertOffsetRt = (int)(i / 2+ 4);
                        
         for (j = 0; j < i; ++j, ++blockIdx)
         {
            blockTransList[blockIdx].CreateList(1);
            MatrixBlockTransition* list = blockTransList[blockIdx].GetListPtr();
                                
            list->block = (j + vertOffset) * 8 + vertOffset;
            list->invert = 0;
            list->transition = SlideVerticalEdgeWipe;
         }
         for (j = 0; j < i - 2; ++j, ++blockIdx)
         {
            blockTransList[blockIdx].CreateList(1);
            MatrixBlockTransition* list = blockTransList[blockIdx].GetListPtr();
                                
            list->block = j + (i / 2 + 3) * 8 + (10 - i) / 2;
            list->invert = 0;
            list->transition = EdgeWipe;
         }
         for (j = 0; j < i; ++j, ++blockIdx)
         {
            blockTransList[blockIdx].CreateList(1);
            MatrixBlockTransition* list = blockTransList[blockIdx].GetListPtr();
                                
            list->block = (vertOffsetRt - j) * 8 - vertOffset - 1;
            list->invert = 1;
            list->transition = SlideVerticalEdgeWipe;
         }
         for (j = 0; j < i - 2; ++j, ++blockIdx)
         {
            blockTransList[blockIdx].CreateList(1);
            MatrixBlockTransition* list = blockTransList[blockIdx].GetListPtr();
                                
            list->block = 7 * horzOffset - 1 - j;
            list->invert = 1;
            list->transition = EdgeWipe;
         }
      }
                
      z_ccwTopLeftDataBuffer = new CHXBuffer();
      z_ccwTopLeftDataBuffer->AddRef();
      z_ccwTopLeftDataBuffer->Set((UCHAR*)&VerticalMatrixTransition, sizeof(UCHAR*));
   }
   else if (completeness == MATRIX_TRANSITION_DELETE)
   {
      delete *((MatrixTransitionData**)z_ccwTopLeftDataBuffer->GetBuffer());
      if (!z_ccwTopLeftDataBuffer->Release())
      {
         z_ccwTopLeftDataBuffer = NULL;
         return HXCreateRegion();
      }
   }
        
   return MatrixTransition(left,top,right,bottom,completeness,*((MatrixTransitionData**)z_ccwTopLeftDataBuffer->GetBuffer()),lines);
}

HXREGION* CounterClockwiseTopRightMatrix(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   HXREGION* retRGN = MirrorVertical(ClockwiseTopLeftMatrix(left,top,right,bottom,completeness,lines),left + (right - left + 1) / 2);
   if (lines)
      MirrorVertical(lines,left + (right - left + 1) / 2);
   return retRGN;
}

HXREGION* CounterClockwiseBottomRightMatrix(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   HXREGION* retRGN = MirrorHorizontal(MirrorVertical(CounterClockwiseTopLeftMatrix(left,top,right,bottom,completeness,lines),left + (right - left + 1) / 2),top + (bottom - top + 1) / 2);
   if (lines)
   {
      MirrorHorizontal(lines,top + (bottom - top + 1) / 2);
      MirrorVertical(lines,left + (right - left + 1) / 2);
   }
   return retRGN;
}

HXREGION* CounterClockwiseBottomLeftMatrix(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   HXREGION* retRGN = MirrorHorizontal(ClockwiseTopLeftMatrix(left,top,right,bottom,completeness,lines),top + (bottom - top + 1) / 2);
   if (lines)
      MirrorHorizontal(lines,top + (bottom - top + 1) / 2);
   return retRGN;
}

HXREGION* VerticalStartTopMatrix(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   static CHXBuffer* z_verticalTopDataBuffer = NULL;
        
   if (!z_verticalTopDataBuffer || completeness == MATRIX_TRANSITION_INIT)
   {
      MatrixTransitionData* VerticalMatrixTransition = new MatrixTransitionData(8,1,4);
      MatrixBlockTransitionList* blockTransList = VerticalMatrixTransition->GetTransactionListPtr();
                
      for (int i = 0; i < 4; ++i)
      {
         blockTransList[i].CreateList(2);
         MatrixBlockTransition* list = blockTransList[i].GetListPtr();
                        
         list[0].invert = list[1].invert = i & 1;
         list[0].transition = list[1].transition = SlideVerticalEdgeWipe;
         list[0].block = i;
         list[1].block = 7 - i;
      }
                
      z_verticalTopDataBuffer = new CHXBuffer();
      z_verticalTopDataBuffer->AddRef();
      z_verticalTopDataBuffer->Set((UCHAR*)&VerticalMatrixTransition, sizeof(UCHAR*));
   }
   else if (completeness == MATRIX_TRANSITION_DELETE)
   {
      delete *((MatrixTransitionData**)z_verticalTopDataBuffer->GetBuffer());
      if (!z_verticalTopDataBuffer->Release())
      {
         z_verticalTopDataBuffer = NULL;
         return HXCreateRegion();
      }
   }
        
   return MatrixTransition(left,top,right,bottom,completeness,*((MatrixTransitionData**)z_verticalTopDataBuffer->GetBuffer()),lines);
}

HXREGION* VerticalStartBottomMatrix(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   HXREGION* retRGN = MirrorHorizontal(VerticalStartTopMatrix(left,top,right,bottom,completeness,lines),top + (bottom - top + 1) / 2);
   if (lines)
      MirrorHorizontal(lines,top + (bottom - top + 1) / 2);
   return retRGN;
}

HXREGION* VerticalStartTopOppositeMatrix(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   static CHXBuffer* z_verticalTopOppDataBuffer = NULL;
        
   if (!z_verticalTopOppDataBuffer || completeness == MATRIX_TRANSITION_INIT)
   {
      MatrixTransitionData* VerticalMatrixTransition = new MatrixTransitionData(8,1,4);
      MatrixBlockTransitionList* blockTransList = VerticalMatrixTransition->GetTransactionListPtr();
                
      for (int i = 0; i < 4; ++i)
      {
         blockTransList[i].CreateList(2);
         MatrixBlockTransition* list = blockTransList[i].GetListPtr();
                        
         list[0].invert = i & 1;
         list[1].invert = !list[0].invert;
         list[0].transition = list[1].transition = SlideVerticalEdgeWipe;
         list[0].block = i;
         list[1].block = 7 - i;
      }
                
      z_verticalTopOppDataBuffer = new CHXBuffer();
      z_verticalTopOppDataBuffer->AddRef();
      z_verticalTopOppDataBuffer->Set((UCHAR*)&VerticalMatrixTransition, sizeof(UCHAR*));
   }
   else if (completeness == MATRIX_TRANSITION_DELETE)
   {
      delete *((MatrixTransitionData**)z_verticalTopOppDataBuffer->GetBuffer());
      if (!z_verticalTopOppDataBuffer->Release())
      {
         z_verticalTopOppDataBuffer = NULL;
         return HXCreateRegion();
      }
   }
        
   return MatrixTransition(left,top,right,bottom,completeness,*((MatrixTransitionData**)z_verticalTopOppDataBuffer->GetBuffer()),lines);
}

HXREGION* VerticalStartBottomOppositeMatrix(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   HXREGION* retRGN = MirrorHorizontal(VerticalStartTopOppositeMatrix(left,top,right,bottom,completeness,lines),top + (bottom - top + 1) / 2);
   if (lines)
      MirrorHorizontal(lines,top + (bottom - top + 1) / 2);
   return retRGN;
}

HXREGION* HorizontalStartLeftMatrix(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   static CHXBuffer* z_verticalTopOppDataBuffer = NULL;
        
   if (!z_verticalTopOppDataBuffer || completeness == MATRIX_TRANSITION_INIT)
   {
      MatrixTransitionData* VerticalMatrixTransition = new MatrixTransitionData(1,8,4);
      MatrixBlockTransitionList* blockTransList = VerticalMatrixTransition->GetTransactionListPtr();
                
      for (int i = 0; i < 4; ++i)
      {
         blockTransList[i].CreateList(2);
         MatrixBlockTransition* list = blockTransList[i].GetListPtr();
                        
         list[0].invert = list[1].invert = i & 1;
         list[0].transition = list[1].transition = EdgeWipe;
         list[0].block = i;
         list[1].block = 7 - i;
      }
                
      z_verticalTopOppDataBuffer = new CHXBuffer();
      z_verticalTopOppDataBuffer->AddRef();
      z_verticalTopOppDataBuffer->Set((UCHAR*)&VerticalMatrixTransition, sizeof(UCHAR*));
   }
   else if (completeness == MATRIX_TRANSITION_DELETE)
   {
      delete *((MatrixTransitionData**)z_verticalTopOppDataBuffer->GetBuffer());
      if (!z_verticalTopOppDataBuffer->Release())
      {
         z_verticalTopOppDataBuffer = NULL;
         return HXCreateRegion();
      }
   }
        
   return MatrixTransition(left,top,right,bottom,completeness,*((MatrixTransitionData**)z_verticalTopOppDataBuffer->GetBuffer()),lines);
}

HXREGION* HorizontalStartRightMatrix(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   HXREGION* retRGN = MirrorVertical(HorizontalStartLeftMatrix(left,top,right,bottom,completeness,lines),left + (right - left + 1) / 2);
   if (lines)
      MirrorVertical(lines,left + (right - left + 1) / 2);
   return retRGN;
}

HXREGION* HorizontalStartLeftOppositeMatrix(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   static CHXBuffer* z_verticalTopOppDataBuffer = NULL;
        
   if (!z_verticalTopOppDataBuffer || completeness == MATRIX_TRANSITION_INIT)
   {
      MatrixTransitionData* VerticalMatrixTransition = new MatrixTransitionData(1,8,4);
      MatrixBlockTransitionList* blockTransList = VerticalMatrixTransition->GetTransactionListPtr();
                
      for (int i = 0; i < 4; ++i)
      {
         blockTransList[i].CreateList(2);
         MatrixBlockTransition* list = blockTransList[i].GetListPtr();
                        
         list[0].invert = i & 1;
         list[1].invert = !list[0].invert;
         list[0].transition = list[1].transition = EdgeWipe;
         list[0].block = i;
         list[1].block = 7 - i;
      }
                
      z_verticalTopOppDataBuffer = new CHXBuffer();
      z_verticalTopOppDataBuffer->AddRef();
      z_verticalTopOppDataBuffer->Set((UCHAR*)&VerticalMatrixTransition, sizeof(UCHAR*));
   }
   else if (completeness == MATRIX_TRANSITION_DELETE)
   {
      delete *((MatrixTransitionData**)z_verticalTopOppDataBuffer->GetBuffer());
      if (!z_verticalTopOppDataBuffer->Release())
      {
         z_verticalTopOppDataBuffer = NULL;
         return HXCreateRegion();
      }
   }
        
   return MatrixTransition(left,top,right,bottom,completeness,*((MatrixTransitionData**)z_verticalTopOppDataBuffer->GetBuffer()),lines);
}

HXREGION* HorizontalStartRightOppositeMatrix(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   HXREGION* retRGN = MirrorVertical(HorizontalStartLeftOppositeMatrix(left,top,right,bottom,completeness,lines),left + (right - left + 1) / 2);
   if (lines)
      MirrorVertical(lines,left + (right - left + 1) / 2);
   return retRGN;
}

HXREGION* DoubleSpiralTopMatrix(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   tranLines* tmpLines = NULL;

   if (lines)
      tmpLines = new tranLines;
   int ii = (int)(((float)(left + right)) / 2.0 + .5)-1;
   int jj = ii + 1;
   
   
   HXREGION* retRGN = CounterClockwiseTopLeftMatrix(left, top, ii, bottom, completeness,lines);
   HXREGION* rgn1 = ClockwiseTopRightMatrix(jj, top, right, bottom, completeness,tmpLines);
   HXCombineRgn(retRGN, retRGN, rgn1, HX_RGN_XOR);
   HXDestroyRegion(rgn1);

   if (lines)
      *lines += *tmpLines;
        
   return retRGN;
}

HXREGION* DoubleSpiralBottomMatrix(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   HXREGION* retRGN = MirrorHorizontal(DoubleSpiralTopMatrix(left,top,right,bottom,completeness,lines),top + (bottom - top + 1) / 2);
   if (lines)
      MirrorHorizontal(lines,top + (bottom - top + 1) / 2);

   return retRGN;
}

HXREGION* DoubleSpiralLeftMatrix(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   tranLines* tmpLines = NULL;

   if (lines)
      tmpLines = new tranLines;

   HXREGION* retRGN = ClockwiseTopLeftMatrix(left, top, right, (top + bottom) / 2 + 1, completeness,lines);
   HXREGION* rgn1 = CounterClockwiseBottomLeftMatrix(left, (top + bottom) / 2, right, bottom, completeness,tmpLines);
   HXCombineRgn(retRGN, retRGN, rgn1, HX_RGN_OR);
   HXDestroyRegion(rgn1);
        
   if (lines)
      *lines += *tmpLines;
        
   return retRGN;
}

HXREGION* DoubleSpiralRightMatrix(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   HXREGION* retRGN = MirrorVertical(DoubleSpiralLeftMatrix(left,top,right,bottom,completeness,lines),left + (right - left + 1) / 2);
   if (lines)
      MirrorVertical(lines,left + (right - left + 1) / 2);

   return retRGN;
}

HXREGION* QuadSpiralVerticalMatrix(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   tranLines* tmpLines = NULL;

   if (lines)
      tmpLines = new tranLines;

   HXREGION* retRGN = DoubleSpiralTopMatrix(left, top, right, (top + bottom) / 2 + 1, completeness,lines);
   HXREGION* rgn1 = DoubleSpiralBottomMatrix(left, (top + bottom) / 2 , right, bottom, completeness,tmpLines);
   HXCombineRgn(retRGN, retRGN, rgn1, HX_RGN_OR);
   HXDestroyRegion(rgn1);

   if (lines)
      *lines += *tmpLines;
        
   return retRGN;
}

HXREGION* QuadSpiralHorizontalMatrix(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   tranLines* tmpLines = NULL;

   if (lines)
      tmpLines = new tranLines;

   HXREGION* retRGN = DoubleSpiralLeftMatrix(left, top, (left + right) / 2, bottom, completeness,lines);
   HXREGION* rgn1 = DoubleSpiralRightMatrix((left + right) / 2 + 1, top, right, bottom, completeness,tmpLines);
   HXCombineRgn(retRGN, retRGN, rgn1, HX_RGN_XOR);
   HXDestroyRegion(rgn1);

   if (lines)
      *lines += *tmpLines;
        
   return retRGN;
}

HXREGION* VerticalWaterfallLeftMatrix(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   static CHXBuffer* z_waterfallLeftDataBuffer = NULL;
        
   if (!z_waterfallLeftDataBuffer || completeness == MATRIX_TRANSITION_INIT)
   {
      MatrixTransitionData* VerticalMatrixTransition = new MatrixTransitionData(8,4,11);
      MatrixBlockTransitionList* blockTransList = VerticalMatrixTransition->GetTransactionListPtr();
                
      int blockCount;
      int start = 0;
                
      for (int i = 0; i < 11; ++i)
      {
         blockCount = 6 - abs(i - 5);
         if (blockCount > 4) blockCount = 4;
                        
         blockTransList[i].CreateList(blockCount);
         MatrixBlockTransition* list = blockTransList[i].GetListPtr();
                        
         for (int j = 0; j < blockCount; ++j)
         {
            list[j].block = start - j * 7;
            list[j].invert = 0;
            list[j].transition = SlideVerticalEdgeWipe;
         }
         start = (i >= 3) ? start + 1 : start + 8;
      }
                
      z_waterfallLeftDataBuffer = new CHXBuffer();
      z_waterfallLeftDataBuffer->AddRef();
      z_waterfallLeftDataBuffer->Set((UCHAR*)&VerticalMatrixTransition, sizeof(UCHAR*));
   }
   else if (completeness == MATRIX_TRANSITION_DELETE)
   {
      delete *((MatrixTransitionData**)z_waterfallLeftDataBuffer->GetBuffer());
      if (!z_waterfallLeftDataBuffer->Release())
      {
         z_waterfallLeftDataBuffer = NULL;
         return HXCreateRegion();
      }
   }
        
   return MatrixTransition(left,top,right,bottom,completeness,*((MatrixTransitionData**)z_waterfallLeftDataBuffer->GetBuffer()),lines);
}

HXREGION* VerticalWaterfallRightMatrix(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   HXREGION* retRGN = MirrorVertical(VerticalWaterfallLeftMatrix(left, top, right, bottom, completeness,lines),left + (right - left + 1) / 2);
   if (lines)
      MirrorVertical(lines,left + (right - left + 1) / 2);

   return retRGN;
}

HXREGION* HorizontalWaterfallLeftMatrix(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   static CHXBuffer* z_waterfallHorzLeftDataBuffer = NULL;
        
   if (!z_waterfallHorzLeftDataBuffer || completeness == MATRIX_TRANSITION_INIT)
   {
      MatrixTransitionData* VerticalMatrixTransition = new MatrixTransitionData(4,8,11);
      MatrixBlockTransitionList* blockTransList = VerticalMatrixTransition->GetTransactionListPtr();
                
      int blockCount;
      int start = 0;
                
      for (int i = 0; i < 11; ++i)
      {
         blockCount = 6 - abs(i - 5);
         if (blockCount > 4) blockCount = 4;
                        
         blockTransList[i].CreateList(blockCount);
         MatrixBlockTransition* list = blockTransList[i].GetListPtr();
                        
         for (int j = 0; j < blockCount; ++j)
         {
            list[j].block = start + j * 3;
            list[j].invert = 0;
            list[j].transition = EdgeWipe;
         }
         start = (start >= 3) ? start + 4 : start + 1;
      }
                
      z_waterfallHorzLeftDataBuffer = new CHXBuffer();
      z_waterfallHorzLeftDataBuffer->AddRef();
      z_waterfallHorzLeftDataBuffer->Set((UCHAR*)&VerticalMatrixTransition, sizeof(UCHAR*));
   }
   else if (completeness == MATRIX_TRANSITION_DELETE)
   {
      delete *((MatrixTransitionData**)z_waterfallHorzLeftDataBuffer->GetBuffer());
      if (!z_waterfallHorzLeftDataBuffer->Release())
      {
         z_waterfallHorzLeftDataBuffer = NULL;
         return HXCreateRegion();
      }
   }
        
   return MatrixTransition(left,top,right,bottom,completeness,*((MatrixTransitionData**)z_waterfallHorzLeftDataBuffer->GetBuffer()),lines);
}

HXREGION* HorizontalWaterfallRightMatrix(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   HXREGION* retRGN = MirrorVertical(HorizontalWaterfallLeftMatrix(left, top, right, bottom, completeness,lines),left + (right - left + 1) / 2);
   if (lines)
      MirrorVertical(lines,left + (right - left + 1) / 2);

   return retRGN;
}

#endif //_TRANSITIONS_ON_

HXREGION* DefaultTransition(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   if (lines)
   {
      lines->m_nLines = 0;
      HX_VECTOR_DELETE( lines->m_pLines );
   }
   return HXCreateRectRegion(left, top, right - left, bottom - top);
}

#ifdef _TRANSITIONS_ON_

HXREGION* CreateConvexPoly(int nSides, int startingAngle, int left, int top, int right, int bottom, int completeness, int multiplier = 100, int arclength = 360, int oneExtra = 0, tranLines* lines = NULL)
{
   HXxPoint* points = (HXxPoint*) malloc(sizeof(HXxPoint)* (nSides+oneExtra));

   HX_ASSERT( points );
   
   int count = 0;
   int middlex = (left+right)/2;
   int middley = (top+bottom)/2;
   double sizex = (double)(right - left) * (double) completeness / 1000.0 * (double)multiplier / 100.0;
   double sizey = (double)(bottom - top) * (double) completeness / 1000.0 * (double)multiplier / 100.0;

   for(;count<(nSides+oneExtra); count++)
   {
      double angle      = ((double)startingAngle + ((double)(((double)arclength/(double)nSides)*(double)count)))*PI/180.0;
      points[count].x = (int) (middlex + sin(angle) * sizex);
      points[count].y = (int) (middley - cos(angle) * sizey);
   }

   if (lines)
   {
      lines->m_nLines = nSides;
      lines->m_pLines = new LineSegment[nSides];

      lines->m_pLines[0].start.x = points[0].x;
      lines->m_pLines[0].start.y = points[0].y;

      for (count = 1; count < nSides; count++)
      {
         lines->m_pLines[count].start.x = points[count].x;
         lines->m_pLines[count].start.y = points[count].y;
         lines->m_pLines[count - 1].finish.x = points[count].x;
         lines->m_pLines[count - 1].finish.y = points[count].y;
      }
      lines->m_pLines[count - 1].finish.x = points[0].x;
      lines->m_pLines[count - 1].finish.y = points[0].y;
   }

   HXREGION* tempRGN = HXPolygonRegion( points, (nSides+oneExtra), WindingRule);
   free(points);
   return tempRGN;
}

HXREGION* CreateConcavePoly(int nSides, int startingAngle, int left, int top, int right, int bottom, int completeness, int multiplier = 100, tranLines* lines = NULL)
{
   HXxPoint* points = (HXxPoint*) malloc(sizeof(HXxPoint)* nSides*2);
        
   int count = 0;
   int middlex = (left+right)/2;
   int middley = (top+bottom)/2;
   double sizex = (double)(right - left) * (double) completeness / 1000.0 * (double)multiplier / 100.0;
   double sizey = (double)(bottom - top) * (double) completeness / 1000.0 * (double)multiplier / 100.0;
        
   for(;count<nSides*2; count++)
   {
      double angle      = (startingAngle + ((double)((360.0/((double)nSides*2))*(double)count)))*PI/180.0;
      points[count].x = (int) (middlex + sin(angle) * sizex * (double)(count %2 + 1));
      points[count].y = (int) (middley - cos(angle) * sizey * (double)(count %2 + 1));
   }
        
   if (lines)
   {
      lines->m_nLines = nSides * 2;
      lines->m_pLines = new LineSegment[lines->m_nLines];

      lines->m_pLines[0].start.x = points[0].x;
      lines->m_pLines[0].start.y = points[0].y;

      for (count = 1; count < lines->m_nLines; count++)
      {
         lines->m_pLines[count].start.x = points[count].x;
         lines->m_pLines[count].start.y = points[count].y;
         lines->m_pLines[count - 1].finish.x = points[count].x;
         lines->m_pLines[count - 1].finish.y = points[count].y;
      }
      lines->m_pLines[count - 1].finish.x = points[0].x;
      lines->m_pLines[count - 1].finish.y = points[0].y;
   }
   HXREGION* tempRGN = HXPolygonRegion( points, nSides*2, WindingRule);
   free(points);
   return tempRGN;
}

HXREGION* CreateArrowHeadPoly(int startingAngle, int left, int top, int right, int bottom, int completeness, int multiplier = 100, tranLines* lines = NULL)
{
   int angles[] = {0, 140, 180, 220};
   double multiple[] = { 1.0, 1.0, 0.3333, 1.0};
   int nSides = 4;
   HXxPoint* points = (HXxPoint*) malloc(sizeof(HXxPoint)* nSides);
        
   int count = 0;
   int middlex = (left+right)/2;
   int middley = (top+bottom)/2;
   double sizex = (double)(right - left) * (double) completeness / 1000.0 * (double)multiplier / 100.0;
   double sizey = (double)(bottom - top) * (double) completeness / 1000.0 * (double)multiplier / 100.0;
        
   for(;count<nSides; count++)
   {
      double angle      = ((double)(startingAngle + angles[count]))*PI/180.0;
      points[count].x = (int) (middlex + sin(angle) * sizex * multiple[count]);
      points[count].y = (int) (middley - cos(angle) * sizey * multiple[count]);
   }
        
   if (lines)
   {
      lines->m_nLines = nSides;
      lines->m_pLines = new LineSegment[nSides];

      lines->m_pLines[0].start.x = points[0].x;
      lines->m_pLines[0].start.y = points[0].y;

      for (count = 1; count < nSides; count++)
      {
         lines->m_pLines[count].start.x = points[count].x;
         lines->m_pLines[count].start.y = points[count].y;
         lines->m_pLines[count - 1].finish.x = points[count].x;
         lines->m_pLines[count - 1].finish.y = points[count].y;
      }
      lines->m_pLines[count - 1].finish.x = points[0].x;
      lines->m_pLines[count - 1].finish.y = points[0].y;
   }
   HXREGION* tempRGN = HXPolygonRegion( points, nSides, WindingRule);
   free(points);
   return tempRGN;
}

HXREGION* CreateSharpTrianglePoly(int startingAngle, int left, int top, int right, int bottom, int completeness, int multiplier = 100, tranLines* lines = NULL)
{
   int angles[] = {0, 150, 210};
   int nSides = 3;
   HXxPoint* points = (HXxPoint*) malloc(sizeof(HXxPoint)* nSides);
        
   int count = 0;
   int middlex = (left+right)/2;
   int middley = (top+bottom)/2;
   double sizex = (double)(right - left) * (double) completeness / 1000.0 * (double)multiplier / 100.0;
   double sizey = (double)(bottom - top) * (double) completeness / 1000.0 * (double)multiplier / 100.0;
        
   for(;count<nSides; count++)
   {
      double angle      = ((double)(startingAngle + angles[count]))*PI/180.0;
      points[count].x = (int) (middlex + sin(angle) * sizex); 
      points[count].y = (int) (middley - cos(angle) * sizey);
   }
        
   if (lines)
   {
      lines->m_nLines = nSides;
      lines->m_pLines = new LineSegment[nSides];

      lines->m_pLines[0].start.x = points[0].x;
      lines->m_pLines[0].start.y = points[0].y;

      for (count = 1; count < nSides; count++)
      {
         lines->m_pLines[count].start.x = points[count].x;
         lines->m_pLines[count].start.y = points[count].y;
         lines->m_pLines[count - 1].finish.x = points[count].x;
         lines->m_pLines[count - 1].finish.y = points[count].y;
      }
      lines->m_pLines[count - 1].finish.x = points[0].x;
      lines->m_pLines[count - 1].finish.y = points[0].y;
   }
   HXREGION* tempRGN = HXPolygonRegion( points, nSides, WindingRule);
   free(points);
   return tempRGN;
}

HXREGION* KeyHoleIris(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   if (completeness >= 1000)
      return HXCreateRectRegion(left,top,right-left,bottom-top);

   int midX = left + right / 2;
   int midY = top + bottom / 2;
   int radius = int(double(midY - top) / 450.0 * completeness);
   int hTop = midY - radius;
   int startY = int(hTop + double(midY - hTop) * 2.0 / 5.0);

   int i;
   HXxPoint p[61];

   double angle = 1.570796; // 90 degrees
   for (i = 0; i <= 30; ++i, angle += 0.087266) // 5 degress
   {
      p[i].x = midX + int(cos(angle) * radius);
      p[i].y = startY - int(sin(angle) * radius);
   }

   p[30].x = midX - radius;
   p[30].y = startY + radius * 3;
   p[31].x = midX + radius;
   p[31].y = p[30].y;

   for (i = 32; i < 61; ++i)
   {
      p[i].x = 2 * midX - p[61 - i].x;
      p[i].y = p[61 - i].y;
   }

   if (lines)
   {
      lines->m_pLines = new LineSegment[61];

      if(!lines->m_pLines)
      {
         lines->m_nLines = 0;
      }
      else
      {
         int j;
         lines->m_nLines = 61;
         for (i = 0, j = 1; i < 60; ++i, ++j)
         {
            lines->m_pLines[i].start.x = p[i].x;
            lines->m_pLines[i].start.y = p[i].y;
            lines->m_pLines[i].finish.x = p[j].x;
            lines->m_pLines[i].finish.y = p[j].y;
         }
         lines->m_pLines[60].start.x = p[60].x;
         lines->m_pLines[60].start.y = p[60].y;
         lines->m_pLines[60].finish.x = p[0].x;
         lines->m_pLines[60].finish.y = p[0].y;
      }
   }

   return HXPolygonRegion(p, 61, WindingRule);
}

HXREGION* CatEyeIris(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   int width = right - left;
   int height = bottom - top;
   int halfWidth = width / 2;
   int halfHeight = height / 2;
   int radius = int(sqrt((double)(height * height + halfWidth * halfWidth)));
        
   double step = double(radius) / 1000.0;
   int x = int(double(halfHeight) / step);
   double newStep = double(1000 - x) / 1000.0;
   completeness = int(double(completeness) * newStep + x);
        
   tranLines* tmpLines = NULL;

   if (lines)
      tmpLines = new tranLines;

   HXREGION* retRGN = CreateConvexPoly(51,0,halfWidth - radius,top - radius,halfWidth + radius,top + radius,completeness,50,360,0,tmpLines);
   HXREGION* reg1 = CreateConvexPoly(51,0,halfWidth - radius,bottom - radius,halfWidth + radius,bottom + radius,completeness,50,360,0,lines);
    
   if (lines)
   {
      *lines += *tmpLines;
      delete tmpLines;
   }
        
   HXCombineRgn(retRGN, retRGN, reg1, HX_RGN_AND);
   HXDestroyRegion(reg1);
        
   return retRGN;
}

HXREGION* CatEyeSideIris(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   int width = right - left;
   int height = bottom - top;
   int halfWidth = width / 2;
   int halfHeight = height / 2;
   int radius = int(sqrt((double)(width * width + halfHeight * halfHeight)));
        
   double step = double(radius) / 1000.0;
   int x = int(double(halfWidth) / step);
   double newStep = double(1000 - x) / 1000.0;
   completeness = int(double(completeness) * newStep + x);
        
   tranLines* tmpLines = NULL;

   if (lines)
      tmpLines = new tranLines;

   HXREGION* retRGN = CreateConvexPoly(51,0,left - radius,halfHeight - radius,left + radius,halfHeight + radius,completeness,50,360,0,lines);
   HXREGION* reg1 = CreateConvexPoly(51,0,right - radius,halfHeight - radius,right + radius,halfHeight + radius,completeness,50,360,0,tmpLines);
        
   if (lines)
   {
      *lines += *tmpLines;
      delete tmpLines;
   }
        
   HXCombineRgn(retRGN, retRGN, reg1, HX_RGN_AND);
   HXDestroyRegion(reg1);
        
   return retRGN;
}

HXREGION* RoundRectCalc(int midX, int midY, int dx, int dy, int radius, tranLines* lines)
{
   int i;

   HXxPoint p[60];

   double angle = 1.570796; // 90 degrees
   for (i = 0; i < 15; ++i, angle += 0.10472) // 6 degrees
   {
      int nx = int(cos(angle) * radius);
      int ny = int(sin(angle) * radius);

      p[i].x = p[29 - i].x = midX - dx / 2 + nx;
      p[59 - i].x = p[30 + i].x = midX + dx / 2 - nx;
      p[i].y = p[59 - i].y = midY - dy / 2 - ny;
      p[29 - i].y = p[30 + i].y = midY + dy / 2 + ny;
   }

   if (lines)
   {
      lines->m_pLines = new LineSegment[60];

      if(!lines->m_pLines)
      {
         lines->m_nLines = 0;
      }
      else
      {
         int j;
         lines->m_nLines = 60;
         for (i = 0, j = 1; i < 59; ++i, ++j)
         {
            lines->m_pLines[i].start.x = p[i].x;
            lines->m_pLines[i].start.y = p[i].y;
            lines->m_pLines[i].finish.x = p[j].x;
            lines->m_pLines[i].finish.y = p[j].y;
         }
         lines->m_pLines[59].start.x = p[59].x;
         lines->m_pLines[59].start.y = p[59].y;
         lines->m_pLines[59].finish.x = p[0].x;
         lines->m_pLines[59].finish.y = p[0].y;
      }
   }
        
   return HXPolygonRegion(p, 60, WindingRule);
}

HXREGION* RoundRectHorizontal(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   if (completeness >= 1000)
      return HXCreateRectRegion(left,top,right-left,bottom-top);

   int width = right - left;
   int height = bottom - top;
   int midX = left + width / 2;
   int midY = top + height / 2;
   int steps = height / 2 + height / 16;
        
   if (width > height * 2)
      steps += (width - height) / 2;
        
   int dy = int(steps * (double(completeness) / 1000.0));
   int dx = dy * 2;
   int radius = dy / 2;

   return RoundRectCalc(midX, midY, dx, dy, radius, lines);
}

HXREGION* RoundRectVeritical(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   if (completeness >= 1000)
      return HXCreateRectRegion(left,top,right-left,bottom-top);

   int width = right - left;
   int height = bottom - top;
   int midX = left + right / 2;
   int midY = top + bottom / 2;
   int steps = width / 2;
        
   if (height > width * 2)
      steps += (height - width) / 2;
        
   int dx = int(steps * (double(completeness) / 1000.0));
   int dy = dx * 2;
   int radius = dx / 2;

   return RoundRectCalc(midX, midY, dx, dy, radius, lines);
}

HXREGION* ConvexPolyIris(int sides, int angle, int left, int top, int right, int bottom, int completeness, int multiplier = 100, tranLines* lines = NULL)
{
   if (completeness >= 1000)
      return HXCreateRectRegion(left,top,right-left,bottom-top);
        
   int width = right - left;
   int height = bottom - top;
   int midX = left + width / 2;
   int midY = top + height / 2;
        
   double step = double(max(width, height)) / 2000.0;
   int square = int(step * completeness);
        
   int sLeft = midX - square;
   int sTop = midY - square;
   int sRight = midX + square;
   int sBottom = midY + square;
        
   return CreateConvexPoly(sides, angle, sLeft, sTop, sRight, sBottom, completeness, multiplier, 360, 0 ,lines);
}

HXREGION* RectangleIris(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   return CreateConvexPoly(4, 45, left, top, right, bottom, completeness, 75, 360, 0 , lines);
}

HXREGION* DiamondIris(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   return ConvexPolyIris(4,0,left,top,right,bottom,completeness, 100, lines);
}

HXREGION* TriangleIris(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   return ConvexPolyIris(3,0,left,top,right,bottom,completeness, 140, lines);
}

HXREGION* TriangleRightIris(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   return ConvexPolyIris(3,90,left,top,right,bottom,completeness,140, lines);
}

HXREGION* TriangleUpsideDownIris(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   return ConvexPolyIris(3,180,left,top,right,bottom,completeness, 140, lines);
}

HXREGION* TriangleLeftIris(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   return ConvexPolyIris(3,270,left,top,right,bottom,completeness, 140, lines);
}

HXREGION* PentagonIris(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   return ConvexPolyIris(5,0,left,top,right,bottom,completeness, 66, lines);
}

HXREGION* PentagonUpsideDownLeftIris(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   return ConvexPolyIris(5,180,left,top,right,bottom,completeness,66, lines);
}

HXREGION* HexagonIris(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   return ConvexPolyIris(6,60,left,top,right,bottom,completeness,85, lines);
}

HXREGION* HexagonSideIris(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   return ConvexPolyIris(6,30,left,top,right,bottom,completeness,85, lines);
}

HXREGION* CircleIris(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   return ConvexPolyIris(50,0,left,top,right,bottom,completeness,60, lines);
}

HXREGION* OvalIris(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   return CreateConvexPoly(50, 0, left - (right - left)/2, top, right + (right - left)/2, bottom, completeness, 60, 360, 0 , lines);
}

HXREGION* OvalSideIris(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   return CreateConvexPoly(50, 0, left, top - (bottom - top)/2, right, bottom + (bottom - top)/2, completeness, 60, 360, 0 , lines);
}

HXREGION* StarIris(int sides, int angle, int left, int top, int right, int bottom, int completeness, int multiplier = 100, tranLines* lines = NULL)
{
   if (completeness >= 1000)
      return HXCreateRectRegion(left,top,right-left,bottom-top);
        
   int width = right - left;
   int height = bottom - top;
   int midX = left + width / 2;
   int midY = top + height / 2;
        
   int square = int(double(min(width, height) * double(multiplier) / 100.0 * completeness) / 1000.0);
        
   int sLeft = midX - square;
   int sTop = midY - square;
   int sRight = midX + square;
   int sBottom = midY + square;
        
   HXREGION* retRGN = CreateConcavePoly(sides, angle, sLeft, sTop, sRight, sBottom, completeness, 50, lines);
   return retRGN;
}

HXREGION* FourPointStarIris(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   return StarIris(4,45,left,top,right,bottom,completeness,120, lines);
}

HXREGION* FivePointStarIris(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   return StarIris(5,36,left,top,right,bottom,completeness,150, lines);
}

HXREGION* SixPointStarIris(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   return StarIris(6,30,left,top,right,bottom,completeness,150, lines);
}

HXREGION* ArrowHeadIris(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   return CreateArrowHeadPoly(0, left, top, right, bottom, completeness, 200, lines);
}

HXREGION* ArrowHeadRightIris(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   return CreateArrowHeadPoly(90, left, top, right, bottom, completeness, 200, lines);
}

HXREGION* ArrowHeadUpsideDownIris(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   return CreateArrowHeadPoly(180, left, top, right, bottom, completeness, 200, lines);
}

HXREGION* ArrowHeadLeftIris(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   return CreateArrowHeadPoly(270, left, top, right, bottom, completeness, 200, lines);
}

HXREGION* HeartIris(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   if (completeness >= 1000)
      return HXCreateRectRegion(left,top,right-left,bottom-top);

   int midX = (right - left) / 2;
   int midY = (bottom - top) / 2;
   int radius = int(double(midY - top) / 750.0 * completeness);
   int hLeft = midX - radius;
   int hTop = midY - radius;
   int startY = int(hTop + double(midY - hTop) * 2.0 / 5.0);
   int i;

   HXxPoint p[60];

   double angle = 0;
   for (i = 0; i <= 30; ++i, angle += 0.1309) // 7.5 degress
   {
      p[i].x = hLeft + int(cos(angle) * radius);
      p[i].y = startY - int(sin(angle) * radius);
   }

   p[30].x = midX;
   p[30].y = p[29].y + (5 * (midX - p[29].x)) / 4; // slope is 5/4 or 1.25

   for (i = 31; i < 60; ++i)
   {
      p[i].x = 2 * midX - p[60 - i].x;
      p[i].y = p[60 - i].y;
   }

   if (lines)
   {
      lines->m_pLines = new LineSegment[60];

      if(!lines->m_pLines)
      {
         lines->m_nLines = 0;
      }
      else
      {
         int j;
         lines->m_nLines = 60;
         for (i = 0, j = 1; i < 59; ++i, ++j)
         {
            lines->m_pLines[i].start.x = p[i].x;
            lines->m_pLines[i].start.y = p[i].y;
            lines->m_pLines[i].finish.x = p[j].x;
            lines->m_pLines[i].finish.y = p[j].y;
         }
         lines->m_pLines[59].start.x = p[59].x;
         lines->m_pLines[59].start.y = p[59].y;
         lines->m_pLines[59].finish.x = p[0].x;
         lines->m_pLines[59].finish.y = p[0].y;
      }
   }

   return HXPolygonRegion(p, 60, WindingRule);
}


HXREGION* EdgeWipe(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   int x = (int)((double)left + (right - left)*((double)completeness)/1000.0);

   if (lines)
   {
      lines->m_nLines = 1;
      lines->m_pLines = new LineSegment[1];
      lines->m_pLines->start.x = lines->m_pLines->finish.x = x;
      lines->m_pLines->start.y = top;
      lines->m_pLines->finish.y = bottom;
   }

   return HXCreateRectRegion(left,
                              top,
                              x - left,
                              bottom - top);
}

HXREGION* SlideVerticalEdgeWipe(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   int y = (int) ((double)top + (double)(bottom - top)* ((double)completeness) / 1000.0);

   if (lines)
   {
      lines->m_nLines = 1;
      lines->m_pLines = new LineSegment[1];
      lines->m_pLines->start.x = left;
      lines->m_pLines->finish.x = right;
      lines->m_pLines->start.y = lines->m_pLines->finish.y = y;
   }

   return HXCreateRectRegion( left,
                               top,
                               right - left,
                               y - top
                               );
}

HXREGION* TopLeftEdgeWipe(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   HXxPoint points[4];
        
   points[0].x = left;
   points[0].y = top;
   points[1].x = left;
   points[1].y = top + ((bottom - top) * completeness  )/ 1000;
   points[2].x = left + ((right - left) * completeness )/ 1000;
   points[2].y = top + ((bottom - top) * completeness  )/ 1000;
   points[3].x = left + ((right - left) * completeness )/ 1000;
   points[3].y = top;
        
   if (lines)
   {
      lines->m_nLines = 2;
      lines->m_pLines = new LineSegment[2];

      if (!lines->m_pLines)
      {
         lines->m_nLines = 0;
      }
      else
      {
         lines->m_pLines[0].start.x = points[1].x;
         lines->m_pLines[0].start.y = points[1].y;
         lines->m_pLines[0].finish.x = points[2].x;
         lines->m_pLines[0].finish.y = points[2].y;
         lines->m_pLines[1].start.x = points[2].x;
         lines->m_pLines[1].start.y = points[2].y;
         lines->m_pLines[1].finish.x = points[3].x;
         lines->m_pLines[1].finish.y = points[3].y;
      }
   }

   return HXPolygonRegion( points, 4, WindingRule);
}

HXREGION* TopRightEdgeWipe(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   HXxPoint points[4];
        
   points[0].x = right;
   points[0].y = top;
   points[1].x = right;
   points[1].y = top + ((bottom - top) * completeness)/ 1000;
   points[2].x = right - ((right - left) * completeness)/ 1000;
   points[2].y = top + ((bottom - top) * completeness)/ 1000;
   points[3].x = right - ((right - left) * completeness)/ 1000;
   points[3].y = top;
        
   if (lines)
   {
      lines->m_nLines = 2;
      lines->m_pLines = new LineSegment[2];

      if (!lines->m_pLines)
      {
         lines->m_nLines = 0;
      }
      else
      {
         lines->m_pLines[0].start.x = points[1].x;
         lines->m_pLines[0].start.y = points[1].y;
         lines->m_pLines[0].finish.x = points[2].x;
         lines->m_pLines[0].finish.y = points[2].y;
         lines->m_pLines[1].start.x = points[2].x;
         lines->m_pLines[1].start.y = points[2].y;
         lines->m_pLines[1].finish.x = points[3].x;
         lines->m_pLines[1].finish.y = points[3].y;
      }
   }

   return HXPolygonRegion( points, 4, WindingRule);
}


HXREGION* BottomRightEdgeWipe(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   HXxPoint points[4];
        
   points[0].x = right;
   points[0].y = bottom;
   points[1].x = right;
   points[1].y = bottom - ((bottom - top) * completeness)/ 1000;
   points[2].y = bottom - ((bottom - top) * completeness)/ 1000;
   points[2].x = right - ((right - left) * completeness)/ 1000;
   points[3].x = right - ((right - left) * completeness)/ 1000;
   points[3].y = bottom;
        
   if (lines)
   {
      lines->m_nLines = 2;
      lines->m_pLines = new LineSegment[2];

      if (!lines->m_pLines)
      {
         lines->m_nLines = 0;
      }
      else
      {
         lines->m_pLines[0].start.x = points[1].x;
         lines->m_pLines[0].start.y = points[1].y;
         lines->m_pLines[0].finish.x = points[2].x;
         lines->m_pLines[0].finish.y = points[2].y;
         lines->m_pLines[1].start.x = points[2].x;
         lines->m_pLines[1].start.y = points[2].y;
         lines->m_pLines[1].finish.x = points[3].x;
         lines->m_pLines[1].finish.y = points[3].y;
      }
   }

   return HXPolygonRegion( points, 4, WindingRule);
}

HXREGION* BottomLeftEdgeWipe(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   HXxPoint points[4];
        
   points[0].x = left;
   points[0].y = bottom;
   points[1].x = left;
   points[1].y = bottom - ((bottom - top) * completeness )/ 1000;
   points[2].y = bottom - ((bottom - top) * completeness )/ 1000;
   points[2].x = left + ((right - left) * completeness )/ 1000;
   points[3].x = left + ((right - left) * completeness )/ 1000;
   points[3].y = bottom;
        
   if (lines)
   {
      lines->m_nLines = 2;
      lines->m_pLines = new LineSegment[2];

      if (!lines->m_pLines)
      {
         lines->m_nLines = 0;
      }
      else
      {
         lines->m_pLines[0].start.x = points[1].x;
         lines->m_pLines[0].start.y = points[1].y;
         lines->m_pLines[0].finish.x = points[2].x;
         lines->m_pLines[0].finish.y = points[2].y;
         lines->m_pLines[1].start.x = points[2].x;
         lines->m_pLines[1].start.y = points[2].y;
         lines->m_pLines[1].finish.x = points[3].x;
         lines->m_pLines[1].finish.y = points[3].y;
      }
   }

   return HXPolygonRegion( points, 4, WindingRule);
}

HXREGION* FourCornerEdgeWipe(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   tranLines *tl1 = NULL, *tl2 = NULL, *tl3 = NULL;

   if (lines)
   {
      tl1 = new tranLines;
      tl2 = new tranLines;
      tl3 = new tranLines;
   }

   HXREGION* retRGN = HXCreateRectRegion(0, 0, 0, 0);
   HXREGION* rgn1 = TopLeftEdgeWipe(left, top, left+(right-left)/2, top+(bottom-top)/2, completeness,lines);
   HXREGION* rgn2 = TopRightEdgeWipe(left+(right-left)/2, top, right, top+(bottom-top)/2, completeness,tl1);
   HXREGION* rgn3 = BottomRightEdgeWipe(left+(right-left)/2, top+(bottom-top)/2, right, bottom, completeness,tl2);
   HXREGION* rgn4 = BottomLeftEdgeWipe(left, top+(bottom-top)/2, left+(right-left)/2, bottom, completeness,tl3);

   if (lines)
   {
      *lines += *tl1;
      *lines += *tl2;
      *lines += *tl3;
      delete tl1;
      delete tl2;
      delete tl3;
   }
    
   HXCombineRgn(retRGN, retRGN, rgn1, HX_RGN_OR);
   HXCombineRgn(retRGN, retRGN, rgn2, HX_RGN_OR);
   HXCombineRgn(retRGN, retRGN, rgn3, HX_RGN_OR);
   HXCombineRgn(retRGN, retRGN, rgn4, HX_RGN_OR);
        
   HXDestroyRegion(rgn1);
   HXDestroyRegion(rgn2);
   HXDestroyRegion(rgn3);
   HXDestroyRegion(rgn4);
    
   return retRGN;
}

HXREGION* BoxEdgeWipe(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   double dleft     = left;
   double dtop              = top;
   double dright            = right;
   double dbottom           = bottom;
   double dcompleteness    = completeness;

   int l = (int) (((dleft+dright)/2.0 ) - ((dright - dleft)/2.0 ) * dcompleteness/1000.0);
   int t = (int) (((dtop+dbottom)/2.0 ) - ((dbottom - dtop)/2.0 ) * dcompleteness/1000.0);
   int r = (int) (((dleft+dright)/2.0 ) + ((dright - dleft)/2.0 ) * dcompleteness/1000.0);
   int b = (int) (((dtop+dbottom)/2.0 ) + ((dbottom - dtop)/2.0 ) * dcompleteness/1000.0);

   if (lines)
   {
      lines->m_nLines = 4;
      lines->m_pLines = new LineSegment[4];

      if (!lines->m_pLines)
      {
         lines->m_nLines = 0;
      }
      else
      {
         lines->m_pLines[0].start.x = l;
         lines->m_pLines[0].start.y = t;
         lines->m_pLines[0].finish.x = r;
         lines->m_pLines[0].finish.y = t;
         lines->m_pLines[1].start.x = r;
         lines->m_pLines[1].start.y = t;
         lines->m_pLines[1].finish.x = r;
         lines->m_pLines[1].finish.y = b;
         lines->m_pLines[2].start.x = r;
         lines->m_pLines[2].start.y = b;
         lines->m_pLines[2].finish.x = l;
         lines->m_pLines[2].finish.y = b;
         lines->m_pLines[3].start.x = l;
         lines->m_pLines[3].start.y = b;
         lines->m_pLines[3].finish.x = l;
         lines->m_pLines[3].finish.y = t;
      }
   }
   return HXCreateRectRegion(l,t,r-l,b-t);
}

HXREGION* FourBoxEdgeWipe(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   tranLines *tl1 = NULL, *tl2 = NULL, *tl3 = NULL;

   if (lines)
   {
      tl1 = new tranLines;
      tl2 = new tranLines;
      tl3 = new tranLines;
   }

   HXREGION* retRGN = HXCreateRectRegion(0, 0, 0, 0);
   HXREGION* rgn1 = BoxEdgeWipe(left, top, left+(right-left)/2, top+(bottom-top)/2, completeness,lines);
   HXREGION* rgn2 = BoxEdgeWipe(left+(right-left)/2, top, right, top+(bottom-top)/2, completeness,tl1);
   HXREGION* rgn3 = BoxEdgeWipe(left+(right-left)/2, top+(bottom-top)/2, right, bottom, completeness,tl2);
   HXREGION* rgn4 = BoxEdgeWipe(left, top+(bottom-top)/2, left+(right-left)/2, bottom, completeness,tl3);
        
   if (lines)
   {
      *lines += *tl1;
      *lines += *tl2;
      *lines += *tl3;
      delete tl1;
      delete tl2;
      delete tl3;
   }
        
   HXCombineRgn(retRGN, retRGN, rgn1, HX_RGN_OR);
   HXCombineRgn(retRGN, retRGN, rgn2, HX_RGN_OR);
   HXCombineRgn(retRGN, retRGN, rgn3, HX_RGN_OR);
   HXCombineRgn(retRGN, retRGN, rgn4, HX_RGN_OR);
        
   HXDestroyRegion(rgn1);
   HXDestroyRegion(rgn2);
   HXDestroyRegion(rgn3);
   HXDestroyRegion(rgn4);
        
   return retRGN;
}

HXREGION* BarnVerticalEdgeWipe(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   int l = (int)(((double)(left+right)/2)-((double) (right - left)/2 ) * ((double)completeness/1000.0));
   int r = (int) (((double) (left+right)/2 ) + ((double) (right - left)/2 ) * ((double)completeness/1000.0));

   if (lines)
   {
      lines->m_nLines = 2;
      lines->m_pLines = new LineSegment[2];

      if (!lines->m_pLines)
      {
         lines->m_nLines = 0;
      }
      else
      {
         lines->m_pLines[0].start.x = l;
         lines->m_pLines[0].start.y = top;
         lines->m_pLines[0].finish.x = l;
         lines->m_pLines[0].finish.y = bottom;
         lines->m_pLines[1].start.x = r;
         lines->m_pLines[1].start.y = top;
         lines->m_pLines[1].finish.x = r;
         lines->m_pLines[1].finish.y = bottom;
      }
   }

   return HXCreateRectRegion(l,top,r-l,bottom-top);
}

HXREGION* BarnHorizontalEdgeWipe(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   int t = (int) (((double) (top+bottom)/2 ) - ((double) (bottom - top)/2 ) * ((double)completeness/1000.0));
   int b = (int) (((double) (top+bottom)/2 ) + ((double) (bottom - top)/2 ) * ((double)completeness/1000.0));

   if (lines)
   {
      lines->m_nLines = 2;
      lines->m_pLines = new LineSegment[2];

      if (!lines->m_pLines)
      {
         lines->m_nLines = 0;
      }
      else
      {
         lines->m_pLines[0].start.x = left;
         lines->m_pLines[0].start.y = t;
         lines->m_pLines[0].finish.x = right;
         lines->m_pLines[0].finish.y = t;
         lines->m_pLines[1].start.x = left;
         lines->m_pLines[1].start.y = b;
         lines->m_pLines[1].finish.x = right;
         lines->m_pLines[1].finish.y = b;
      }
   }

   return HXCreateRectRegion(left,t,right-left,b-t);
}

HXREGION* TopCenterEdgeWipe(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   int l = (int) (((double) (left+right)/2 ) - ((double) (right - left)/2 ) * ((double)completeness/1000.0));
   int r = (int) (((double) (left+right)/2 ) + ((double) (right - left)/2 ) * ((double)completeness/1000.0));
   int b = (int) (((double) top + ((double) (bottom - top) )) * ((double)completeness/1000.0));

   if (lines)
   {
      lines->m_nLines = 3;
      lines->m_pLines = new LineSegment[3];

      if (!lines->m_pLines)
      {
         lines->m_nLines = 0;
      }
      else
      {
         lines->m_pLines[0].start.x = l;
         lines->m_pLines[0].start.y = top;
         lines->m_pLines[0].finish.x = l;
         lines->m_pLines[0].finish.y = b;
         lines->m_pLines[1].start.x = l;
         lines->m_pLines[1].start.y = b;
         lines->m_pLines[1].finish.x = r;
         lines->m_pLines[1].finish.y = b;
         lines->m_pLines[2].start.x = r;
         lines->m_pLines[2].start.y = b;
         lines->m_pLines[2].finish.x = r;
         lines->m_pLines[2].finish.y = top;
      }
   }

   HXREGION* retRGN = HXCreateRectRegion(l,top,r-l,b-top);
        
   return retRGN;
}

HXREGION* CenterRightEdgeWipe(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   int l = (int) (left + ((double) (right - left) ) * ( 1.0 - (double)completeness/1000.0));
   int t = (int) (((double) (top+bottom)/2 ) - ((double) (bottom - top)/2 ) * ((double)completeness/1000.0));
   int b = (int) (((double) (top+bottom)/2 ) + ((double) (bottom - top)/2 ) * ((double)completeness/1000.0));

   if (lines)
   {
      lines->m_nLines = 3;
      lines->m_pLines = new LineSegment[3];

      if (!lines->m_pLines)
      {
         lines->m_nLines = 0;
      }
      else
      {
         lines->m_pLines[0].start.x = right;
         lines->m_pLines[0].start.y = t;
         lines->m_pLines[0].finish.x = l;
         lines->m_pLines[0].finish.y = t;
         lines->m_pLines[1].start.x = l;
         lines->m_pLines[1].start.y = t;
         lines->m_pLines[1].finish.x = l;
         lines->m_pLines[1].finish.y = b;
         lines->m_pLines[2].start.x = l;
         lines->m_pLines[2].start.y = b;
         lines->m_pLines[2].finish.x = right;
         lines->m_pLines[2].finish.y = b;
      }
   }

   HXREGION* retRGN = HXCreateRectRegion(l,t,right-l,b-t);
    
   return retRGN;
}

HXREGION* BottomCenterEdgeWipe(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   int l = (int) (((double) (left+right)/2 ) - ((double) (right - left)/2 ) * ((double)completeness/1000.0));
   int t = (int) (bottom - ((double) (bottom - top) ) * ((double)completeness/1000.0));
   int r = (int) (((double) (left+right)/2 ) + ((double) (right - left)/2 ) * ((double)completeness/1000.0));

   if (lines)
   {
      lines->m_nLines = 3;
      lines->m_pLines = new LineSegment[3];

      if (!lines->m_pLines)
      {
         lines->m_nLines = 0;
      }
      else
      {
         lines->m_pLines[0].start.x = l;
         lines->m_pLines[0].start.y = bottom;
         lines->m_pLines[0].finish.x = l;
         lines->m_pLines[0].finish.y = t;
         lines->m_pLines[1].start.x = l;
         lines->m_pLines[1].start.y = t;
         lines->m_pLines[1].finish.x = r;
         lines->m_pLines[1].finish.y = t;
         lines->m_pLines[2].start.x = r;
         lines->m_pLines[2].start.y = t;
         lines->m_pLines[2].finish.x = r;
         lines->m_pLines[2].finish.y = bottom;
      }
   }

   HXREGION* retRGN = HXCreateRectRegion(l,t,r-l,bottom-t);
    
   return retRGN;
}

HXREGION* LeftCenterEdgeWipe(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   int t = (int) (((double) (top+bottom)/2 ) - ((double) (bottom - top)/2 ) * ((double)completeness/1000.0));
   int r = (int) (left + ((double) (right - left) ) * ((double)completeness/1000.0));
   int b = (int) (((double) (top+bottom)/2 ) + ((double) (bottom - top)/2 ) * ((double)completeness/1000.0));

   if (lines)
   {
      lines->m_nLines = 3;
      lines->m_pLines = new LineSegment[3];

      if (!lines->m_pLines)
      {
         lines->m_nLines = 0;
      }
      else
      {
         lines->m_pLines[0].start.x = left;
         lines->m_pLines[0].start.y = t;
         lines->m_pLines[0].finish.x = r;
         lines->m_pLines[0].finish.y = t;
         lines->m_pLines[1].start.x = r;
         lines->m_pLines[1].start.y = t;
         lines->m_pLines[1].finish.x = r;
         lines->m_pLines[1].finish.y = b;
         lines->m_pLines[2].start.x = r;
         lines->m_pLines[2].start.y = b;
         lines->m_pLines[2].finish.x = left;
         lines->m_pLines[2].finish.y = b;
      }
   }

   HXREGION* retRGN = HXCreateRectRegion(left,t,r-left,b-t);
    
   return retRGN;
}

HXREGION* DiagonalLeftDownEdgeWipe(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   HXREGION* retRGN = HXCreateRectRegion(left, top, right-left, bottom-top);
   HXxPoint points[4];
        
   points[0].x = left;
   points[0].y = top;
   points[1].x = left + ((right - left) * completeness * 2)/ 1000;
   points[1].y = top;
   points[2].x = left;
   points[2].y = top + ((bottom - top) * completeness * 2)/ 1000;

   if (lines)
   {
      lines->m_nLines = 1;
      lines->m_pLines = new LineSegment[1];

      if (!lines->m_pLines)
      {
         lines->m_nLines = 0;
      }
      else
      {
         lines->m_pLines->start.x = points[1].x;
         lines->m_pLines->start.y = points[1].y;
         lines->m_pLines->finish.x = points[2].x;
         lines->m_pLines->finish.y = points[2].y;
      }
   }
        
   HXREGION* tempRGN = HXPolygonRegion( points, 3, WindingRule);
        
   HXCombineRgn(retRGN, retRGN, tempRGN, HX_RGN_AND);
   HXDestroyRegion(tempRGN);
   return retRGN;
}

HXREGION* DiagonalRightDownEdgeWipe(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   HXREGION* retRGN = HXCreateRectRegion(left, top, right-left, bottom-top);
   HXxPoint points[4];
        
   points[0].x = right;
   points[0].y = top;
   points[1].x = right - ((right - left) * completeness * 2)/ 1000;
   points[1].y = top;
   points[2].x = right;
   points[2].y = top + ((bottom - top) * completeness * 2)/ 1000;
        
   if (lines)
   {
      lines->m_nLines = 1;
      lines->m_pLines = new LineSegment[1];

      if (!lines->m_pLines)
      {
         lines->m_nLines = 0;
      }
      else
      {
         lines->m_pLines->start.x = points[1].x;
         lines->m_pLines->start.y = points[1].y;
         lines->m_pLines->finish.x = points[2].x;
         lines->m_pLines->finish.y = points[2].y;
      }
   }
        
   HXREGION* tempRGN = HXPolygonRegion( points, 3, WindingRule);
        
   HXCombineRgn(retRGN, retRGN, tempRGN, HX_RGN_AND);
   HXDestroyRegion(tempRGN);
   return retRGN;
}

HXREGION* HalfBowTieEdgeWipe(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   HXREGION* retRGN = NULL;
   HXxPoint points[5];

   if (completeness < 500)
   {
      points[0].x = left;
      points[0].y = top;
      points[1].x = (int) ((right + left) / 2 - ((double)(right - left)) * (double)completeness / 1000.0);
      points[1].y = top;
      points[2].x = points[1].x + (right + left) / 2;
      points[2].y = (top + bottom) / 2;
      points[3].x = points[1].x;
      points[3].y = bottom;
      points[4].x = left;
      points[4].y = bottom;

      if (lines)
      {
         lines->m_nLines = 2;
         lines->m_pLines = new LineSegment[2];

         if (!lines->m_pLines)
         {
            lines->m_nLines = 0;
         }
         else
         {
            lines->m_pLines[0].start.x = points[1].x;
            lines->m_pLines[0].start.y = points[1].y;
            lines->m_pLines[0].finish.x = points[2].x;
            lines->m_pLines[0].finish.y = points[2].y;
            lines->m_pLines[1].start.x = points[2].x;
            lines->m_pLines[1].start.y = points[2].y;
            lines->m_pLines[1].finish.x = points[3].x;
            lines->m_pLines[1].finish.y = points[3].y;
         }
      }

      retRGN = InvertRGN(HXPolygonRegion(points, 5, WindingRule),left, top, right, bottom);
   }
   else
   {
      int vOffset = (int)((bottom - top) / 2 * (double)(completeness - 500) / 500.0);

      points[0].x = left;
      points[0].y = top + vOffset;
      points[1].x = (right + left) / 2 - (int)((left + right) / 2 * (double)(completeness - 500) / 500.0);
      points[1].y = (top + bottom) / 2;
      points[2].x = left;
      points[2].y = bottom - vOffset;

      if (lines)
      {
         lines->m_nLines = 2;
         lines->m_pLines = new LineSegment[2];

         if (!lines->m_pLines)
         {
            lines->m_nLines = 0;
         }
         else
         {
            lines->m_pLines[0].start.x = points[0].x;
            lines->m_pLines[0].start.y = points[0].y;
            lines->m_pLines[0].finish.x = points[1].x;
            lines->m_pLines[0].finish.y = points[1].y;
            lines->m_pLines[1].start.x = points[1].x;
            lines->m_pLines[1].start.y = points[1].y;
            lines->m_pLines[1].finish.x = points[2].x;
            lines->m_pLines[1].finish.y = points[2].y;
         }
      }

      retRGN = InvertRGN(HXPolygonRegion(points, 3, WindingRule),left, top, right, bottom);
   }

   return retRGN;
}

HXREGION* VerticalBowTieEdgeWipe(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   HXREGION* retRGN = HalfBowTieEdgeWipe(left, top, right, bottom, completeness,  NULL);
   HXREGION* tempRGN = MirrorVertical(HalfBowTieEdgeWipe(left, top, right, bottom, completeness,lines),(left + right) / 2);
   HXCombineRgn(retRGN, retRGN, tempRGN, HX_RGN_AND);
   HXDestroyRegion(tempRGN);

   if (lines)
   {
      tranLines tmpLines;
      tmpLines += *lines;
      MirrorVertical(&tmpLines,(left + right) / 2);
      *lines += tmpLines;
   }
   return retRGN;
}

HXREGION* HorizontalBowTieEdgeWipe(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   HXREGION* retRGN = InvertRGN(VerticalBowTieEdgeWipe(left, top, right, bottom, 1000 - completeness,lines), left, top, right, bottom);

   if (lines && lines->m_nLines == 4)
   {
      MirrorHorizontal(lines,(top + bottom) / 2);
      lines->m_pLines[0].Clip(left,top,(right + left) / 2, bottom);
      lines->m_pLines[1].Clip(left,top,(right + left) / 2, bottom);
      lines->m_pLines[2].Clip((right + left) / 2,top,right, bottom);
      lines->m_pLines[3].Clip((right + left) / 2,top,right, bottom);
   }

   return retRGN;
}

HXREGION* DiagonaLeftOutEdgeWipe(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   HXxPoint points[6];
        
   points[0].x = (int) (right - ((double)(right - left)) * ((double)completeness / 1000.0));
   points[0].y = top;
   points[1].x = right;
   points[1].y = top;
   points[2].x = right;
   points[2].y = (int) (top + ((double)(bottom - top)) * ((double)completeness/ 1000.0));
   points[3].x = (int) (left + ((double)(right - left)) * ((double)completeness/ 1000.0));
   points[3].y = bottom;
   points[4].x = left;
   points[4].y = bottom;
   points[5].x = left;
   points[5].y = (int) (bottom - ((double)(bottom - top)) * ((double)completeness/ 1000.0));
        
   if (lines)
   {
      lines->m_nLines = 2;
      lines->m_pLines = new LineSegment[2];

      if (!lines->m_pLines)
      {
         lines->m_nLines = 0;
      }
      else
      {
         lines->m_pLines[0].start.x = points[0].x;
         lines->m_pLines[0].start.y = points[0].y;
         lines->m_pLines[0].finish.x = points[5].x;
         lines->m_pLines[0].finish.y = points[5].y;
         lines->m_pLines[1].start.x = points[2].x;
         lines->m_pLines[1].start.y = points[2].y;
         lines->m_pLines[1].finish.x = points[3].x;
         lines->m_pLines[1].finish.y = points[3].y;
      }
   }

   return HXPolygonRegion(points, 6, WindingRule);
}


HXREGION* DiagonaRightOutEdgeWipe(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   HXREGION* retRGN = DiagonaLeftOutEdgeWipe(left,top,right,bottom,completeness,lines);
   if (lines)
      MirrorVertical(lines,(right - left) / 2);

   return MirrorVertical(retRGN,(right - left) / 2);
}

HXREGION* DiagonaCrossEdgeWipe(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   LineSegment ls;
   HXxPoint p[16];

   int xOff = int(double(right - left) / 2000.0 * completeness);
   int yOff = int(double(bottom - top) / 2000.0 * completeness);
   int midX = (right + left) / 2;
   int midY = (bottom + top) / 2;

   p[0].x = left + xOff;
   p[0].y = top;
   p[1].x = midX;
   p[1].y = midY - yOff;
   p[2].x = right - xOff;
   p[2].y = top;

   p[3].x = right;
   p[3].y = top;

   if (lines)
   {
      ls.start.x = p[0].x;
      ls.start.y = p[0].y;
      ls.finish.x = p[1].x;
      ls.finish.y = p[1].y;
      *lines += ls;
      ls.start.x = p[2].x;
      ls.start.y = p[2].y;
      ls.finish.x = p[1].x;
      ls.finish.y = p[1].y;
      *lines += ls;
   }

   p[4].x = right;
   p[4].y = top + yOff;
   p[5].x = midX + xOff;
   p[5].y = midY;
   p[6].x = right;
   p[6].y = bottom - yOff;

   p[7].x = right;
   p[7].y = bottom;

   if (lines)
   {
      ls.start.x = p[4].x;
      ls.start.y = p[4].y;
      ls.finish.x = p[5].x;
      ls.finish.y = p[5].y;
      *lines += ls;
      ls.start.x = p[6].x;
      ls.start.y = p[6].y;
      ls.finish.x = p[5].x;
      ls.finish.y = p[5].y;
      *lines += ls;
   }
        
   p[8].x = right - xOff;
   p[8].y = bottom;
   p[9].x = midX;
   p[9].y = midY + yOff;
   p[10].x = left + xOff;
   p[10].y = bottom;

   p[11].x = left;
   p[11].y = bottom;

   if (lines)
   {
      ls.start.x = p[8].x;
      ls.start.y = p[8].y;
      ls.finish.x = p[9].x;
      ls.finish.y = p[9].y;
      *lines += ls;
      ls.start.x = p[10].x;
      ls.start.y = p[10].y;
      ls.finish.x = p[9].x;
      ls.finish.y = p[9].y;
      *lines += ls;
   }

   p[12].x = left;
   p[12].y = bottom - yOff;
   p[13].x = midX - xOff;
   p[13].y = midY;
   p[14].x = left;
   p[14].y = top + yOff;

   p[15].x = left;
   p[15].y = top;

   if (lines)
   {
      ls.start.x = p[12].x;
      ls.start.y = p[12].y;
      ls.finish.x = p[13].x;
      ls.finish.y = p[13].y;
      *lines += ls;
      ls.start.x = p[14].x;
      ls.start.y = p[14].y;
      ls.finish.x = p[13].x;
      ls.finish.y = p[13].y;
      *lines += ls;
   }
        
   return HXPolygonRegion(p, 16, WindingRule);
}

HXREGION* DiagonalBoxEdgeWipe(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   tranLines* tmpLines = NULL;
   if (lines)
      tmpLines = new tranLines;

   HXREGION* retRGN = DiamondIris(left, top, right, bottom, completeness/2+500,lines);
   HXREGION* rgn1 = DiamondIris(left, top, right, bottom, 500 - completeness/2,tmpLines);
   HXCombineRgn(retRGN, retRGN, rgn1, HX_RGN_XOR);
   HXDestroyRegion(rgn1);

   if (lines)
   {
      *lines += *tmpLines;
      delete tmpLines;
   }
        
   return retRGN;
}


HXREGION* FilledVEdgeWipe(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   HXxPoint points[3];
        
   points[0].x = (int) ((right+left)/2 + ((double)(right - left)) * (  (double)completeness/ 1000.0));
   points[0].y = top;
   points[1].x = (int) ((right+left)/2 - ((double)(right - left)) * (  (double)completeness/ 1000.0));
   points[1].y = top;
   points[2].x = (right+left)/2;
   points[2].y = (int) (top + ((double)(bottom - top)) * 2.0  * ( (double)completeness/ 1000.0));
        
   if (lines)
   {
      lines->m_nLines = 2;
      lines->m_pLines = new LineSegment[2];

      if (!lines->m_pLines)
      {
         lines->m_nLines = 0;
      }
      else
      {
         lines->m_pLines[0].start.x = points[0].x;
         lines->m_pLines[0].start.y = points[0].y;
         lines->m_pLines[0].finish.x = points[2].x;
         lines->m_pLines[0].finish.y = points[2].y;
         lines->m_pLines[1].start.x = points[1].x;
         lines->m_pLines[1].start.y = points[1].y;
         lines->m_pLines[1].finish.x = points[2].x;
         lines->m_pLines[1].finish.y = points[2].y;
      }
   }

   return HXPolygonRegion( points, 3, WindingRule);
}

HXREGION* FilledVRightEdgeWipe(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   HXxPoint points[3];
        
   points[0].x = right; 
   points[0].y = (int) ((bottom+top)/2 + ((double)(bottom - top)) * (  (double)completeness/ 1000.0));
   points[1].x = right; 
   points[1].y = (int) ((bottom+top)/2 - ((double)(bottom - top)) * (  (double)completeness/ 1000.0));
   points[2].x = (int) (right - ((double)(right - top)) * 2.0  * ( (double)completeness/ 1000.0));
   points[2].y = (bottom+top)/2;
        
   if (lines)
   {
      lines->m_nLines = 2;
      lines->m_pLines = new LineSegment[2];

      if (!lines->m_pLines)
      {
         lines->m_nLines = 0;
      }
      else
      {
         lines->m_pLines[0].start.x = points[0].x;
         lines->m_pLines[0].start.y = points[0].y;
         lines->m_pLines[0].finish.x = points[2].x;
         lines->m_pLines[0].finish.y = points[2].y;
         lines->m_pLines[1].start.x = points[1].x;
         lines->m_pLines[1].start.y = points[1].y;
         lines->m_pLines[1].finish.x = points[2].x;
         lines->m_pLines[1].finish.y = points[2].y;
      }
   }

   return HXPolygonRegion( points, 3, WindingRule);
}

HXREGION* FilledVBottomEdgeWipe(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   HXREGION* retRgn = FilledVEdgeWipe(left,top,right,bottom,completeness,lines);
   if (lines)
      MirrorHorizontal(lines,(top + bottom) / 2);

   return MirrorHorizontal(retRgn,(top + bottom) / 2);
}

HXREGION* FilledVLeftEdgeWipe(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   HXREGION* retRgn = FilledVRightEdgeWipe(left,top,right,bottom,completeness,lines);
   if (lines)
      MirrorVertical(lines,(left + right) / 2);

   return MirrorVertical(retRgn,(left + right) / 2);
}

HXREGION* HollowVEdgeWipe(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   tranLines* tmp = NULL;

   if (lines)
      tmp = new tranLines;

   HXREGION* retRGN = FilledVEdgeWipe(left, top, right, bottom, 500+ completeness/2,lines);
   HXREGION* rgn1 = FilledVEdgeWipe(left, top, right, bottom, 500 - completeness/2,tmp);

   if (lines)
   {
      *lines += *tmp;
      delete tmp;
   }
        
   HXCombineRgn(retRGN, retRGN, rgn1, HX_RGN_XOR);
   HXDestroyRegion(rgn1);
        
   return retRGN;
}

HXREGION* HollowVRightEdgeWipe(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   tranLines* tmp = NULL;

   if (lines)
      tmp = new tranLines;

   HXREGION* retRGN = FilledVRightEdgeWipe(left, top, right, bottom, 500+ completeness/2,lines);
   HXREGION* rgn1 = FilledVRightEdgeWipe(left, top, right, bottom, 500 - completeness/2,tmp);
        
   if (lines)
   {
      *lines += *tmp;
      delete tmp;
   }
        
   HXCombineRgn(retRGN, retRGN, rgn1, HX_RGN_XOR);
   HXDestroyRegion(rgn1);
        
   return retRGN;
}

HXREGION* HollowVLeftEdgeWipe(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   HXREGION* retRgn = HollowVRightEdgeWipe(left,top,right,bottom,completeness,lines);
   if (lines)
      MirrorVertical(lines,(left + right) / 2);

   return MirrorVertical(retRgn,(left + right) / 2);
}

HXREGION* HollowVBottomEdgeWipe(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   HXREGION* retRgn = HollowVEdgeWipe(left,top,right,bottom,completeness,lines);
   if (lines)
      MirrorHorizontal(lines,(top + bottom) / 2);

   return MirrorHorizontal(retRgn,(top + bottom) / 2);
}

HXREGION* VerticalZigZagEdgeWipe(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   int width = right - left;
        
   if (!width)
      ++width;
        
   HXxPoint points[13];
   // this is the width of the zigzag portion
   int zigzag = (int) ((float)(bottom - top + 1) / 10.0+.5);
   int tmpCompleteness = (int) ((float)completeness * (float)(right - left + zigzag + 1) / (float)width+.5);
        
   points[0].x = left - zigzag;
   points[0].y = top;
   points[1].x = left + (width * tmpCompleteness) / 1000 - zigzag;
   points[1].y = top;
        
   for(int i = 1; i< 11; i++)
   {
      points[i+1].x = left + (width * tmpCompleteness) / 1000 - !(i & 1) * zigzag;
      points[i+1].y = top + zigzag * i;
   }
        
   points[12].x = left-zigzag;
   points[12].y = bottom;
        
   if (lines)
   {
      lines->m_nLines = 10;
      lines->m_pLines = new LineSegment[10];

      if (!lines->m_pLines)
      {
         lines->m_nLines = 0;
      }
      else
      {
         for(int i = 1; i < 11; i++)
         {
            lines->m_pLines[i-1].start.x = points[i].x;
            lines->m_pLines[i-1].start.y = points[i].y;
            lines->m_pLines[i-1].finish.x = points[i + 1].x;
            lines->m_pLines[i-1].finish.y = points[i + 1].y;
         }
      }
   }
        
   return HXPolygonRegion( points, 13, WindingRule);
}

HXREGION* HorizontalZigZagEdgeWipe(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   // this is the height of the zigzag portion
   int height = bottom - top;
        
   if (!height)
      ++height;
        
   int zigzag = (int)(((float)right - (float)left) / 10.0 +.5);
   int tmpCompleteness = completeness * (bottom - top + zigzag + 1) / height;
   int worknow = (int)(((float)height * (float)tmpCompleteness) / 1000.0 +.5);
   
   HXxPoint points[13];
        
   points[0].x = left;
   points[0].y = top - zigzag;
   points[1].x = left;
   points[1].y = top  + worknow - zigzag;
        
   for(int i = 1; i< 11; i++)
   {
      points[i+1].y = top + worknow - !(i & 1) * zigzag;
      points[i+1].x = left + zigzag * i ;
   }
        
   points[12].x = right;
   points[12].y = top  - zigzag;
        
   if (lines)
   {
      lines->m_nLines = 10;
      lines->m_pLines = new LineSegment[10];

      if (!lines->m_pLines)
      {
         lines->m_nLines = 0;
      }
      else
      {
         for(int i = 1; i < 11; i++)
         {
            lines->m_pLines[i-1].start.x = points[i].x;
            lines->m_pLines[i-1].start.y = points[i].y;
            lines->m_pLines[i-1].finish.x = points[i + 1].x;
            lines->m_pLines[i-1].finish.y = points[i + 1].y;
         }
      }
   }
        
   return HXPolygonRegion( points, 13, WindingRule);
}


HXREGION* HorizontalBarnZigZagEdgeWipe(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   tranLines* tmp = NULL;

   if (lines)
      tmp = new tranLines;

   HXREGION* retRGN = HorizontalZigZagEdgeWipe(left, top, right, bottom, (int) (500 - (double)completeness/2),lines);
   HXREGION* rgn1 = HorizontalZigZagEdgeWipe(left, top, right, bottom, 500 + completeness/2,tmp);
   HXCombineRgn(retRGN, retRGN, rgn1, HX_RGN_XOR);
   HXDestroyRegion(rgn1);

   if (lines)
   {
      *lines += *tmp;
      delete tmp;
   }

   return retRGN;
}

HXREGION* VerticalBarnZigZagEdgeWipe(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   tranLines* tmp = NULL;

   if (lines)
      tmp = new tranLines;

   HXREGION* retRGN = VerticalZigZagEdgeWipe(left, top, right, bottom, (int) (500 - (double)completeness/2),lines);
   HXREGION* rgn1 = VerticalZigZagEdgeWipe(left, top, right, bottom, 500 + completeness/2,tmp);
   HXCombineRgn(retRGN, retRGN, rgn1, HX_RGN_XOR);
   HXDestroyRegion(rgn1);

   if (lines)
   {
      *lines += *tmp;
      delete tmp;
   }

   return retRGN;
}

HXREGION* InternalRotatingTopRadial(int left, int top, int right, int bottom, int completeness = NULL, tranLines* lines = NULL)
{
   HXxPoint points[8];
        
   points[0].x = (left+right)/2;
   points[0].y = (top+bottom)/2;
   points[1].x = points[0].x; //(left+right)/2;
   points[1].y = top;

   int count = 2;
   for(int temp = completeness; temp >= 125; temp-=250)
   {
      points[count].x = count < 4 ? right : left;
      points[count].y = (count>2) && (count<5) ? bottom : top;
      count++;
   }
        
   double r = max(right - left, bottom - top);
   r*=2.0;
        
   double angle = ((double)completeness/1000.0) * PI * 2.0;
   points[count].x = (left+right)/2 + (int) (r * sin(angle));
   points[count].y = (top+bottom)/2 - (int) (r * cos(angle));
   count++;
        
   HXREGION* retRGN  = HXPolygonRegion( points, count, WindingRule);

   if (lines)
   {
      lines->m_nLines = 1;
      lines->m_pLines = new LineSegment[1];
      lines->m_pLines->start.x = points[0].x;
      lines->m_pLines->start.y = points[0].y;
      lines->m_pLines->finish.x = points[count-1].x;
      lines->m_pLines->finish.y = points[count-1].y;
   }
        
   return retRGN;
}

HXREGION* RotatingTopRadial(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   HXREGION* retRGN = InternalRotatingTopRadial(left, top, right, bottom, completeness, lines);
   if (lines)
   {
      LineSegment ls;
      ls.start.x = (left + right) / 2;
      ls.start.y = (top + bottom) / 2;
      ls.finish.x = ls.start.x;
      ls.finish.y = top;
      *lines += ls;
   }

   return retRGN;
}

HXREGION* InternalRotatingRightRadial(int left, int top, int right, int bottom, int completeness, tranLines* lines = NULL)
{
   HXREGION* retRGN = InternalRotatingTopRadial(left, top, right, bottom, (completeness+250)> 1000 ? 1000: completeness+250,lines);
   HXREGION* rgn1 = InternalRotatingTopRadial(left, top, right, bottom, 250);
   HXCombineRgn(retRGN, retRGN, rgn1, HX_RGN_DIFF);
   HXDestroyRegion(rgn1);
        
   if (completeness > 750)
   {
      if (lines)
      {
         lines->Destroy(); // need to remove the ones we put in by the 1st call to IRTR()
      }

      HXREGION* rgn1 = InternalRotatingTopRadial(left, top, right, bottom, completeness - 750,  lines);
      HXCombineRgn(retRGN, retRGN, rgn1, HX_RGN_OR);
      HXDestroyRegion(rgn1);
   }
        
   return retRGN;
}

HXREGION* RotatingRightRadial(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   HXREGION* retRGN = InternalRotatingRightRadial(left, top, right, bottom, completeness,lines);

   if (lines)
   {
      LineSegment ls;
      ls.start.x = (left + right) / 2;
      ls.start.y = (top + bottom) / 2;
      ls.finish.x = right;
      ls.finish.y = ls.start.y;
      *lines += ls;
   }
   return retRGN;
}

HXREGION* InternalRotatingBottomRadial(int left, int top, int right, int bottom, int completeness, tranLines* lines = NULL)
{
   HXREGION* retRGN = InternalRotatingTopRadial(left, top, right, bottom, (completeness+500)> 1000 ? 1000: completeness+500, lines);
   HXREGION* rgn1 = InternalRotatingTopRadial(left, top, right, bottom, 500);
   HXCombineRgn(retRGN, retRGN, rgn1, HX_RGN_DIFF);
   HXDestroyRegion(rgn1);
        
   if (completeness > 500)
   {
      if (lines)
      {
         lines->Destroy(); // need to remove the ones we put in by the 1st call to IRTR()
      }

      HXREGION* rgn1 = InternalRotatingTopRadial(left, top, right, bottom, completeness - 500, lines);
      HXCombineRgn(retRGN, retRGN, rgn1, HX_RGN_OR);
      HXDestroyRegion(rgn1);
   }
        
   return retRGN;
}

HXREGION* RotatingBottomRadial(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   HXREGION* retRGN = InternalRotatingBottomRadial(left, top, right, bottom, completeness,lines);

   if (lines)
   {
      LineSegment ls;
      ls.start.x = (left + right) / 2;
      ls.start.y = (top + bottom) / 2;
      ls.finish.x = ls.start.x;
      ls.finish.y = bottom;
      *lines += ls;
   }
   return retRGN;
}

HXREGION* InternalRotatingLeftRadial(int left, int top, int right, int bottom, int completeness, tranLines* lines = NULL)
{
   HXREGION* retRGN = InternalRotatingTopRadial(left, top, right, bottom, (completeness+750)> 1000 ? 1000: completeness+750, lines);
   HXREGION* rgn1 = InternalRotatingTopRadial(left, top, right, bottom, 750);
   HXCombineRgn(retRGN, retRGN, rgn1, HX_RGN_DIFF);
   HXDestroyRegion(rgn1);
        
   if (completeness > 250)
   {
      if (lines)
      {
         lines->Destroy(); // need to remove the ones we put in by the 1st call to IRTR()
      }

      HXREGION* rgn1 = InternalRotatingTopRadial(left, top, right, bottom, completeness - 250, lines);
      HXCombineRgn(retRGN, retRGN, rgn1, HX_RGN_OR);
      HXDestroyRegion(rgn1);
   }
        
   return retRGN;
}

HXREGION* RotatingLeftRadial(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   HXREGION* retRGN = InternalRotatingLeftRadial(left, top, right, bottom, completeness,lines);

   if (lines)
   {
      LineSegment ls;
      ls.start.x = (left + right) / 2;
      ls.start.y = (top + bottom) / 2;
      ls.finish.x = left;
      ls.finish.y = ls.start.y;
      *lines += ls;
   }
   return retRGN;
}

HXREGION* RotatingTopBottomRadial(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   tranLines* tmpLines = NULL;

   if (lines)
      tmpLines = new tranLines;

   HXREGION* rgn1 = InternalRotatingTopRadial(left, top, right, bottom, completeness/2, lines);
   HXREGION* retRGN = InternalRotatingBottomRadial(left, top, right, bottom, completeness/2, tmpLines);

   if (lines)
   {
      *lines += *tmpLines;
      delete tmpLines;
      LineSegment ls;
      ls.start.x = (left + right) / 2;
      ls.start.y = top;
      ls.finish.x = ls.start.x;
      ls.finish.y = bottom;
      *lines += ls;
   }
        
   HXCombineRgn(retRGN, retRGN, rgn1, HX_RGN_OR);
   HXDestroyRegion(rgn1);
   return retRGN;
}

HXREGION* RotatingLeftRightRadial(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   tranLines* tmpLines = NULL;

   if (lines)
      tmpLines = new tranLines;

   HXREGION* rgn1 = InternalRotatingLeftRadial(left, top, right, bottom, completeness/2,  lines);
   HXREGION* retRGN = InternalRotatingRightRadial(left, top, right, bottom, completeness/2,  tmpLines);
        
   if (lines)
   {
      *lines += *tmpLines;
      delete tmpLines;
      LineSegment ls;
      ls.start.x = left;
      ls.start.y = (top + bottom) / 2;
      ls.finish.x = right;
      ls.finish.y = ls.start.y;
      *lines += ls;
   }
        
   HXCombineRgn(retRGN, retRGN, rgn1, HX_RGN_OR);
   HXDestroyRegion(rgn1);
   return retRGN;
}

HXREGION* RotatingQuadrantRadial(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   tranLines* tmpLines = NULL;

   if (lines)
      tmpLines = new tranLines;

   HXREGION* rgn1 = InternalRotatingLeftRadial(left, top, right, bottom, completeness/4,  lines);
   HXREGION* retRGN = InternalRotatingRightRadial(left, top, right, bottom, completeness/4,  tmpLines);
   HXCombineRgn(retRGN, retRGN, rgn1, HX_RGN_OR);
   HXDestroyRegion(rgn1);
   if (lines)
   {
      *lines += *tmpLines;
      delete tmpLines;
      tmpLines = new tranLines;
   }
        
   rgn1 = InternalRotatingTopRadial(left, top, right, bottom, completeness/4,  tmpLines);
   HXCombineRgn(retRGN, retRGN, rgn1, HX_RGN_OR);
   HXDestroyRegion(rgn1);
   if (lines)
   {
      *lines += *tmpLines;
      delete tmpLines;
      tmpLines = new tranLines;
   }
        
   rgn1 = InternalRotatingBottomRadial(left, top, right, bottom, completeness/4,  tmpLines);
   HXCombineRgn(retRGN, retRGN, rgn1, HX_RGN_OR);
   HXDestroyRegion(rgn1);
   if (lines)
   {
      *lines += *tmpLines;
      delete tmpLines;
      tmpLines = new tranLines;
      LineSegment ls;
      ls.start.x = (left + right) / 2;
      ls.start.y = top;
      ls.finish.x = ls.start.x;
      ls.finish.y = bottom;
      *lines += ls;
      ls.start.x = left;
      ls.start.y = (top + bottom) / 2;
      ls.finish.x = right;
      ls.finish.y = ls.start.y;
      *lines += ls;
   }

   return retRGN;
}

HXREGION* TopBottom180Radial(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   tranLines* tmpLines = NULL;

   if (lines)
      tmpLines = new tranLines;

   HXREGION* retRGN = HXCreateRectRegion(left, top, right-left, bottom-top);
   HXREGION* rgn1 = InternalRotatingTopRadial(left, top, right, bottom, 1000 - completeness / 2,  lines);
   HXCombineRgn(retRGN, retRGN, rgn1, HX_RGN_DIFF);
   HXDestroyRegion(rgn1);
   HXREGION* ret1 = InternalRotatingTopRadial(left, top, right, bottom, completeness / 2,  tmpLines);
   HXCombineRgn(retRGN, retRGN, ret1, HX_RGN_OR);
   HXDestroyRegion(ret1);
        
   if (lines)
   {
      *lines += *tmpLines;
      delete tmpLines;
   }

   return retRGN;
}

HXREGION* RightToLeft180Radial(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   tranLines* tmpLines = NULL;

   if (lines)
      tmpLines = new tranLines;

   HXREGION* retRGN = HXCreateRectRegion(left, top, right-left,bottom-top);
   HXREGION* rgn1 = InternalRotatingRightRadial(left, top, right, bottom, 1000 - completeness / 2,  lines);
   HXCombineRgn(retRGN, retRGN, rgn1, HX_RGN_DIFF);
   HXDestroyRegion(rgn1);
   HXREGION* ret1 = InternalRotatingRightRadial(left, top, right, bottom, completeness / 2,  tmpLines);
   HXCombineRgn(retRGN, retRGN, ret1, HX_RGN_OR);
   HXDestroyRegion(ret1);
        
   if (lines)
   {
      *lines += *tmpLines;
      delete tmpLines;
   }

   return retRGN;
}

HXREGION* topBottom90Radial(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   tranLines* tmpLines = NULL;

   if (lines)
      tmpLines = new tranLines;

   HXREGION* retRGN= InternalRotatingBottomRadial(left, top, right, bottom, 500 - completeness / 4,  lines);
   HXREGION* rgn1 = InternalRotatingBottomRadial(left, top, right, bottom, 500+ completeness / 4,  tmpLines);
   HXCombineRgn(retRGN, rgn1, retRGN, HX_RGN_XOR);
   HXDestroyRegion(rgn1);
   if (lines)
   {
      *lines += *tmpLines;
      delete tmpLines;
      tmpLines = new tranLines;
   }
        
   rgn1 = InternalRotatingTopRadial(left, top, right, bottom, 500 - completeness / 4,  tmpLines);
   HXCombineRgn(retRGN, rgn1, retRGN, HX_RGN_XOR);
   HXDestroyRegion(rgn1);
   if (lines)
   {
      *lines += *tmpLines;
      delete tmpLines;
      tmpLines = new tranLines;
   }
        
   rgn1 = InternalRotatingTopRadial(left, top, right, bottom, 500+ completeness / 4,  tmpLines);
   HXCombineRgn(retRGN, rgn1, retRGN, HX_RGN_XOR);
   HXDestroyRegion(rgn1);
   if (lines)
   {
      *lines += *tmpLines;
      delete tmpLines;
      tmpLines = new tranLines;
   }
        
   return retRGN;
}


HXREGION* RightToLeft90Radial(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   tranLines* tmpLines = NULL;

   if (lines)
      tmpLines = new tranLines;

   HXREGION* retRGN= InternalRotatingBottomRadial(left, top, right, bottom, 250 - completeness / 4,  lines);
   HXREGION* rgn1 = InternalRotatingBottomRadial(left, top, right, bottom, 250+ completeness / 4,  tmpLines);
   HXCombineRgn(retRGN, rgn1, retRGN, HX_RGN_XOR);
   HXDestroyRegion(rgn1);
   if (lines)
   {
      *lines += *tmpLines;
      delete tmpLines;
      tmpLines = new tranLines;
   }
        
   rgn1 = InternalRotatingTopRadial(left, top, right, bottom, 250 - completeness / 4,  tmpLines);
   HXCombineRgn(retRGN, rgn1, retRGN, HX_RGN_XOR);
   HXDestroyRegion(rgn1);
   if (lines)
   {
      *lines += *tmpLines;
      delete tmpLines;
      tmpLines = new tranLines;
   }
        
   rgn1 = InternalRotatingTopRadial(left, top, right, bottom, 250+ completeness / 4,  tmpLines);
   HXCombineRgn(retRGN, rgn1, retRGN, HX_RGN_XOR);
   HXDestroyRegion(rgn1);
   if (lines)
   {
      *lines += *tmpLines;
      delete tmpLines;
      tmpLines = new tranLines;
   }
        
   return retRGN;
}

HXREGION* InternalTop180Radial(int left, int top, int right, int bottom, int completeness, tranLines* lines = NULL)
{
   return InternalRotatingRightRadial(left, top - (bottom-top), right, bottom, completeness / 2,  lines);
}

HXREGION* Top180Radial(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   return InternalTop180Radial(left, top, right, bottom, completeness,  lines);
}

HXREGION* InternalRight180Radial(int left, int top, int right, int bottom, int completeness, tranLines* lines = NULL)
{
   HXREGION* retRGN = InternalRotatingBottomRadial(left - (right -left), top, right, bottom, completeness / 2,  lines);
   HXOffsetRegion(retRGN, (right -left), 0);
   if (lines)
      lines->Offset(right - left, 0);

   return retRGN;
}

HXREGION* Right180Radial(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   return InternalRight180Radial(left, top, right, bottom, completeness,  lines);
}

HXREGION* InternalBottom180Radial(int left, int top, int right, int bottom, int completeness, tranLines* lines = NULL)
{
   HXREGION* retRGN = InternalRotatingLeftRadial(left, top - (bottom-top), right, bottom, completeness / 2,  lines);
   HXOffsetRegion(retRGN, 0, bottom - top);
   if (lines)
      lines->Offset(0, bottom - top);

   return retRGN;
}

HXREGION* Bottom180Radial(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   return InternalBottom180Radial(left, top, right, bottom, completeness,  lines);
}

HXREGION* InternalLeft180Radial(int left, int top, int right, int bottom, int completeness, tranLines* lines = NULL)
{
   return InternalRotatingTopRadial(left - (right -left), top, right, bottom, completeness / 2,  lines);
}

HXREGION* Left180Radial(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   return InternalLeft180Radial(left, top, right, bottom, completeness,  lines);
}

HXREGION* CounterRotatingTopBottomRadial(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   tranLines* tmpLines = NULL;
   if (lines)
      tmpLines = new tranLines;

   HXREGION* retRGN = InternalTop180Radial(left, top, right, bottom, completeness / 2,  lines);
   HXREGION* rgn1 = InternalBottom180Radial(left, top, right, bottom, completeness / 2,  tmpLines);
   HXCombineRgn(retRGN, retRGN, rgn1, HX_RGN_OR);
   HXDestroyRegion(rgn1);

   if (lines)
   {
      *lines += *tmpLines;
      delete tmpLines;
   }

   return retRGN;
}

HXREGION* CounterRotatingLeftRightRadial(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   tranLines* tmpLines = NULL;
   if (lines)
      tmpLines = new tranLines;

   HXREGION* retRGN = InternalLeft180Radial(left, top, right, bottom, completeness / 2,  lines);
   HXREGION* rgn1 = InternalRight180Radial(left, top, right, bottom, completeness / 2,  tmpLines);
   HXCombineRgn(retRGN, retRGN, rgn1, HX_RGN_OR);
   HXDestroyRegion(rgn1);

   if (lines)
   {
      *lines += *tmpLines;
      delete tmpLines;
   }

   return retRGN;
}

HXREGION* DoubleRotatingTopBottomRadial(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   tranLines* tmpLines = NULL;
   if (lines)
      tmpLines = new tranLines;

   HXREGION* retRGN       = InternalBottom180Radial(left, top, right, bottom, 1000 - completeness,lines);
   HXREGION* rgn1 = HXCreateRectRegion(left, top, right-left,bottom-top);
   HXCombineRgn(retRGN, rgn1, retRGN, HX_RGN_DIFF);
   HXDestroyRegion(rgn1);
   rgn1 = InternalTop180Radial(left, top, right, bottom, completeness, tmpLines);
   if (completeness > 500)
      HXCombineRgn(retRGN, retRGN, rgn1, HX_RGN_AND);
   else
      HXCombineRgn(retRGN, retRGN, rgn1, HX_RGN_OR);

   HXDestroyRegion(rgn1);
   if (lines)
   {
      lines->Clip(left,(top + bottom) / 2,right,bottom);
      tmpLines->Clip(left,top,right,(top + bottom) / 2);
      *lines += *tmpLines;
      delete tmpLines;
   }
   return retRGN;
}

HXREGION* DoubleRotatingLeftRightRadial(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   tranLines* tmpLines = NULL;
   if (lines)
      tmpLines = new tranLines;


   HXREGION* retRGN = InternalRight180Radial(left, top, right, bottom, 1000 - completeness,  lines);
   HXREGION* rgn1 = HXCreateRectRegion(left, top, right-left,bottom-top);
   HXCombineRgn(retRGN, rgn1, retRGN, HX_RGN_DIFF);
   HXDestroyRegion(rgn1);
   rgn1 = InternalLeft180Radial(left, top, right, bottom, completeness,  tmpLines);
   if (completeness > 500)
      HXCombineRgn(retRGN, retRGN, rgn1, HX_RGN_AND);
   else
      HXCombineRgn(retRGN, retRGN, rgn1, HX_RGN_OR);

   HXDestroyRegion(rgn1);
   if (lines)
   {
      lines->Clip((left + right) / 2,top,right,bottom);
      tmpLines->Clip(left,top,(left + right) / 2,bottom);
      *lines += *tmpLines;
      delete tmpLines;
   }
   return retRGN;
}

HXREGION* OpenVTopRadial(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   HXREGION* retRgn = MirrorHorizontal(OpenVBottomRadial(left,top,right,bottom,completeness,lines),(top + bottom) / 2);
   if (lines)
      MirrorHorizontal(lines,(top + bottom) / 2);

   return retRgn;
}

HXREGION* OpenVRightRadial(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   HXREGION* retRgn = MirrorVertical(OpenVLeftRadial(left,top,right,bottom,completeness,lines),(left + right) / 2);
   if (lines)
      MirrorVertical(lines,(left + right) / 2);

   return retRgn;
}

HXREGION* OpenVBottomRadial(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   tranLines* tmpLines = NULL;
   if (lines)
      tmpLines = new tranLines;

   HXREGION* retRGN = InternalRotatingLeftRadial(left, top - (bottom - top), right, bottom, 250 - completeness/4,  lines);
   HXOffsetRegion(retRGN, 0, bottom - top);
   retRGN       = InvertRGN(retRGN, left, top, left + (right - left)/2, bottom);
   HXREGION* rgn1 = InternalRotatingTopRadial(left, top - (bottom - top), right, bottom, completeness/4,  tmpLines);
   HXOffsetRegion(rgn1, 0, bottom - top);
   HXCombineRgn(retRGN, rgn1, retRGN, HX_RGN_OR);
   HXDestroyRegion(rgn1);

   if (lines)
   {
      *lines += *tmpLines;
      delete tmpLines;
      lines->Offset(0, bottom - top);
   }
   return retRGN;
}

HXREGION* OpenVLeftRadial(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   tranLines* tmpLines = NULL;
   if (lines)
      tmpLines = new tranLines;

   HXREGION* retRGN = InternalRotatingRightRadial(left - (right - left), top, right, bottom, completeness/4,  lines);
   HXREGION* rgn1 = InternalRotatingTopRadial(left - (right - left), top, right, bottom, 250 - completeness/4,  tmpLines);
   rgn1 = InvertRGN(rgn1, left, top, right, top + (bottom - top) / 2);
   HXCombineRgn(retRGN, rgn1, retRGN, HX_RGN_OR);
   HXDestroyRegion(rgn1);

   if (lines)
   {
      *lines += *tmpLines;
      delete tmpLines;
   }
   return retRGN;
}

HXREGION* OpenVTopBottomRadial(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   tranLines* tmpLines = NULL;
   if (lines)
      tmpLines = new tranLines;

   HXREGION* retRGN = OpenVBottomRadial(left, top, right, bottom, completeness,  lines);
   HXREGION* rgn1  = OpenVTopRadial(left, top, right, bottom, completeness,  tmpLines);
   HXCombineRgn(retRGN, rgn1, retRGN, HX_RGN_AND);
   HXDestroyRegion(rgn1);

   if (lines)
   {
      *lines += *tmpLines;
      delete tmpLines;
   }
   return retRGN;
}

HXREGION* OpenVLeftRightRadial(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   tranLines* tmpLines = NULL;
   if (lines)
      tmpLines = new tranLines;

   HXREGION* retRGN = OpenVLeftRadial(left, top, right, bottom, completeness,  lines);
   HXREGION* rgn1 = OpenVRightRadial(left, top, right, bottom, completeness,  tmpLines);
   HXCombineRgn(retRGN, rgn1, retRGN, HX_RGN_AND);
   HXDestroyRegion(rgn1);

   if (lines)
   {
      *lines += *tmpLines;
      delete tmpLines;
   }
   return retRGN;
}

HXREGION* RotatingTopLeftRadial(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   HXREGION* retRGN = RotatingRightRadial(left - (right - left), top - (bottom - top), right, bottom, completeness / 4,  lines);

   if (lines)
   {
      //XXXSMJ This is cheap!  Changes to RotatingRightRadial() might break this
      lines->m_nLines = 1;
   }
   return retRGN;
}

HXREGION* RotatingBottomLeftRadial(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   HXREGION* retRGN = InvertRGN(RotatingRightRadial(left - (right - left), top, right, bottom +  (bottom - top), 1000 - completeness / 4,  lines), left, top, right, bottom);
   if (lines)
   {
      //XXXSMJ This is cheap!  Changes to RotatingRightRadial() might break this
      lines->m_nLines = 1;
   }
   return retRGN;
}

HXREGION* RotatingBottomRightRadial(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   HXREGION* retRGN = RotatingLeftRadial(left, top, right + (right - left), bottom  + (bottom - top), completeness / 4,  lines);
   if (lines)
   {
      //XXXSMJ This is cheap!  Changes to RotatingLeftRadial() might break this
      lines->m_nLines = 1;
   }
   return retRGN;
}

HXREGION* RotatingTopRightRadial(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   HXREGION* retRGN = InvertRGN(RotatingLeftRadial(left, top - (bottom - top), right + (right - left), bottom, 1000 - completeness / 4,  lines), left, top, right, bottom);
   if (lines)
   {
      //XXXSMJ This is cheap!  Changes to RotatingLeftRadial() might break this
      lines->m_nLines = 1;
   }
   return retRGN;
}

HXREGION* RotatingTopLeftBottomRightRadial(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   LineSegment ls;
   HXxPoint points[3];
        
   points[0].x = left;
   points[0].y = top;
   points[1].x = right;
   points[1].y = (int) (bottom - ((double)(bottom - top)) * ( 1.0 - (double)completeness/ 1000.0));
   points[2].x = right;
   points[2].y = top;
        
   HXREGION* retRGN = HXPolygonRegion( points, 3, WindingRule);
   if (lines)
   {
      ls.start.x = points[0].x;
      ls.start.y = points[0].y;
      ls.finish.x = points[1].x;
      ls.finish.y = points[1].y;
      *lines += ls;
   }
    
   points[0].x = right;
   points[0].y = bottom;
   points[1].x = left;
   points[1].y = (int) (bottom - ((double)(bottom - top)) * ((double)completeness/ 1000.0));
   points[2].x = left;
   points[2].y = bottom;
        
   HXREGION* tempRGN = HXPolygonRegion( points, 3, WindingRule);
   if (lines)
   {
      ls.start.x = points[0].x;
      ls.start.y = points[0].y;
      ls.finish.x = points[1].x;
      ls.finish.y = points[1].y;
      *lines += ls;
   }

   HXCombineRgn(retRGN, retRGN, tempRGN, HX_RGN_OR);
   HXDestroyRegion(tempRGN);
        
   return retRGN;
}

HXREGION* RotatingBottomLeftTopRightRadial(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   LineSegment ls;
   HXxPoint points[3];
        
   points[0].x = left;
   points[0].y = bottom;
   points[1].x = int(left + double(right - left) * double(completeness) / 1000.0);
   points[1].y = top;
   points[2].x = left;
   points[2].y = top;
        
   HXREGION* retRGN = HXPolygonRegion( points, 3, WindingRule);
   if (lines)
   {
      ls.start.x = points[0].x;
      ls.start.y = points[0].y;
      ls.finish.x = points[1].x;
      ls.finish.y = points[1].y;
      *lines += ls;
   }

    
   points[0].x = right;
   points[0].y = top;
   points[1].x = int(right - double(right - left) * double(completeness) / 1000.0);
   points[1].y = bottom;
   points[2].x = right;
   points[2].y = bottom;
        
   HXREGION* tempRGN = HXPolygonRegion( points, 3, WindingRule);
   if (lines)
   {
      ls.start.x = points[0].x;
      ls.start.y = points[0].y;
      ls.finish.x = points[1].x;
      ls.finish.y = points[1].y;
      *lines += ls;
   }

   HXCombineRgn(retRGN, retRGN, tempRGN, HX_RGN_OR);
   HXDestroyRegion(tempRGN);
        
   return retRGN;
}

HXREGION* RotatingTopLeftRightRadial(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   tranLines* tmpLines = NULL;
   if (lines)
      tmpLines = new tranLines;

   HXREGION* retRGN = RotatingTopLeftRadial(left, top, right, bottom, completeness,  lines);
   HXREGION* rgn1 = RotatingTopRightRadial(left, top, right, bottom, completeness,  tmpLines);
   HXCombineRgn(retRGN, retRGN, rgn1, HX_RGN_AND);
   HXDestroyRegion(rgn1);

   if (lines)
   {
      *lines += *tmpLines;
      delete tmpLines;
   }

   return retRGN;
}

HXREGION* RotatingLeftTopBottomRadial(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   tranLines* tmpLines = NULL;
   if (lines)
      tmpLines = new tranLines;

   HXREGION* retRGN = RotatingTopLeftRadial(left, top, right, bottom, 1000 - completeness,  lines);
   HXREGION* rgn1 = RotatingBottomLeftRadial(left, top, right, bottom, 1000 - completeness,  tmpLines);
   HXCombineRgn(retRGN, retRGN, rgn1, HX_RGN_OR);
   HXDestroyRegion(rgn1);

   if (lines)
   {
      *lines += *tmpLines;
      delete tmpLines;
   }

   return InvertRGN(retRGN, left, top, right, bottom);
}

HXREGION* RotatingBottomLeftRightRadial(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   HXREGION* retRGN = MirrorHorizontal(RotatingTopLeftRightRadial(left, top, right, bottom, completeness,  lines),(top + bottom) / 2);
   if (lines)
      MirrorHorizontal(lines,(top + bottom) / 2);

   return retRGN;
}

HXREGION* RotatingRightTopBottomRadial(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   HXREGION* retRGN = MirrorVertical(RotatingLeftTopBottomRadial(left, top, right, bottom, completeness,  lines),(left + right) / 2);
   if (lines)
      MirrorVertical(lines,(left + right) / 2);

   return retRGN;
}

HXREGION* RotatingDoubleCenterRightRadial(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   tranLines* tmpLines = NULL;
   if (lines)
      tmpLines = new tranLines;

   HXREGION* retRGN = RotatingBottomRadial(left, top, right, bottom, 1000 - completeness,  lines);
   HXREGION* rgn1 = RotatingTopRadial(left, top, right, bottom, completeness,  tmpLines);
   rgn1 = InvertRGN(rgn1, left, top, right, bottom);
   HXOffsetRegion(retRGN,0,-(bottom - top) / 4);
   HXOffsetRegion(rgn1,0,(bottom - top) / 4);
   if (completeness > 750)
      HXCombineRgn(retRGN, retRGN, rgn1, HX_RGN_AND);
   else
      HXCombineRgn(retRGN, retRGN, rgn1, HX_RGN_OR);

   HXDestroyRegion(rgn1);

   if (lines)
   {
      lines->Offset(0,-(bottom - top) / 4);
      lines->Clip(left,top,right,(top + bottom) / 2);
      tmpLines->Offset(0,(bottom - top) / 4);
      tmpLines->Clip(left,(top + bottom) / 2,right,bottom);
      *lines += *tmpLines;
      delete tmpLines;
   }

   return InvertRGN(retRGN, left, top, right, bottom);
}

HXREGION* RotatingDoubleCenterTopRadial(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   tranLines* tmpLines = NULL;
   if (lines)
      tmpLines = new tranLines;

   HXREGION* retRGN = RotatingLeftRadial(left, top, right, bottom, completeness,lines);
   retRGN  = InvertRGN(retRGN, left, top, right, bottom);
   HXREGION* rgn1 = RotatingRightRadial(left, top, right, bottom, 1000 - completeness,  tmpLines);
   HXOffsetRegion(retRGN,(right - left) / 4, 0);
   HXOffsetRegion(rgn1,-(right - left) / 4, 0);
   if (completeness > 750)
      HXCombineRgn(retRGN, retRGN, rgn1, HX_RGN_AND);
   else
      HXCombineRgn(retRGN, retRGN, rgn1, HX_RGN_OR);

   HXDestroyRegion(rgn1);

   if (lines)
   {
      lines->Offset((right - left) / 4, 0);
      lines->Clip((right + left) / 2,top,right,bottom);
      tmpLines->Offset(-(right - left) / 4, 0);
      tmpLines->Clip(left,top,(right + left) / 2,bottom);
      *lines += *tmpLines;
      delete tmpLines;
   }

   return InvertRGN(retRGN, left, top, right, bottom);
}

HXREGION* RotatingDoubleCenterTopBottomRadial(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   tranLines* tmpLines = NULL;
   if (lines)
      tmpLines = new tranLines;

   HXREGION* retRGN = InternalRotatingTopRadial(left, top, right, bottom, completeness / 2,  lines);
   HXOffsetRegion(retRGN,0,-(bottom - top) / 4);
   HXREGION* rgn1 = HXCreateRegion();
   CopyRegion(rgn1,retRGN);
   MirrorHorizontal(rgn1,(bottom + top) / 2);
   if (lines)
   {
      lines->Offset(0,-(bottom - top) / 4);
      lines->Clip(left,top,right,(top + bottom) / 2);
      *tmpLines += *lines;
      MirrorHorizontal(tmpLines,(bottom + top) / 2);
      *lines += *tmpLines;
      tmpLines->Destroy();
   }
   HXCombineRgn(retRGN, retRGN, rgn1, HX_RGN_OR);
   CopyRegion(rgn1,retRGN);
   MirrorVertical(rgn1,(left + right) / 2);
   HXCombineRgn(retRGN, retRGN, rgn1, HX_RGN_OR);
   HXDestroyRegion(rgn1);
   if (lines)
   {
      *tmpLines += *lines;
      MirrorVertical(tmpLines,(left + right) / 2);
      *lines += *tmpLines;
      delete tmpLines;
   }
   return retRGN;
}


HXREGION* RotatingDoubleCenterLeftRightRadial(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   tranLines* tmpLines = NULL;
   if (lines)
      tmpLines = new tranLines;

   HXREGION* retRGN = InternalRotatingLeftRadial(left, top, right, bottom, completeness / 2,  lines);
   HXOffsetRegion(retRGN,-(right + left) / 4, 0);
   HXREGION* rgn1 = HXCreateRegion();
   CopyRegion(rgn1,retRGN);
   MirrorHorizontal(rgn1,(bottom + top) / 2);
   if (lines)
   {
      lines->Offset(-(right + left) / 4, 0);
      lines->Clip(left,top,(left + right) / 2,bottom);
      *tmpLines += *lines;
      MirrorHorizontal(tmpLines,(bottom + top) / 2);
      *lines += *tmpLines;
      tmpLines->Destroy();
   }
   HXCombineRgn(retRGN, retRGN, rgn1, HX_RGN_OR);
   CopyRegion(rgn1,retRGN);
   MirrorVertical(rgn1,(left + right) / 2);
   HXCombineRgn(retRGN, retRGN, rgn1, HX_RGN_OR);
   HXDestroyRegion(rgn1);
   if (lines)
   {
      *tmpLines += *lines;
      MirrorVertical(tmpLines,(left + right) / 2);
      *lines += *tmpLines;
      delete tmpLines;
   }
   return retRGN;
}

HXREGION* DoubleDiagonalBottom(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   if (completeness <= 0)
      return HXCreateRegion();
    
   HXxPoint p[7];
   tranLines* tmpLines = NULL;

   GetTopLeftDiagonalCoords(left,top,right,bottom,500 + completeness / 2,p,lines);
   HXREGION* retRGN = HXPolygonRegion(p, 7, WindingRule);
   HXREGION* rgn1 = MirrorHorizontal(MirrorVertical(HXPolygonRegion(p, 7, WindingRule),(left + right) / 2),top + (bottom - top) / 2);
   HXCombineRgn(retRGN, retRGN, rgn1, HX_RGN_AND);

   if (lines)
   {
      tmpLines = new tranLines;
      *tmpLines += *lines;
      MirrorVertical(tmpLines,(left + right) / 2);
      MirrorHorizontal(tmpLines,top + (bottom - top) / 2);
      *lines += *tmpLines;
   }

   if (completeness < 120) // deal with slight overlap until the two snakes meet
   {
      HXREGION* blank1 = InvertRGN(HXCreateRectRegion(left,bottom - p[3].y,right,p[3].y),left,top,right-left,bottom-top);
      HXCombineRgn(retRGN, retRGN, blank1, HX_RGN_AND);

      HXDestroyRegion(blank1);
   }

   HXDestroyRegion(rgn1);
    
   return retRGN;
}

HXREGION* DoubleDiagonalTop(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   HXREGION* retRGN = MirrorVertical(DoubleDiagonalBottom(left, top, right, bottom, completeness,lines),(left + right) / 2);
   if (lines)
      MirrorVertical(lines,(left + right) / 2);

   return retRGN;
}

HXREGION* SlideFromLeft(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   if (lines)
   {
      lines->m_nLines = 0;
      HX_VECTOR_DELETE( lines->m_pLines );
   }
   return HXCreateRectRegion(left, top, right - left, bottom - top);
}

HXREGION* SlideFromTop(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   if (lines)
   {
      lines->m_nLines = 0;
      HX_VECTOR_DELETE( lines->m_pLines );
   }
   return HXCreateRectRegion(left, top, right - left, bottom - top);
}

HXREGION* SlideFromRight(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   if (lines)
   {
      lines->m_nLines = 0;
      HX_VECTOR_DELETE( lines->m_pLines );
   }
   return HXCreateRectRegion(left, top, right - left, bottom - top);
}

HXREGION* SlideFromBottom(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   if (lines)
   {
      lines->m_nLines = 0;
      HX_VECTOR_DELETE( lines->m_pLines );
   }
   return HXCreateRectRegion(left, top, right - left, bottom - top);
}

HXREGION* Crossfade(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   if(lines)
   {
      lines->m_nLines = 0;
      HX_VECTOR_DELETE(lines->m_pLines);
   }
   return HXCreateRectRegion(left, top, right - left, bottom - top);
}

HXREGION* FadeToColor(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   if (lines)
   {
      lines->m_nLines = 0;
      HX_VECTOR_DELETE( lines->m_pLines );
   }
   return HXCreateRectRegion(left, top, right - left, bottom - top);
}

HXREGION* FadeFromColor(int left, int top, int right, int bottom, int completeness, tranLines* lines)
{
   if (lines)
   {
      lines->m_nLines = 0;
      HX_VECTOR_DELETE( lines->m_pLines );
   }
   return HXCreateRectRegion(left, top, right - left, bottom - top);
}

#endif //_TRANSITIONS_ON_









#ifdef _TESTING_TRANITIONS_

#define FORWARD

// sloppy, but cheap for this test program
int z_PaneWidth = 280;
int z_PaneHeight = 250;


struct tranMap
{
   int in;
   int type;
   int subType;
};

tranMap theTranMap[200];

extern tranType     z_TransitionTable[];
extern int          z_nNumberTransitions;


HWND    zm_hwnd;
HWND    zm_comboHWND;
HWND    zm_displayOuter;
HWND    zm_displayInner;

char*   zm_pszWindowClassName = "TestRGNClass";
char*   zm_pszWindowName = "TestRGNWindow";
HFONT   zm_theFONT = 0;
HFONT   zm_theSmallFONT = 0;
HBITMAP zm_hBitmapOLD= 0;
HBITMAP zm_hBitmapNEW= 0;
HBITMAP zm_hScratchSurface= 0;
HBITMAP zm_oldSurface = 0;
HBITMAP zm_oldSurface2 = 0;
HDC     zm_memDC = 0;
HDC     zm_memDC2 = 0;

int currentPosition = 0;
int CurrentTransition = 1;
int CurrentSubType = 0;
int zm_maxRects = 0;
int zm_numFrames = 0;
double zm_startTime;
double zm_totalCPUTime;
int     zm_bRegionEffect = 1;
int     z_pPixelValues[300][300];

double GetAngle(int x, int y, int x1, int y1)
{
   int dx = x- x1;
   int dy = y - y1;
        
   return atan2(dx, dy);
}

int GetRange(int x, int y, int x1, int y1)
{
   return (int) sqrt( (double) ((x1 - x) * (x1 - x) + (y1 - y) * (y1 - y)));
}

void DoPixelTransition(HBITMAP back, HBITMAP front, HBITMAP scratch, int completeness, tranLines* lines)
{
   if (!zm_memDC2)
   {
      HDC hdc = GetDC(0);
      zm_memDC2 = CreateCompatibleDC(hdc);
      ReleaseDC(0, hdc);
   }
        
   zm_oldSurface = (HBITMAP)SelectObject(zm_memDC, back);
   zm_oldSurface2 = (HBITMAP)SelectObject(zm_memDC2, zm_hScratchSurface);
   SelectObject(zm_memDC, front);
        
   if (!z_pPixelValues[0][0])
   {
      for(int y = 0; y<z_PaneWidth; y++)
      {
         for(int x = 0; x< z_PaneWidth; x++)
         {
            z_pPixelValues[x][y]= GetPixel(zm_memDC, x, y);
            if (!x && !y && !z_pPixelValues[x][y])
            {   
               z_pPixelValues[x][y] = 1;
            }
         }
      }
   }
        
   int implodex = 140;
   int implodey = 140;
        
   for(int y = 0; y<z_PaneWidth; y++)
   {
      for(int x = 0; x< z_PaneWidth; x++)
      {
         int color = z_pPixelValues[x][y];
         double  angle= GetAngle(x,y,implodex, implodey);
         int range = GetRange(x,y,implodex, implodey);
         range = (range * (1000 - completeness)) / 1000;
         double mess = (double)completeness/500.0  * PI;
         double scaleFactor = sin(angle*3 + mess)*cos(angle*2 + mess);
         scaleFactor = (1.0 - scaleFactor)* (1000.0 - completeness) / 1000.0 + scaleFactor;
         range = (int) (range * scaleFactor + 0.5);
         int newx = (int) ((double) range * sin (angle + mess / 4) + implodex + 0.5);
         int newy = (int) ((double) range * cos (angle + mess / 4)  + implodey + 0.5);
         SetPixel(zm_memDC2, newx, newy, color);
      }
   }
   SelectObject(zm_memDC, zm_oldSurface);
   SelectObject(zm_memDC2, zm_oldSurface2);
}

double currentTime()
{
   static LARGE_INTEGER QueryPerformanceCounterResult = {0,0};
   static LARGE_INTEGER QueryPerformanceFrequencyResult = {0,0};
        
   QueryPerformanceFrequency(&QueryPerformanceFrequencyResult);
        
   double frequency = ((double)QueryPerformanceFrequencyResult.LowPart + 4294967296.0*QueryPerformanceFrequencyResult.HighPart);
   QueryPerformanceCounter(&QueryPerformanceCounterResult);
        
   return ((double)QueryPerformanceCounterResult.LowPart + 4294967296.0*QueryPerformanceCounterResult.HighPart)/frequency;
}

void PrintStat(int x, int y, char* pszStatName, int stat)
{
   LOGBRUSH logBrush;
   logBrush.lbStyle = BS_SOLID;
   logBrush.lbColor = 0x00000000;
   logBrush.lbHatch = 0;
   HBRUSH brush = CreateBrushIndirect(&logBrush);
        
    
   HDC hdc = GetDC(zm_hwnd);
   char buffer[20]; /* Flawfinder: ignore */
   SetTextColor(hdc, 0x00FFFFFF);
   SetBkColor(hdc, 0x00000000);
   SetBkMode(hdc, OPAQUE);
   HBRUSH oldBrush = (HBRUSH) SelectObject(hdc, brush);
        
   TextOut(hdc, x, y, pszStatName, strlen(pszStatName));
   Rectangle(hdc, x+90, y, x+230, y+20);
   sprintf(buffer, "%d", stat); /* Flawfinder: ignore */
   TextOut(hdc, x+90, y, buffer, strlen(buffer));
   SelectObject(hdc, oldBrush);
   DeleteObject(brush);
   ReleaseDC(zm_hwnd, hdc);
}
#ifdef NO_GRAPHICS
void DoTransition(int currentPosition)
{
   RECT rect;
        
   rect.left    = 0;
   rect.top     = 0;
   rect.right   = z_PaneWidth;
   rect.bottom = z_PaneHeight;
        
   HXDestroyRegion(z_TransitionTable[CurrentTransition].m_pSubTypes[CurrentSubType].m_fpTranFunction(rect.left, rect.top, rect.right, rect.bottom, currentPosition));
}
#endif

LRESULT __declspec(dllexport) __stdcall CWindowProc
(
   HWND hWnd,
   UINT message,
   WPARAM wParam,
   LPARAM lParam
   )
{
   switch (message)
   {
      case WM_TIMER:
      {
         /*  The following commented out code is for determing which 
          *     region is supposed to be old and which is supposed to be new.
          */
                        
         /*
           {
           RECT rect;
           GetClientRect(zm_displayInner, &rect);
           HRGN rgn = CreateRectRgn(rect.left, rect.top, rect.right, rect.bottom);
           SetWindowRgn(zm_displayInner, rgn, FALSE);
           HDC hdc = GetDC(zm_displayInner);
           FillRect(hdc, &rect, (HBRUSH)GetStockObject(BLACK_BRUSH));
           GdiFlush();
           ReleaseDC(zm_displayInner, hdc);
           }
         */
                        
         double startTime = currentTime();
                        
         RECT rect;
                        
         rect.left      = 0;
         rect.top       = 0;
         rect.right     = z_PaneWidth;// - 1;
         rect.bottom = z_PaneHeight;// - 1;
                        
#ifdef FORWARD
         currentPosition += 5;
         if (currentPosition > 1000) currentPosition = 1000;
#else
         currentPosition -= 5;
         if (currentPosition < 0) currentPosition = 0;
#endif
                        
         HXREGION* XclipRgn = InvertRGN(z_TransitionTable[CurrentTransition].m_pSubTypes[CurrentSubType].m_fpTranFunction(rect.left, rect.top, rect.right, rect.bottom, currentPosition),rect.left, rect.top, rect.right, rect.bottom);
                        
         HRGN clipRgn = CreateRectRgn(0,0,0,0);
         for(int i=0 ; i<XclipRgn->numRects ; i++ )
         {
            HRGN tmp = CreateRectRgn(
               XclipRgn->rects[i].x1,
               XclipRgn->rects[i].y1,
               XclipRgn->rects[i].x2,
               XclipRgn->rects[i].y2
               );       
            CombineRgn( clipRgn, clipRgn, tmp, RGN_OR );
            DeleteObject( tmp );
         }
         HXDestroyRegion(XclipRgn);
         if (!zm_theSmallFONT)
         {
            zm_theSmallFONT = CreateFont(15, 0, 0, 0, 700, FALSE, FALSE, FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, "Ariel");
         }
                        
         if (!zm_theFONT)
         {
            zm_theFONT = CreateFont(115, 0, 0, 0, 700, FALSE, FALSE, FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, "Ariel");
         }
         int totalrects;
         totalrects = 0;
                        
         {
            LPRGNDATA   lpRgnData;
            DWORD sizeNeeed = GetRegionData(clipRgn, 0, NULL); 
            lpRgnData = (LPRGNDATA) new char[sizeNeeed];
            GetRegionData(clipRgn, sizeNeeed, lpRgnData); 
            PrintStat(z_PaneWidth + 20, 50, "Old Rects:", lpRgnData->rdh.nCount);
            totalrects += lpRgnData->rdh.nCount;
            delete lpRgnData;
         }
                        
         //  Create Initial Objects.
                        
         if (!zm_memDC)
         {
            HDC hdc = GetDC(0);
            zm_memDC = CreateCompatibleDC(hdc);
            ReleaseDC(0, hdc);
         }
                        
         if (!zm_hBitmapNEW)
         {
            HDC hdc = GetDC(0);
            zm_hBitmapNEW = CreateCompatibleBitmap(hdc, z_PaneWidth, z_PaneHeight);
            ReleaseDC(0, hdc);
                                
            zm_oldSurface = (HBITMAP)SelectObject(zm_memDC, zm_hBitmapNEW);
            LOGBRUSH logBrush;
            logBrush.lbStyle = BS_SOLID;
            logBrush.lbColor = 0x000000FF;
            logBrush.lbHatch = 0;
            HBRUSH brush = CreateBrushIndirect(&logBrush);
                                
            HFONT   oldfont             = (HFONT)SelectObject(zm_memDC, zm_theFONT);
            HBRUSH  oldBrush    = (HBRUSH)SelectObject(zm_memDC, brush);
            Rectangle(zm_memDC, 0,0,z_PaneWidth, z_PaneHeight);
            SetBkMode(zm_memDC, TRANSPARENT);
            SIZE stringSize;
            GetTextExtentPoint32(zm_memDC,"NEW",3,&stringSize);
            TextOut(zm_memDC, (z_PaneWidth - stringSize.cx) / 2, (z_PaneHeight - stringSize.cy) / 2, "NEW", 3);
            GdiFlush();
            SelectObject(zm_memDC, oldBrush);
            DeleteObject(brush);
            SelectObject(zm_memDC, oldfont);
            SelectObject(zm_memDC, zm_oldSurface);
         }
                        
         if (!zm_hBitmapOLD)
         {
            HDC hdc = GetDC(0);
            zm_hBitmapOLD = CreateCompatibleBitmap(hdc, z_PaneWidth, z_PaneHeight);
            ReleaseDC(0, hdc);
                                
            zm_oldSurface = (HBITMAP)SelectObject(zm_memDC, zm_hBitmapOLD);
            LOGBRUSH logBrush;
            logBrush.lbStyle = BS_SOLID;
            logBrush.lbColor = 0x0000FFFF;
            logBrush.lbHatch = 0;
            HBRUSH brush = CreateBrushIndirect(&logBrush);
                                
            HFONT   oldfont             = (HFONT)SelectObject(zm_memDC, zm_theFONT);
            HBRUSH  oldBrush    = (HBRUSH)SelectObject(zm_memDC, brush);
            Rectangle(zm_memDC, 0,0,z_PaneWidth, z_PaneHeight);
            SetBkMode(zm_memDC, TRANSPARENT);
            SIZE stringSize;
            GetTextExtentPoint32(zm_memDC,"OLD",3,&stringSize);
            TextOut(zm_memDC, (z_PaneWidth - stringSize.cx) / 2, (z_PaneHeight - stringSize.cy) / 2, "OLD", 3);
            GdiFlush();
            SelectObject(zm_memDC, oldBrush);
            DeleteObject(brush);
            SelectObject(zm_memDC, oldfont);
            SelectObject(zm_memDC, zm_oldSurface);
         }
                        
         if (zm_bRegionEffect)
         {
            HRGN oldRGN;
            oldRGN = CreateRectRgn(0,0,0,0);
            GetWindowRgn(zm_displayInner, oldRGN);
                                
            SetWindowRgn(zm_displayInner, clipRgn, FALSE);
            HDC hdc = GetDC(zm_displayInner);
            zm_oldSurface = (HBITMAP)SelectObject(zm_memDC, zm_hBitmapOLD);
            BitBlt(hdc, 0,0,z_PaneWidth, z_PaneHeight, zm_memDC, 0,0, SRCCOPY);
                                
            HXREGION* ZclipRgn =  InvertRGN(z_TransitionTable[CurrentTransition].m_pSubTypes[CurrentSubType].m_fpTranFunction(rect.left, rect.top, rect.right, rect.bottom, currentPosition),rect.left, rect.top, rect.right, rect.bottom);
            static LARGE_INTEGER QueryPerformanceCounterResult = {0,0};
            static LARGE_INTEGER QueryPerformanceFrequencyResult = {0,0};
                                
            QueryPerformanceFrequency(&QueryPerformanceFrequencyResult);
                                
            double frequency = ((double)QueryPerformanceFrequencyResult.LowPart + 4294967296.0*QueryPerformanceFrequencyResult.HighPart);
            QueryPerformanceCounter(&QueryPerformanceCounterResult);
                                
            double startTime = ((double)QueryPerformanceCounterResult.LowPart + 4294967296.0*QueryPerformanceCounterResult.HighPart)/frequency;
                                
            clipRgn = CreateRectRgn(0,0,0,0);
            for(int i=0 ; i<ZclipRgn->numRects ; i++ )
            {
               HRGN tmp = CreateRectRgn(
                  ZclipRgn->rects[i].x1,
                  ZclipRgn->rects[i].y1,
                  ZclipRgn->rects[i].x2,
                  ZclipRgn->rects[i].y2
                  );    
               CombineRgn( clipRgn, clipRgn, tmp, RGN_OR);
               DeleteObject( tmp );
            }
                                
            HXDestroyRegion(ZclipRgn);
                                
                                
            QueryPerformanceCounter(&QueryPerformanceCounterResult);
            double endTime = ((double)QueryPerformanceCounterResult.LowPart + 4294967296.0*QueryPerformanceCounterResult.HighPart)/frequency;
                                
            static UINT32 z_nNumTimes = 0;
            static double z_fTotalTime;
            static double z_fAverageTime;
                                
            z_nNumTimes++;
            z_fTotalTime += endTime - startTime;
            z_fAverageTime = z_fTotalTime / (double) z_nNumTimes;
                                /*
                                  if (! (z_nNumTimes % 25))
                                  {
                                  FILE* f1 = ::fopen("c:\\performance.txt", "a+"); 
                                  ::fprintf(f1, "WINDRAW2 - BltToPrimary: %d blts. Total CPU time: %f, CPU/Blt: %f -- Blt/s Second Max: %f\n", z_nNumTimes, z_fTotalTime, z_fAverageTime, 1.0/z_fAverageTime);
                                  fclose(f1);
                                  }
                                
                                */
                                
            HRGN tempRgn = CreateRectRgn(rect.left, rect.top, rect.right, rect.bottom);
            CombineRgn(tempRgn, tempRgn, clipRgn, RGN_XOR);
                                
                                
                                //  Print Region Stats
                                
            {
               LPRGNDATA        lpRgnData;
               DWORD sizeNeeed = GetRegionData(tempRgn, 0, NULL); 
               lpRgnData = (LPRGNDATA) new char[sizeNeeed];
               GetRegionData(tempRgn, sizeNeeed, lpRgnData); 
               PrintStat(z_PaneWidth + 20, 70, "New Rects:", lpRgnData->rdh.nCount);
               totalrects += lpRgnData->rdh.nCount;
               delete lpRgnData;
            }
                                
            SetWindowRgn(zm_displayInner, tempRgn, FALSE);
            SelectObject(zm_memDC, zm_hBitmapNEW);
            BitBlt(hdc, 0,0,z_PaneWidth, z_PaneHeight, zm_memDC, 0,0, SRCCOPY);
            ReleaseDC(zm_displayInner, hdc);
            DeleteObject(clipRgn);
            SelectObject(zm_memDC, zm_oldSurface);
            SetWindowRgn(zm_displayInner, oldRGN, 0);
         }
         else
         {
                                //  Pixel based effects.
                                
            if (!zm_hScratchSurface)
            {
               HDC hdc = GetDC(0);
               zm_hScratchSurface = CreateCompatibleBitmap(hdc, 300,300);
               ReleaseDC(0, hdc);
            }
                                
            DoPixelTransition(zm_hBitmapNEW, zm_hBitmapOLD, zm_hScratchSurface, currentPosition);
            HDC hdc = GetDC(zm_displayInner);
            zm_oldSurface = (HBITMAP)SelectObject(zm_memDC, zm_hScratchSurface);
            BitBlt(hdc, 0,0,z_PaneWidth, z_PaneHeight, zm_memDC, 0,0, SRCCOPY);
            ReleaseDC(zm_displayInner, hdc);
            SelectObject(zm_memDC, zm_oldSurface);
            PrintStat(z_PaneWidth + 20, 170, "Frames:", zm_numFrames);
         }
                        
         //      Print More Stats
         PrintStat(z_PaneWidth + 20, 90, "Sum Rects:", totalrects);
         if (totalrects > zm_maxRects)
         {
            zm_maxRects = totalrects;
         }
         PrintStat(z_PaneWidth + 20, 110, "Max Rects:", zm_maxRects);
         zm_totalCPUTime = zm_totalCPUTime + (currentTime() - startTime);
         PrintStat(z_PaneWidth + 20, 130, "% CPU:", (int) (zm_totalCPUTime*100.0 / (currentTime() - zm_startTime)));
                        
         zm_numFrames++;
         PrintStat(z_PaneWidth + 20, 150, "FPS:", (int) (zm_numFrames/ (currentTime() - zm_startTime)));
                        
         PrintStat(z_PaneWidth + 20, 170, "Complete:", currentPosition);
         break;
      }
      case WM_COMMAND:
      {
         int wNotifyCode = HIWORD(wParam);
         if (wNotifyCode == CBN_SELCHANGE)
         {
#ifdef FORWARD
            currentPosition = -5;
#else
            currentPosition = 1005;
#endif
            int currentSel = SendMessage(zm_comboHWND, CB_GETCURSEL , 0, 0);
                                
                                // clear out the previous transitions memory
            HXDestroyRegion(z_TransitionTable[CurrentTransition].m_pSubTypes[CurrentSubType].m_fpTranFunction(0, 0, 0, 0, MATRIX_TRANSITION_DELETE));
                                
            CurrentTransition = theTranMap[currentSel].type;
            CurrentSubType = theTranMap[currentSel].subType;
            zm_maxRects = 0;
            zm_startTime = currentTime();
            zm_totalCPUTime = 0;
            zm_numFrames = 0;

#ifdef NO_GRAPHICS
            double startTime = currentTime();
                                
            for (int i = 0; i <= 1000; i += 5)
            {
               DoTransition(i);
            }
                                  
            double endTime = currentTime();
            PrintStat(z_PaneWidth + 20, 130, "Time (mu):", (int) ((endTime - startTime) * 1000000));
#endif
         }
         break;
      }
      case WM_DESTROY:
      {
         // clear out the previous transitions memory
         HXDestroyRegion(z_TransitionTable[CurrentTransition].m_pSubTypes[CurrentSubType].m_fpTranFunction(0, 0, 0, 0, MATRIX_TRANSITION_DELETE));
                        
         PostQuitMessage(0);
         break;
      }
   }
    
   return (DefWindowProc(hWnd, message, wParam, lParam));
}

int WINAPI WinMain( HINSTANCE hInstance, 
                    HINSTANCE hPrevInstance, 
                    LPSTR lpCmdLine, 
                    int nCmdShow 
                    )
{
   // get the size of the window from command line
   char* pCLine = strstr(lpCmdLine,"Width");
   if (pCLine)
   {
      pCLine = strchr(pCLine,'=');
      if (pCLine)
      {
         pCLine++;
         z_PaneWidth = atoi(pCLine);
      }
   }
   pCLine = strstr(lpCmdLine,"Height");
   if (pCLine)
   {
      pCLine = strchr(pCLine,'=');
      if (pCLine)
      {
         pCLine++;
         z_PaneHeight = atoi(pCLine);
      }
   }
        
   WNDCLASS wndClass;
        
   wndClass.style               = 0; 
   wndClass.lpfnWndProc = CWindowProc;
   wndClass.cbClsExtra          = 0;    
   wndClass.cbWndExtra          = 0; 
   wndClass.hInstance           = hInstance;
   wndClass.hIcon               = NULL; 
   wndClass.hCursor             = LoadCursor(NULL, IDC_ARROW); 
   wndClass.hbrBackground       = (HBRUSH)GetStockObject(BLACK_BRUSH);
   wndClass.lpszMenuName        = NULL; 
   wndClass.lpszClassName       = zm_pszWindowClassName; 
        
   ::RegisterClass(&wndClass);
        
   wndClass.lpfnWndProc = DefWindowProc;
   wndClass.lpszClassName       = "DefWindowProc"; 
   ::RegisterClass(&wndClass);
        
   ::RegisterClass(&wndClass);
    
   zm_hwnd = CreateWindow(
      zm_pszWindowClassName, 
      zm_pszWindowName, 
      WS_BORDER | WS_CAPTION | WS_CLIPCHILDREN | WS_VISIBLE | WS_SYSMENU, 
      100, 
      100,
      z_PaneWidth + 200,
      z_PaneHeight + 70,
      NULL, 
      NULL, 
      hInstance, 
      NULL);
        
   zm_comboHWND= CreateWindow(
      "COMBOBOX", 
      "combo", 
      WS_VISIBLE | WS_CHILD | CBS_DROPDOWN | WS_VSCROLL, 
      10, 
      10,
      400,
      300,
      zm_hwnd, 
      NULL, 
      hInstance, 
      NULL);
        
   zm_displayOuter = CreateWindow(
      "DefWindowProc", 
      "combo", 
      WS_VISIBLE | WS_CHILD | WS_CLIPCHILDREN, 
      10, 
      40,
      z_PaneWidth,
      z_PaneHeight,
      zm_hwnd, 
      NULL, 
      hInstance, 
      NULL);
        
   zm_displayInner = CreateWindow(
      "DefWindowProc", 
      "combo", 
      WS_VISIBLE | WS_CHILD, 
      0, 
      0,
      z_PaneWidth,
      z_PaneHeight,
      zm_displayOuter, 
      NULL, 
      hInstance, 
      NULL);
        
   int count = 0;
   char name[200]; /* Flawfinder: ignore */
   for(int j = 0; j < z_nNumberTransitionTypes; ++j)
   {
      for(int i = 0; i< z_TransitionTable[j].m_nNum; ++i)
      {
         if (count < 200)
         {
            if (z_TransitionTable[j].m_pSubTypes[i].m_pTranName)
            {
               SafeSprintf(name,200, "%s - %s (%d)",z_TransitionTable[j].m_pName,z_TransitionTable[j].m_pSubTypes[i].m_pTranName,z_TransitionTable[j].m_pSubTypes[i].m_SMPTE);
               SendMessage(zm_comboHWND, CB_ADDSTRING, 0, (long)name);
               theTranMap[count].in = count;
               theTranMap[count].type = j;
               theTranMap[count].subType = i;
               count++;
            }
         }
      }
   }
        
   int number = SendMessage(zm_comboHWND, CB_GETCOUNT, 0, 0);
   SendMessage(zm_comboHWND, CB_SETCURSEL, CurrentTransition, 0);

#ifndef NO_GRAPHICS
   SetTimer(zm_hwnd, 1, 1, NULL);
#endif

   MSG msg;
   while (GetMessage(&msg,NULL,0,0))
   {
      if (msg.message == WM_QUIT)
         break;
                
      TranslateMessage(&msg);
      // Dispatches message to window
      DispatchMessage(&msg);
   }
        
   return msg.wParam ;
}

#endif

