//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// This source code is licensed under Microsoft Shared Source License
// Version 1.0 for Windows CE.
// For a copy of the license visit http://go.microsoft.com/fwlink/?LinkId=3223.
//
/*


*/

// Flatten to an error of 2/3.  During initial phase, use 18.14 format.

#define TEST_MAGNITUDE_INITIAL    (6 * 0x00002aa0L)

// Error of 2/3.  During normal phase, use 15.17 format.

#define TEST_MAGNITUDE_NORMAL     (TEST_MAGNITUDE_INITIAL << 3)

/**********************************Class***********************************\
* class HFDBASIS32
*
*   Class for HFD vector objects.
*
* Public Interface:
*
*   vInit(p1, p2, p3, p4)       - Re-parameterizes the given control points
*                                 to our initial HFD error basis.
*   vLazyHalveStepSize(cShift)  - Does a lazy shift.  Caller has to remember
*                                 it changes 'cShift' by 2.
*   vSteadyState(cShift)        - Re-parameterizes to our working normal
*                                 error basis.
*
*   vTakeStep()                 - Forward steps to next sub-curve
*   vHalveStepSize()            - Adjusts down (subdivides) the sub-curve
*   vDoubleStepSize()           - Adjusts up the sub-curve
*   lError()                    - Returns error if current sub-curve were
*                                 to be approximated using a straight line
*                                 (value is actually multiplied by 6)
*   fxValue()                   - Returns rounded coordinate of first point in
*                                 current sub-curve.  Must be in steady
*                                 state.
*
* History:
*  10-Nov-1990 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/

class HFDBASIS32
{
private:
    LONG  e0;
    LONG  e1;
    LONG  e2;
    LONG  e3;

public:
    VOID  vInit(FIX p1, FIX p2, FIX p3, FIX p4);
    VOID  vLazyHalveStepSize(LONG cShift);
    VOID  vSteadyState(LONG cShift);
    VOID  vHalveStepSize();
    VOID  vDoubleStepSize();
    VOID  vTakeStep();

	LONG	lParentErrorDividedBy4();
	LONG	lError();
    FIX   fxValue()                { return((e0 + (1L << 12)) >> 13); }
};

/**********************************Class***********************************\
* class BEZIER32
*
*   Bezier cracker.
*
* A hybrid cubic Bezier curve flattener based on KirkO's error factor.
* Generates line segments fast without using the stack.  Used to flatten
* a path.
*
* For an understanding of the methods used, see:
*
*     Kirk Olynyk, "..."
*     Goossen and Olynyk, "System and Method of Hybrid Forward
*         Differencing to Render Bezier Splines"
*     Lien, Shantz and Vaughan Pratt, "Adaptive Forward Differencing for
*     Rendering Curves and Surfaces", Computer Graphics, July 1987
*     Chang and Shantz, "Rendering Trimmed NURBS with Adaptive Forward
*         Differencing", Computer Graphics, August 1988
*     Foley and Van Dam, "Fundamentals of Interactive Computer Graphics"
*
* Public Interface:
*
*   vInit(pptfx)                - pptfx points to 4 control points of
*                                 Bezier.  Current point is set to the first
*                                 point after the start-point.
*   BEZIER32(pptfx)             - Constructor with initialization.
*   vGetCurrent(pptfx)          - Returns current polyline point.
*   bCurrentIsEndPoint()        - TRUE if current point is end-point.
*   vNext()                     - Moves to next polyline point.
*
* History:
*  1-Oct-1991 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/

extern LONGLONG* gpeqErrorHigh;
extern LONGLONG* gpeqErrorLow;

class BEZIER32
{
//private:
public:
    LONG       cSteps;
    HFDBASIS32 x;
    HFDBASIS32 y;
    RECTFX     rcfxBound;

public:
    BOOL bInit(POINTFIX* aptfx, RECTFX*);
    BOOL bNext(POINTFIX* pptfx);
};

#define FRACTION64 28

class HFDBASIS64
{
private:
    LONGLONG e0;
    LONGLONG e1;
    LONGLONG e2;
    LONGLONG e3;

public:
    VOID vInit(FIX p1, FIX p2, FIX p3, FIX p4);
    VOID vHalveStepSize();
    VOID vDoubleStepSize();
    VOID vTakeStep();
    VOID vUntransform(FIX* afx);

    VOID vParentError(LONGLONG* peq);
    VOID vError(LONGLONG* peq);
    FIX fxValue();
};

class BEZIER64
{
//private:
public:
    HFDBASIS64 xLow;
    HFDBASIS64 yLow;
    HFDBASIS64 xHigh;
    HFDBASIS64 yHigh;

    LONGLONG      eqErrorLow;
    RECTFX*    prcfxClip;
    RECTFX     rcfxClip;

    LONG       cStepsHigh;


    LONG       cStepsLow;

//public:

    BOOL bNext(POINTFIX* pptfx);
    VOID vInit(POINTFIX* aptfx, RECTFX* prcfx, LONGLONG* peq);
};

/**********************************Class***********************************\
* class BEZIER
*
* Bezier cracker.  Flattens any Bezier in our 28.4 device space down
* to a smallest 'error' of 2^-7 = 0.0078.  Will use fast 32 bit cracker
* for small curves and slower 64 bit cracker for big curves.
*
* Public Interface:
*
*   vInit(aptfx, prcfxClip, peqError)
*       - pptfx points to 4 control points of Bezier.  The first point
*         retrieved by bNext() is the the first point in the approximation
*         after the start-point.
*
*       - prcfxClip is an optional pointer to the bound box of the visible
*         region.  This is used to optimize clipping of Bezier curves that
*         won't be seen.  Note that this value should account for the pen's
*         width!
*
*       - optional maximum error in 32.32 format, corresponding to Kirko's
*         error factor.
*
*   bNext(pptfx)
*       - pptfx points to where next point in approximation will be
*         returned.  Returns FALSE if the point is the end-point of the
*         curve.
*
* History:
*  1-Oct-1991 -by- J. Andrew Goossen [andrewgo]
* Wrote it.
\**************************************************************************/

class BEZIER
{
private:

    //
    // Can't do a straight union of BEZIER32 and BEZIER64 here because
    // C++ doesn't like the static constructors and destructors of the
    // EQUADs:
    //
    // Note:
    //

    union
    {
        BEZIER64 bez64;
        BEZIER32 bez32;
    } bez;

    BOOL bBez32;

public:
    BEZIER() {}

    VOID vInit(POINTFIX* aptfx,
               RECTFX* prcfxClip = (RECTFX*) NULL,
               LONGLONG* peqError = gpeqErrorLow)
    {
        bBez32 = (peqError == gpeqErrorLow &&
            bez.bez32.bInit(aptfx, prcfxClip));
        if (!bBez32)
            bez.bez64.vInit(aptfx, prcfxClip, peqError);
    }

    BOOL bNext(POINTFIX* pptfx)
    {
        return(bBez32 ?
               bez.bez32.bNext(pptfx) :
               bez.bez64.bNext(pptfx));
    }
};
