/******************************************************************************\
*
* $Workfile:   stripmm.c  $
*
* Do what you can with no line support.
*
* I implemented the horizontal and vertical strip functions using
* solid fills, and removed the usage of diagonal strips.  With a little
* effort you could implement diagonal strips by doing solid fills while
* playing with lDelta.  This is probably not worth the trouble.
*
* Copyright (c) 1992-1997 Microsoft Corporation
* Copyright (c) 1996-1997 Cirrus Logic, Inc.,
*
* $Log:   S:/projects/drivers/ntsrc/display/STRIPMM.C_V  $
 * 
 *    Rev 1.2   10 Jan 1997 15:40:18   PLCHU
 *  
* 
*    Rev 1.1   Oct 10 1996 15:39:22   unknown
*  
* 
*    Rev 1.1   12 Aug 1996 16:55:04   frido
* Removed unaccessed local variables.
*
*    chu01  : 01-02-97  5480 BitBLT enhancement 
*    chu02  : 01-09-97  Macro redefinition
*
\******************************************************************************/

#include "precomp.h"

#define count COMMAND_TOTAL_PACKETS

#define MM_DRAW_HORZ_STRIP(xy, cx, lDelta, cBpp)\
{\
    ULONG   ulDstAddr;\
\
    ulDstAddr = xy;\
\
    CP_MM_WAIT_FOR_BLT_COMPLETE(ppdev, pjBase);\
    CP_MM_XCNT(ppdev, pjBase, (PELS_TO_BYTES(cx) - 1));\
    CP_MM_YCNT(ppdev, pjBase, 0);\
    CP_MM_DST_ADDR(ppdev, pjBase, ulDstAddr);\
    CP_MM_START_BLT(ppdev, pjBase);\
}

#define MM_DRAW_VERT_STRIP(xy, cy, lDelta, cBpp)\
{\
    ULONG   ulDstAddr;\
\
    ulDstAddr = xy;\
\
    CP_MM_WAIT_FOR_BLT_COMPLETE(ppdev, pjBase);\
    CP_MM_XCNT(ppdev, pjBase, (cBpp - 1));\
    CP_MM_YCNT(ppdev, pjBase, (cy - 1));\
    CP_MM_DST_ADDR(ppdev, pjBase, ulDstAddr);\
    CP_MM_START_BLT(ppdev, pjBase);\
}

#define MM_DRAW_VERT_STRIP_FLIPPED(xy, cy, lDelta, cBpp)\
{\
    ULONG   ulDstAddr;\
\
    ulDstAddr = xy - ((cy - 1) * lDelta);\
\
    CP_MM_WAIT_FOR_BLT_COMPLETE(ppdev, pjBase);\
    CP_MM_XCNT(ppdev, pjBase, (cBpp - 1));\
    CP_MM_YCNT(ppdev, pjBase, (cy - 1));\
    CP_MM_DST_ADDR(ppdev, pjBase, ulDstAddr);\
    CP_MM_START_BLT(ppdev, pjBase);\
}

// chu01, chu02
#define MM_DRAW_HORZ_STRIP80(x, y, cx)\
{\
    CP_MM_WAIT_FOR_BLT_COMPLETE(ppdev, pjBase);\
    CP_MM_BLT_EXT_MODE(ppdev, pjBase, ENABLE_XY_POSITION);\
    CP_MM_XCNT(ppdev, pjBase, (cx - 1));\
    CP_MM_YCNT(ppdev, pjBase, 0);\
    CP_MM_DST_ADDR(ppdev, pjBase, 0);\
    CP_MM_DST_Y(ppdev, pjBase, y);\
    CP_MM_DST_X(ppdev, pjBase, x);\
}

#define MM_DRAW_VERT_STRIP80(x, y, cy)\
{\
    CP_MM_WAIT_FOR_BLT_COMPLETE(ppdev, pjBase);\
    CP_MM_BLT_EXT_MODE(ppdev, pjBase, ENABLE_XY_POSITION);\
    CP_MM_XCNT(ppdev, pjBase, 0);\
    CP_MM_YCNT(ppdev, pjBase, (cy - 1));\
    CP_MM_DST_ADDR(ppdev, pjBase, 0);\
    CP_MM_DST_Y(ppdev, pjBase, y);\
    CP_MM_DST_X(ppdev, pjBase, x);\
}

#define MM_DRAW_VERT_STRIP_FLIPPED80(x, y, cy)\
{\
    CP_MM_WAIT_FOR_BLT_COMPLETE(ppdev, pjBase);\
    CP_MM_BLT_EXT_MODE(ppdev, pjBase, ENABLE_XY_POSITION);\
    CP_MM_XCNT(ppdev, pjBase, 0);\
    CP_MM_YCNT(ppdev, pjBase, (cy - 1));\
    CP_MM_DST_ADDR(ppdev, pjBase, 0);\
    CP_MM_DST_Y(ppdev, pjBase, ((y - cy) + 1));\
    CP_MM_DST_X(ppdev, pjBase, x);\
}

/******************************Public*Routine******************************\
* VOID vMmSolidHorizontal
*
* Draws left-to-right x-major near-horizontal lines using solid fills.
*
* Assumes fgRop, BgRop, and Color are already set correctly.
*
\**************************************************************************/

VOID vMmSolidHorizontal(
PDEV*       ppdev,
STRIP*      pStrip,
LINESTATE*  pLineState)
{
    BYTE*   pjBase   = ppdev->pjBase;
    LONG    cBpp     = ppdev->cBpp;
    LONG    lDelta   = ppdev->lDelta;
    LONG    cStrips  = pStrip->cStrips;
    PLONG   pStrips  = pStrip->alStrips;
    LONG    x        = pStrip->ptlStart.x;
    LONG    y        = pStrip->ptlStart.y;
    LONG    xy       = PELS_TO_BYTES(x) + (lDelta * y);
    LONG    yInc     = 1;
    LONG    i;

    DISPDBG((2, "vMmSolidHorizontal"));

    if (!(pStrip->flFlips & FL_FLIP_V))
    {
        //
        // Horizontal strips ->
        //                     ->
        //

        for (i = 0; i < cStrips; i++)
        {
            MM_DRAW_HORZ_STRIP(xy, *pStrips, lDelta, cBpp);
            x += *pStrips;
            xy += PELS_TO_BYTES(*pStrips);  // x+
            xy += lDelta;                   // y+
            pStrips++;
        }
        y += cStrips;
    }
    else
    {
        //
        //                     ->
        // Horizontal strips ->
        //

        for (i = 0; i < cStrips; i++)
        {
            MM_DRAW_HORZ_STRIP(xy, *pStrips, lDelta, cBpp);
            x += *pStrips;
            xy += PELS_TO_BYTES(*pStrips);  // x+
            xy -= lDelta;                   // y+
            pStrips++;
        }
        y -= cStrips;
    }

    pStrip->ptlStart.x = x;
    pStrip->ptlStart.y = y;
}

/******************************Public*Routine******************************\
* VOID vMmSolidVertical
*
* Draws left-to-right y-major near-vertical lines using solid fills.
*
\**************************************************************************/

VOID vMmSolidVertical(
PDEV*       ppdev,
STRIP*      pStrip,
LINESTATE*  pLineState)
{
    BYTE*   pjBase   = ppdev->pjBase;
    LONG    cBpp     = ppdev->cBpp;
    LONG    lDelta   = ppdev->lDelta;
    LONG    cStrips  = pStrip->cStrips;
    PLONG   pStrips  = pStrip->alStrips;
    LONG    x        = pStrip->ptlStart.x;
    LONG    y        = pStrip->ptlStart.y;
    LONG    xy       = PELS_TO_BYTES(x) + (lDelta * y);
    LONG    i;

    DISPDBG((2, "vMmSolidVertical"));

    if (!(pStrip->flFlips & FL_FLIP_V))
    {
        //
        //                  |
        // Vertical strips  v
        //                   |
        //                   v
        //

        for (i = 0; i < cStrips; i++)
        {
            MM_DRAW_VERT_STRIP(xy, *pStrips, lDelta, cBpp);
            y += *pStrips;
            xy += cBpp;                 // x+
            xy += (*pStrips * lDelta);  // y+
            pStrips++;
        }
    }
    else
    {
        //
        //                   ^
        // Vertical strips   |
        //                  ^
        //                  |
        //

        for (i = 0; i < cStrips; i++)
        {
            MM_DRAW_VERT_STRIP_FLIPPED(xy, *pStrips, lDelta, cBpp);
            y -= *pStrips;
            xy += cBpp;                 // x+
            xy -= (*pStrips * lDelta);  // y-
            pStrips++;
        }
    }
    x += cStrips;

    pStrip->ptlStart.x = x;
    pStrip->ptlStart.y = y;
}

/******************************Public*Routine******************************\
* VOID vMmStyledHorizontal
*
* Takes the list of strips that define the pixels that would be lit for
* a solid line, and breaks them into styling chunks according to the
* styling information that is passed in.
*
* This particular routine handles x-major lines that run left-to-right,
* and are comprised of horizontal strips.  It draws the dashes using
* short-stroke vectors.
*
* The performance of this routine could be improved significantly if
* anyone cared enough about styled lines improve it.
*
\**************************************************************************/

VOID vMmStyledHorizontal(
PDEV*       ppdev,
STRIP*      pstrip,
LINESTATE*  pls)
{
    BYTE*   pjBase   = ppdev->pjBase;
    LONG    cBpp     = ppdev->cBpp;
    LONG    lDelta   = ppdev->lDelta;
    LONG    x        = pstrip->ptlStart.x;   // x position of start of first strip
    LONG    y        = pstrip->ptlStart.y;   // y position of start of first strip
    LONG    xy       = PELS_TO_BYTES(x) + (lDelta * y);
    LONG*   plStrip  = pstrip->alStrips;     // Points to current strip
    LONG    cStrips  = pstrip->cStrips;      // Total number of strips we'll do
    LONG    dy;
    LONG    dylDelta;
    LONG    cStyle;
    LONG    cStrip;
    LONG    cThis;
    ULONG   bIsGap;

    DISPDBG((2, "vMmStyledHorizontal"));

    if (pstrip->flFlips & FL_FLIP_V)
    {
        // The minor direction of the line is 90 degrees, and the major
        // direction is 0 (it's a left-to-right x-major line going up):

        dy = -1;
        dylDelta = -lDelta;
    }
    else
    {
        // The minor direction of the line is 270 degrees, and the major
        // direction is 0 (it's a left-to-right x-major line going down):

        dy = 1;
        dylDelta = lDelta;
    }

    cStrip = *plStrip;              // Number of pels in first strip

    cStyle = pls->spRemaining;      // Number of pels in first 'gap' or 'dash'
    bIsGap = pls->ulStyleMask;      // Tells whether in a 'gap' or a 'dash'

    // ulStyleMask is non-zero if we're in the middle of a 'gap',
    // and zero if we're in the middle of a 'dash':

    if (bIsGap)
        goto SkipAGap;
    else
        goto OutputADash;

PrepareToSkipAGap:

    // Advance in the style-state array, so that we can find the next
    // 'dot' that we'll have to display:

    bIsGap = ~bIsGap;
    pls->psp++;
    if (pls->psp > pls->pspEnd)
        pls->psp = pls->pspStart;

    cStyle = *pls->psp;

    // If 'cStrip' is zero, we also need a new strip:

    if (cStrip != 0)
        goto SkipAGap;

    // Here, we're in the middle of a 'gap' where we don't have to
    // display anything.  We simply cycle through all the strips
    // we can, keeping track of the current position, until we run
    // out of 'gap':

    while (TRUE)
    {
        // Each time we loop, we move to a new scan and need a new strip:

        y += dy;
        xy += dylDelta;

        plStrip++;
        cStrips--;
        if (cStrips == 0)
            goto AllDone;

        cStrip = *plStrip;

    SkipAGap:

        cThis   = min(cStrip, cStyle);
        cStyle -= cThis;
        cStrip -= cThis;

        x += cThis;
        xy += PELS_TO_BYTES(cThis);

        if (cStyle == 0)
            goto PrepareToOutputADash;
    }

PrepareToOutputADash:

    // Advance in the style-state array, so that we can find the next
    // 'dot' that we'll have to display:

    bIsGap = ~bIsGap;
    pls->psp++;
    if (pls->psp > pls->pspEnd)
        pls->psp = pls->pspStart;

    cStyle = *pls->psp;

    // If 'cStrip' is zero, we also need a new strip.

    if (cStrip != 0)
    {
        // There's more to be done in the current strip:

        goto OutputADash;
    }

    // We've finished with the current strip:

    while (TRUE)
    {
        // Each time we loop, we move to a new scan and need a new strip:

        y += dy;
        xy += dylDelta;

        plStrip++;
        cStrips--;
        if (cStrips == 0)
            goto AllDone;

        cStrip = *plStrip;

    OutputADash:

        cThis   = min(cStrip, cStyle);
        cStyle -= cThis;
        cStrip -= cThis;

        MM_DRAW_HORZ_STRIP(xy, cThis, lDelta, cBpp);

        x += cThis;
        xy += PELS_TO_BYTES(cThis); // x+

        if (cStyle == 0)
            goto PrepareToSkipAGap;
    }

AllDone:

    // Update our state variables so that the next line can continue
    // where we left off:

    pls->spRemaining   = cStyle;
    pls->ulStyleMask   = bIsGap;
    pstrip->ptlStart.x = x;
    pstrip->ptlStart.y = y;
}

/******************************Public*Routine******************************\
* VOID vMmStyledVertical
*
* Takes the list of strips that define the pixels that would be lit for
* a solid line, and breaks them into styling chunks according to the
* styling information that is passed in.
*
* This particular routine handles y-major lines that run left-to-right,
* and are comprised of vertical strips.  It draws the dashes using
* short-stroke vectors.
*
* The performance of this routine could be improved significantly if
* anyone cared enough about styled lines improve it.
*
\**************************************************************************/

VOID vMmStyledVertical(
PDEV*       ppdev,
STRIP*      pstrip,
LINESTATE*  pls)
{
    BYTE*   pjBase   = ppdev->pjBase;
    LONG    cBpp     = ppdev->cBpp;
    LONG    lDelta   = ppdev->lDelta;
    LONG    x        = pstrip->ptlStart.x;   // x position of start of first strip
    LONG    y        = pstrip->ptlStart.y;   // y position of start of first strip
    LONG    xy       = PELS_TO_BYTES(x) + (lDelta * y);
    LONG*   plStrip  = pstrip->alStrips;     // Points to current strip
    LONG    cStrips  = pstrip->cStrips;      // Total number of strips we'll do
    LONG    dy;
    LONG    dylDelta;
    LONG    cStyle;
    LONG    cStrip;
    LONG    cThis;
    ULONG   bIsGap;

    DISPDBG((2, "vMmStyledVertical")) ;

    if (pstrip->flFlips & FL_FLIP_V)
    {
        // The minor direction of the line is 0 degrees, and the major
        // direction is 90 (it's a left-to-right y-major line going up):

        dy = -1;
        dylDelta = -lDelta;
    }
    else
    {
        // The minor direction of the line is 0 degrees, and the major
        // direction is 270 (it's a left-to-right y-major line going down):

        dy = 1;
        dylDelta = lDelta;
    }

    cStrip = *plStrip;              // Number of pels in first strip

    cStyle = pls->spRemaining;      // Number of pels in first 'gap' or 'dash'
    bIsGap = pls->ulStyleMask;      // Tells whether in a 'gap' or a 'dash'

    // ulStyleMask is non-zero if we're in the middle of a 'gap',
    // and zero if we're in the middle of a 'dash':

    if (bIsGap)
        goto SkipAGap;
    else
        goto OutputADash;

PrepareToSkipAGap:

    // Advance in the style-state array, so that we can find the next
    // 'dot' that we'll have to display:

    bIsGap = ~bIsGap;
    pls->psp++;
    if (pls->psp > pls->pspEnd)
        pls->psp = pls->pspStart;

    cStyle = *pls->psp;

    // If 'cStrip' is zero, we also need a new strip:

    if (cStrip != 0)
        goto SkipAGap;

    // Here, we're in the middle of a 'gap' where we don't have to
    // display anything.  We simply cycle through all the strips
    // we can, keeping track of the current position, until we run
    // out of 'gap':

    while (TRUE)
    {
        // Each time we loop, we move to a new column and need a new strip:

        xy += cBpp;
        x++;

        plStrip++;
        cStrips--;
        if (cStrips == 0)
            goto AllDone;

        cStrip = *plStrip;

    SkipAGap:

        cThis   = min(cStrip, cStyle);
        cStyle -= cThis;
        cStrip -= cThis;

        if (dy > 0)
        {
            y += cThis;
            xy += (cThis * lDelta);
        }
        else
        {
            y -= cThis;
            xy -= (cThis * lDelta);
        }

        if (cStyle == 0)
            goto PrepareToOutputADash;
    }

PrepareToOutputADash:

    // Advance in the style-state array, so that we can find the next
    // 'dot' that we'll have to display:

    bIsGap = ~bIsGap;
    pls->psp++;
    if (pls->psp > pls->pspEnd)
        pls->psp = pls->pspStart;

    cStyle = *pls->psp;

    // If 'cStrip' is zero, we also need a new strip.

    if (cStrip != 0)
    {
        // There's more to be done in the current strip:

        goto OutputADash;
    }

    // We've finished with the current strip:

    while (TRUE)
    {
        // Each time we loop, we move to a new column and need a new strip:

        xy += cBpp;
        x++;

        plStrip++;
        cStrips--;
        if (cStrips == 0)
            goto AllDone;

        cStrip = *plStrip;

    OutputADash:

        cThis   = min(cStrip, cStyle);
        cStyle -= cThis;
        cStrip -= cThis;

        if (dy <= 0)
        {
            MM_DRAW_VERT_STRIP_FLIPPED(xy, cThis, lDelta, cBpp);
            y -=  cThis;                // y-
            xy -=  (cThis * lDelta);    // y-
        }
        else
        {
            MM_DRAW_VERT_STRIP(xy, cThis, lDelta, cBpp);
            y +=  cThis;                // y+
            xy +=  (cThis * lDelta);    // y+
        }


        if (cStyle == 0)
            goto PrepareToSkipAGap;
    }

AllDone:

    // Update our state variables so that the next line can continue
    // where we left off:

    pls->spRemaining   = cStyle;
    pls->ulStyleMask   = bIsGap;
    pstrip->ptlStart.x = x;
    pstrip->ptlStart.y = y;
}

/******************************Public*Routine******************************\
* VOID vInvalidStrip
*
* Put this in the function table for entries that shouldn't get hit.
*
\**************************************************************************/

VOID vInvalidStrip(
PDEV*       ppdev,          // unused
STRIP*      pStrip,         // unused
LINESTATE*  pLineState)     // unused
{

    RIP("vInvalidStrip called");
    return;
}

// chu01
/******************************Public*Routine******************************\
*
*     B i t B L T   E n h a n c e m e n t   F o r   C L - G D 5 4 8 0
*
\**************************************************************************/

VOID vMmSolidHorizontal80(
PDEV*       ppdev,
STRIP*      pStrip,
LINESTATE*  pLineState)
{
    BYTE*   pjBase      = ppdev->pjBase ;
    LONG    cBpp        = ppdev->cBpp ;
    LONG    lDelta      = ppdev->lDelta ;
    LONG    cStrips     = pStrip->cStrips ;
    PLONG   pStrips     = pStrip->alStrips ;   // cx for each stroke
    LONG    x           = pStrip->ptlStart.x ; // X-position
    LONG    y           = pStrip->ptlStart.y ; // Y-position
    LONG    yOrg        = y ;
    LONG    yInc        = 1 ;
    LONG    x0, y0, cx ;

    ULONG   ulDstOffset = 0 ;
    ULONG_PTR* ulCLStart ;
    ULONG   ulWidthHeight ;

    LONG    i           = 0 ;
    BYTE    MM1B ;

    DISPDBG((2, "vMmSolidHorizontal80")) ;

    if (!(pStrip->flFlips & FL_FLIP_V))
    {
        //                          
        // Horizontal strips ->     1.
        //                     ->       2.
        //
        if (cStrips != 1)
        {
            MM1B = ENABLE_COMMAND_LIST | ENABLE_XY_POSITION | SRC_CPU_DATA ;
            CP_MM_BLT_EXT_MODE(ppdev, pjBase, MM1B) ;
Loop_H1:
            ulCLStart = ppdev->pCommandList ;
            ulDstOffset = (ULONG)(((ULONG_PTR)ulCLStart
                                 - (ULONG_PTR)ppdev->pjScreen) << 14) ;
            CP_MM_CL_SWITCH(ppdev) ;

            // First strip
            x0 = x ;
            y0 = y ;
            cx = *pStrips ;
            i++ ;

            // Next strip
            y++ ;
            x += cx ; 
            pStrips++ ;

            while (TRUE)
            {
                // GR20, GR21, GR22, GR23
                ulWidthHeight = PACKXY_FAST((*pStrips - 1), 0) ;
                ulWidthHeight |= COMMAND_NOSRC_NOTHING ;

                // GR40, GR41, GR42, GR43
                *(ulCLStart + 1) = PACKXY_FAST(x, y) ;

                // GR2C, GR2D, GR2E
                *(ulCLStart + 2) = 0 ;

                i++ ;

                if ((i == cStrips) || ((i % count) == 0))
                {
                    // Last Command
                    ulWidthHeight |= COMMAND_LAST_PACKET ;
                    *ulCLStart = ulWidthHeight ;
                    break ;
                }
                *ulCLStart = ulWidthHeight ;

                // Next strip
                y++ ;
                x += *pStrips ; 
                pStrips++ ;
                ulCLStart += 4 ;
            }

            CP_MM_WAIT_FOR_BLT_COMPLETE(ppdev, pjBase) ;
            CP_MM_XCNT(ppdev, pjBase, (cx - 1)) ;
            CP_MM_YCNT(ppdev, pjBase, 0) ;
            CP_MM_DST_ADDR(ppdev, pjBase, ulDstOffset) ;
            CP_MM_DST_Y(ppdev, pjBase, y0) ;
            CP_MM_DST_X(ppdev, pjBase, x0) ;

            if (i == cStrips)
                x += *pStrips ; 
            else if ((i % count) == 0)
            {
                // 
                // Resume a new command list
                //
                y++ ;
                cx = *pStrips ;
                x += cx ; 
                pStrips++ ; 
                if (i != (cStrips - 1))
                {
                    goto Loop_H1 ;
                }
                else
                {
                    MM_DRAW_HORZ_STRIP80(x, y, *pStrips) ;
                    x += *pStrips ;
                    pStrips++;
                }
            }
        }
        else
        {
            MM_DRAW_HORZ_STRIP80(x, y, *pStrips) ;
            x += *pStrips ;
            pStrips++;
        }
        yOrg += cStrips;
    }
    else
    {
        //
        //                     ->     2.
        // Horizontal strips ->     1.
        //
        if (cStrips != 1)
        {
            MM1B = ENABLE_COMMAND_LIST | ENABLE_XY_POSITION | SRC_CPU_DATA ;
            CP_MM_BLT_EXT_MODE(ppdev, pjBase, MM1B) ;
Loop_H2:
            ulCLStart = ppdev->pCommandList;
            ulDstOffset = (ULONG)(((ULONG_PTR)ulCLStart
                                 - (ULONG_PTR)ppdev->pjScreen) << 14) ;
            CP_MM_CL_SWITCH(ppdev) ;

            // First strip
            x0 = x ;
            y0 = y ;
            cx = *pStrips ;
            i++ ;

            // Next strip
            y-- ;
            x += cx ; 
            pStrips++ ;

            while (TRUE)
            {
                // GR20, GR21, GR22, GR23
                ulWidthHeight = PACKXY_FAST((*pStrips - 1), 0) ;
                ulWidthHeight |= COMMAND_NOSRC_NOTHING ;

                // GR40, GR41, GR42, GR43
                *(ulCLStart + 1) = PACKXY_FAST(x, y) ;

                // GR2C, GR2D, GR2E
                *(ulCLStart + 2) = 0 ;

                i++ ;

                if ((i == cStrips) || ((i % count) == 0))
                {
                    // Last Command
                    ulWidthHeight |= COMMAND_LAST_PACKET ;
                    *ulCLStart = ulWidthHeight ;
                    break ;
                }
                *ulCLStart = ulWidthHeight ;

                // Next strip
                y-- ;
                x += *pStrips ; 
                pStrips++ ;
                ulCLStart += 4 ;
            }

            CP_MM_WAIT_FOR_BLT_COMPLETE(ppdev, pjBase) ;
            CP_MM_XCNT(ppdev, pjBase, (cx - 1)) ;
            CP_MM_YCNT(ppdev, pjBase, 0) ;
            CP_MM_DST_ADDR(ppdev, pjBase, ulDstOffset) ;
            CP_MM_DST_Y(ppdev, pjBase, y0) ;
            CP_MM_DST_X(ppdev, pjBase, x0) ;

            if (i == cStrips)
                x += *pStrips ; 
            else if ((i % count) == 0) 
            {
                // 
                // Resume a new command list
                //
                y-- ;
                cx = *pStrips ;
                x += cx ; 
                pStrips++ ; 
                if (i != (cStrips - 1))
                {
                    goto Loop_H2 ;
                }
                else
                {
                    MM_DRAW_HORZ_STRIP80(x, y, *pStrips) ;
                    x += *pStrips ;
                    pStrips++;
                }
            }
        }
        else
        {
            MM_DRAW_HORZ_STRIP80(x, y, *pStrips) ;
            x += *pStrips ;
            pStrips++;
        }
        yOrg -= cStrips;
    }

    pStrip->ptlStart.x = x    ;
    pStrip->ptlStart.y = yOrg ;

}

/******************************Public*Routine******************************\
* VOID vMmSolidVertical80
*
* Draws left-to-right y-major near-vertical lines using solid fills.
*
\**************************************************************************/

VOID vMmSolidVertical80(
PDEV*       ppdev,
STRIP*      pStrip,
LINESTATE*  pLineState)
{
    BYTE*   pjBase      = ppdev->pjBase ;
    LONG    cBpp        = ppdev->cBpp ;
    LONG    lDelta      = ppdev->lDelta ;
    LONG    cStrips     = pStrip->cStrips ;
    PLONG   pStrips     = pStrip->alStrips ;
    LONG    x           = pStrip->ptlStart.x ;
    LONG    y           = pStrip->ptlStart.y ;
    LONG    xOrg        = x ;
    LONG    x0, y0, cy ;

    ULONG   ulDstOffset = 0 ;
    ULONG_PTR* ulCLStart ;
    ULONG   ulWidthHeight ;

    LONG    i           = 0 ;
    BYTE    MM1B ;

    DISPDBG((2, "vMmSolidVertical80")) ;

    if (!(pStrip->flFlips & FL_FLIP_V))
    {
        //
        //                  |     1.
        // Vertical strips  v
        //                   |     2.
        //                   v
        //
        if (cStrips != 1)
        {
            MM1B = ENABLE_COMMAND_LIST | ENABLE_XY_POSITION | SRC_CPU_DATA ;
            CP_MM_BLT_EXT_MODE(ppdev, pjBase, MM1B) ;
Loop_V1:
            ulCLStart = ppdev->pCommandList ;
            ulDstOffset = (ULONG)(((ULONG_PTR)ulCLStart
                                 - (ULONG_PTR)ppdev->pjScreen) << 14) ;
            CP_MM_CL_SWITCH(ppdev) ;

            // First strip
            x0 = x ; 
            y0 = y ;
            cy = *pStrips ;
            i++ ;

            // Next strip
            x++ ; 
            y += cy ; 
            pStrips++ ;

            while (TRUE)
            {
                // GR20, GR21, GR22, GR23
                ulWidthHeight = PACKXY_FAST(0, (*pStrips - 1)) ;
                ulWidthHeight |= COMMAND_NOSRC_NOTHING ;

                // GR40, GR41, GR42, GR43
                *(ulCLStart + 1) = PACKXY_FAST(x, y) ;

                // GR2C, GR2D, GR2E
                *(ulCLStart + 2) = 0 ;

                i++ ;

                if ((i == cStrips) || ((i % count) == 0))
                {
                    // Last Command
                    ulWidthHeight |= COMMAND_LAST_PACKET ;
                    *ulCLStart = ulWidthHeight ;
                    break ;
                }
                *ulCLStart = ulWidthHeight ;

                // Next strip
                x++ ;
                y += *pStrips ; 
                pStrips++ ;
                ulCLStart += 4 ;
            }
            CP_MM_WAIT_FOR_BLT_COMPLETE(ppdev, pjBase) ;
            CP_MM_XCNT(ppdev, pjBase, 0) ;
            CP_MM_YCNT(ppdev, pjBase, (cy - 1)) ;
            CP_MM_DST_ADDR(ppdev, pjBase, ulDstOffset) ;
            CP_MM_DST_Y(ppdev, pjBase, y0) ;
            CP_MM_DST_X(ppdev, pjBase, x0) ;

            if (i == cStrips)
                y += *pStrips ; 
            else if ((i % count) == 0) 
            {
                // 
                // Resume a new command list
                //
                x++ ;
                cy = *pStrips ;
                y += cy ; 
                pStrips++ ; 
                if (i != (cStrips - 1))
                {
                    goto Loop_V1 ;
                }
                else
                {
                    MM_DRAW_VERT_STRIP80(x, y, *pStrips) ;
                    y += *pStrips ;
                    pStrips++;
                }
            }
        }
        else
        {
            MM_DRAW_VERT_STRIP80(x, y, *pStrips) ;
            y += *pStrips ;
            pStrips++;
        }
    }
    else
    {
        //
        //                   ^
        // Vertical strips   |     2.
        //                  ^
        //                  |     1.
        //

        if (cStrips != 1)
        {
            MM1B = ENABLE_COMMAND_LIST | ENABLE_XY_POSITION | SRC_CPU_DATA ;
            CP_MM_BLT_EXT_MODE(ppdev, pjBase, MM1B) ;
Loop_V2:
            ulCLStart = ppdev->pCommandList ;
            ulDstOffset = (ULONG)(((ULONG_PTR)ulCLStart
                                 - (ULONG_PTR)ppdev->pjScreen) << 14) ;
            CP_MM_CL_SWITCH(ppdev) ;

            // First strip
            x0 = x ;
            cy = *pStrips ;
            y -= (cy - 1) ;
            y0 = y ;

            i++ ;
            pStrips++ ;

            // Next strip
            x++ ;
            y -= *pStrips ;

            while (TRUE)
            {
                // GR20, GR21, GR22, GR23
                ulWidthHeight = PACKXY_FAST(0, (*pStrips - 1)) ;
                ulWidthHeight |= COMMAND_NOSRC_NOTHING ;

                // GR40, GR41, GR42, GR43
                *(ulCLStart + 1) = PACKXY_FAST(x, y) ;

                // GR2C, GR2D, GR2E
                *(ulCLStart + 2) = 0 ;

                i++ ;

                if ((i == cStrips) || ((i % count) == 0))
                {
                    // Last Command
                    ulWidthHeight |= COMMAND_LAST_PACKET ;
                    *ulCLStart = ulWidthHeight ;
                    break ;
                }
                *ulCLStart = ulWidthHeight ;

                // Next strip
                x++ ;
                pStrips++ ;
                y -= *pStrips ; 

                ulCLStart += 4 ;
            }

            CP_MM_WAIT_FOR_BLT_COMPLETE(ppdev, pjBase) ;
            CP_MM_XCNT(ppdev, pjBase, 0) ;
            CP_MM_YCNT(ppdev, pjBase, (cy - 1)) ;
            CP_MM_DST_ADDR(ppdev, pjBase, ulDstOffset) ;
            CP_MM_DST_Y(ppdev, pjBase, y0) ;
            CP_MM_DST_X(ppdev, pjBase, x0);

            if (i == cStrips)
                y -= *pStrips ; 
            else if ((i % count) == 0)
            {
                // 
                // Resume a new command list
                //
                x++ ;
                y-- ; 
                pStrips++ ; 

                if (i != (cStrips - 1))
                {
                    goto Loop_V2 ;
                }
                else
                {
                    MM_DRAW_VERT_STRIP80(x, y, *pStrips) ;
                    y -= *pStrips ;
                    pStrips++;
                }
            }
        }
        else
        {
            MM_DRAW_VERT_STRIP_FLIPPED80(x, y, *pStrips) ;
            y -= *pStrips ;
            pStrips++;
        }
    }

    xOrg += cStrips ;
    pStrip->ptlStart.x = xOrg ;
    pStrip->ptlStart.y = y    ;

}