/******************************Module*Header*******************************\ * * ******************* * * GDI SAMPLE CODE * * ******************* * * Module Name: Strips.c * * Copyright (c) 1992-1998 Microsoft Corporation \**************************************************************************/ #include "precomp.h" /******************************Public*Routine******************************\ * VOID vssSolidHorizontal * * Draws left-to-right x-major near-horizontal lines using short-stroke * vectors. Is faster than using the radial-line routine, but only works * when every strip is 15 pels in length or less. * \**************************************************************************/ VOID vssSolidHorizontal( PDEV* ppdev, STRIP* pStrip, LINESTATE* pLineState) { LONG i, cStrips; PLONG pStrips; LONG xPels, xSumPels, yDir; USHORT Cmd, ssCmd, dirDraw, dirSkip; Cmd = DRAW | WRITE | MULTIPLE_PIXELS | DIR_TYPE_RADIAL | LAST_PIXEL_OFF | BUS_SIZE_16 | BYTE_SWAP; cStrips = pStrip->cStrips; IO_FIFO_WAIT(ppdev, 3); IO_CUR_X(ppdev, pStrip->ptlStart.x); IO_CUR_Y(ppdev, pStrip->ptlStart.y); IO_CMD(ppdev, Cmd); // Setup the drawing direction and the skip direction. dirDraw = 0x10; if (!(pStrip->flFlips & FL_FLIP_V)) { yDir = 1; dirSkip = 0xC100; } else { dirSkip = 0x4100; yDir = -1; } // Output the short stroke commands. xSumPels = 0; pStrips = pStrip->alStrips; for (i = 0; i < cStrips; i++) { xPels = *pStrips++; xSumPels += xPels; ssCmd = (USHORT) (dirSkip | dirDraw | xPels); IO_FIFO_WAIT(ppdev, 4); IO_SHORT_STROKE(ppdev, ssCmd); } pStrip->ptlStart.x += xSumPels; pStrip->ptlStart.y += cStrips * yDir; } /******************************Public*Routine******************************\ * VOID vrlSolidHorizontal * * Draws left-to-right x-major near-horizontal lines using radial lines. * \**************************************************************************/ VOID vrlSolidHorizontal( PDEV* ppdev, STRIP* pStrip, LINESTATE* pLineState) { LONG cStrips; USHORT Cmd; LONG i, yInc, x, y; PLONG pStrips; Cmd = DRAW_LINE | DRAW | DIR_TYPE_RADIAL | LAST_PIXEL_OFF | MULTIPLE_PIXELS | DRAWING_DIRECTION_0 | WRITE; cStrips = pStrip->cStrips; x = pStrip->ptlStart.x; y = pStrip->ptlStart.y; yInc = 1; if (pStrip->flFlips & FL_FLIP_V) yInc = -1; pStrips = pStrip->alStrips; for (i = 0; i < cStrips; i++) { IO_FIFO_WAIT(ppdev, 4); IO_CUR_X(ppdev, x); IO_CUR_Y(ppdev, y); IO_MAJ_AXIS_PCNT(ppdev, *pStrips); IO_CMD(ppdev, Cmd); x += *pStrips++; y += yInc; } pStrip->ptlStart.x = x; pStrip->ptlStart.y = y; } /******************************Public*Routine******************************\ * VOID vssSolidVertical * * Draws left-to-right y-major near-vertical lines using short-stroke * vectors. Is faster than using the radial-line routine, but only works * when every strip is 15 pels in length or less. * \**************************************************************************/ VOID vssSolidVertical( PDEV* ppdev, STRIP* pStrip, LINESTATE* pLineState) { LONG i, cStrips; PLONG pStrips; LONG yPels, ySumPels, yDir; USHORT Cmd, ssCmd, dirDraw, dirSkip; Cmd = DRAW | WRITE | MULTIPLE_PIXELS | DIR_TYPE_RADIAL | LAST_PIXEL_OFF | BUS_SIZE_16 | BYTE_SWAP; cStrips = pStrip->cStrips; IO_FIFO_WAIT(ppdev, 3); IO_CUR_X(ppdev, pStrip->ptlStart.x); IO_CUR_Y(ppdev, pStrip->ptlStart.y); IO_CMD(ppdev, Cmd); // Setup the drawing direction and the skip direction. if (!(pStrip->flFlips & FL_FLIP_V)) { yDir = 1; dirDraw = 0xD0; } else { yDir = -1; dirDraw = 0x50; } dirSkip = 0x0100; // Output the short stroke commands. ySumPels = 0; pStrips = pStrip->alStrips; for (i = 0; i < cStrips; i++) { yPels = *pStrips++; ySumPels += yPels; ssCmd = (USHORT) (dirSkip | dirDraw | yPels); IO_FIFO_WAIT(ppdev, 4); IO_SHORT_STROKE(ppdev, ssCmd); } pStrip->ptlStart.x += cStrips; pStrip->ptlStart.y += ySumPels * yDir; } /******************************Public*Routine******************************\ * VOID vrlSolidVertical * * Draws left-to-right y-major near-vertical lines using radial lines. * \**************************************************************************/ VOID vrlSolidVertical( PDEV* ppdev, STRIP* pStrip, LINESTATE* pLineState) { LONG cStrips; USHORT Cmd; LONG i, x, y; PLONG pStrips; cStrips = pStrip->cStrips; pStrips = pStrip->alStrips; x = pStrip->ptlStart.x; y = pStrip->ptlStart.y; if (!(pStrip->flFlips & FL_FLIP_V)) { Cmd = DRAW_LINE | DRAW | DIR_TYPE_RADIAL | LAST_PIXEL_OFF | MULTIPLE_PIXELS | DRAWING_DIRECTION_270 | WRITE; for (i = 0; i < cStrips; i++) { IO_FIFO_WAIT(ppdev, 4); IO_CUR_X(ppdev, x); IO_CUR_Y(ppdev, y); IO_MAJ_AXIS_PCNT(ppdev, *pStrips); IO_CMD(ppdev, Cmd); y += *pStrips++; x++; } } else { Cmd = DRAW_LINE | DRAW | DIR_TYPE_RADIAL | LAST_PIXEL_OFF | MULTIPLE_PIXELS | DRAWING_DIRECTION_90 | WRITE; for (i = 0; i < cStrips; i++) { IO_FIFO_WAIT(ppdev, 4); IO_CUR_X(ppdev, x); IO_CUR_Y(ppdev, y); IO_MAJ_AXIS_PCNT(ppdev, *pStrips); IO_CMD(ppdev, Cmd); y -= *pStrips++; x++; } } pStrip->ptlStart.x = x; pStrip->ptlStart.y = y; } /******************************Public*Routine******************************\ * VOID vssSolidDiagonalHorizontal * * Draws left-to-right x-major near-diagonal lines using short-stroke * vectors. Is faster than using the radial-line routine, but only * works when every strip is 15 pels in length or less. * \**************************************************************************/ VOID vssSolidDiagonalHorizontal( PDEV* ppdev, STRIP* pStrip, LINESTATE* pLineState) { LONG i, cStrips; PLONG pStrips; LONG Pels, SumPels, yDir; USHORT Cmd, ssCmd, dirDraw, dirSkip; Cmd = DRAW | WRITE | MULTIPLE_PIXELS | DIR_TYPE_RADIAL | LAST_PIXEL_OFF | BUS_SIZE_16 | BYTE_SWAP; cStrips = pStrip->cStrips; IO_FIFO_WAIT(ppdev, 3); IO_CUR_X(ppdev, pStrip->ptlStart.x); IO_CUR_Y(ppdev, pStrip->ptlStart.y); IO_CMD(ppdev, Cmd); // Setup the drawing direction and the skip direction. if (!(pStrip->flFlips & FL_FLIP_V)) { yDir = 1; dirDraw = 0xF0; dirSkip = 0x4100; } else { yDir = -1; dirDraw = 0x30; dirSkip = 0xC100; } // Output the short stroke commands. SumPels = 0; pStrips = pStrip->alStrips; for (i = 0; i < cStrips; i++) { Pels = *pStrips++; SumPels += Pels; ssCmd = (USHORT)(dirSkip | dirDraw | Pels); IO_FIFO_WAIT(ppdev, 4); IO_SHORT_STROKE(ppdev, ssCmd); } pStrip->ptlStart.x += SumPels; pStrip->ptlStart.y += (SumPels - cStrips) * yDir; } /******************************Public*Routine******************************\ * VOID vrlSolidDiagonalHorizontal * * Draws left-to-right x-major near-diagonal lines using radial lines. * \**************************************************************************/ VOID vrlSolidDiagonalHorizontal( PDEV* ppdev, STRIP* pStrip, LINESTATE* pLineState) { LONG cStrips; USHORT Cmd; LONG i, x, y; PLONG pStrips; cStrips = pStrip->cStrips; pStrips = pStrip->alStrips; x = pStrip->ptlStart.x; y = pStrip->ptlStart.y; if (!(pStrip->flFlips & FL_FLIP_V)) { Cmd = DRAW_LINE | DRAW | DIR_TYPE_RADIAL | LAST_PIXEL_OFF | MULTIPLE_PIXELS | DRAWING_DIRECTION_315 | WRITE; for (i = 0; i < cStrips; i++) { IO_FIFO_WAIT(ppdev, 4); IO_CUR_X(ppdev, x); IO_CUR_Y(ppdev, y); IO_MAJ_AXIS_PCNT(ppdev, *pStrips); IO_CMD(ppdev, Cmd); y += *pStrips - 1; x += *pStrips++; } } else { Cmd = DRAW_LINE | DRAW | DIR_TYPE_RADIAL | LAST_PIXEL_OFF | MULTIPLE_PIXELS | DRAWING_DIRECTION_45 | WRITE; for (i = 0; i < cStrips; i++) { IO_FIFO_WAIT(ppdev, 4); IO_CUR_X(ppdev, x); IO_CUR_Y(ppdev, y); IO_MAJ_AXIS_PCNT(ppdev, *pStrips); IO_CMD(ppdev, Cmd); y -= *pStrips - 1; x += *pStrips++; } } pStrip->ptlStart.x = x; pStrip->ptlStart.y = y; } /******************************Public*Routine******************************\ * VOID vssSolidDiagonalVertical * * Draws left-to-right y-major near-diagonal lines using short-stroke * vectors. Is faster than using the radial-line routine, but only * works when every strip is 15 pels in length or less. * \**************************************************************************/ VOID vssSolidDiagonalVertical( PDEV* ppdev, STRIP* pStrip, LINESTATE* pLineState) { LONG i, cStrips; PLONG pStrips; LONG Pels, SumPels, yDir; USHORT Cmd, ssCmd, dirDraw, dirSkip; Cmd = DRAW | WRITE | MULTIPLE_PIXELS | DIR_TYPE_RADIAL | LAST_PIXEL_OFF | BUS_SIZE_16 | BYTE_SWAP; cStrips = pStrip->cStrips; IO_FIFO_WAIT(ppdev, 3); IO_CUR_X(ppdev, pStrip->ptlStart.x); IO_CUR_Y(ppdev, pStrip->ptlStart.y); IO_CMD(ppdev, Cmd); // Setup the drawing direction and the skip direction. if (!(pStrip->flFlips & FL_FLIP_V)) { yDir = 1; dirDraw = 0xF0; } else { yDir = -1; dirDraw = 0x30; } dirSkip = 0x8100; // Output the short stroke commands. SumPels = 0; pStrips = pStrip->alStrips; for (i = 0; i < cStrips; i++) { Pels = *pStrips++; SumPels += Pels; ssCmd = (USHORT)(dirSkip | dirDraw | Pels); IO_FIFO_WAIT(ppdev, 4); IO_SHORT_STROKE(ppdev, ssCmd); } pStrip->ptlStart.x += SumPels - cStrips; pStrip->ptlStart.y += SumPels * yDir; } /******************************Public*Routine******************************\ * VOID vrlSolidDiagonalVertical * * Draws left-to-right y-major near-diagonal lines using radial lines. * \**************************************************************************/ VOID vrlSolidDiagonalVertical( PDEV* ppdev, STRIP* pStrip, LINESTATE* pLineState) { LONG cStrips; USHORT Cmd; LONG i, x, y; PLONG pStrips; cStrips = pStrip->cStrips; pStrips = pStrip->alStrips; x = pStrip->ptlStart.x; y = pStrip->ptlStart.y; if (!(pStrip->flFlips & FL_FLIP_V)) { Cmd = DRAW_LINE | DRAW | DIR_TYPE_RADIAL | LAST_PIXEL_OFF | MULTIPLE_PIXELS | DRAWING_DIRECTION_315 | WRITE; for (i = 0; i < cStrips; i++) { IO_FIFO_WAIT(ppdev, 4); IO_CUR_X(ppdev, x); IO_CUR_Y(ppdev, y); IO_MAJ_AXIS_PCNT(ppdev, *pStrips); IO_CMD(ppdev, Cmd); y += *pStrips; x += *pStrips++ - 1; } } else { Cmd = DRAW_LINE | DRAW | DIR_TYPE_RADIAL | LAST_PIXEL_OFF | MULTIPLE_PIXELS | DRAWING_DIRECTION_45 | WRITE; for (i = 0; i < cStrips; i++) { IO_FIFO_WAIT(ppdev, 4); IO_CUR_X(ppdev, x); IO_CUR_Y(ppdev, y); IO_MAJ_AXIS_PCNT(ppdev, *pStrips); IO_CMD(ppdev, Cmd); y -= *pStrips; x += *pStrips++ - 1; } } pStrip->ptlStart.x = x; pStrip->ptlStart.y = y; } /******************************Public*Routine******************************\ * VOID vStripStyledHorizontal * * 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 vStripStyledHorizontal( PDEV* ppdev, STRIP* pstrip, LINESTATE* pls) { LONG x; LONG y; ULONG dirSkip; LONG dy; LONG* plStrip; LONG cStrips; LONG cStyle; LONG cStrip; LONG cThis; ULONG bIsGap; 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): dirSkip = 0x4110; dy = -1; } 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): dirSkip = 0xc110; dy = 1; } cStrips = pstrip->cStrips; // Total number of strips we'll do plStrip = pstrip->alStrips; // Points to current strip x = pstrip->ptlStart.x; // x position of start of first strip y = pstrip->ptlStart.y; // y position of start of first strip // Warm up the hardware so that it will know we'll be outputing // short-stroke vectors, and so that it will have the current position // correctly set if we're starting in the middle of a 'dash': IO_FIFO_WAIT(ppdev, 3); IO_CUR_X(ppdev, x); IO_CUR_Y(ppdev, y); IO_CMD(ppdev, DRAW | WRITE | MULTIPLE_PIXELS | DIR_TYPE_RADIAL | LAST_PIXEL_OFF | BUS_SIZE_16 | BYTE_SWAP); 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; plStrip++; cStrips--; if (cStrips == 0) goto AllDone; cStrip = *plStrip; SkipAGap: cThis = min(cStrip, cStyle); cStyle -= cThis; cStrip -= cThis; x += 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; // We're gonna need the current position to be correct when we // start outputing short-stroke vectors: IO_FIFO_WAIT(ppdev, 2); IO_CUR_X(ppdev, x); // If 'cStrip' is zero, we also need a new strip. if (cStrip != 0) { // There's more to be done in the current strip, so set 'y' // to be the current scan: IO_CUR_Y(ppdev, y); goto OutputADash; } // Set 'y' to be the scan we're about to move to, because we've // finished with the current strip: IO_CUR_Y(ppdev, y + dy); while (TRUE) { // Each time we loop, we move to a new scan and need a new strip: y += dy; plStrip++; cStrips--; if (cStrips == 0) goto AllDone; cStrip = *plStrip; OutputADash: cThis = min(cStrip, cStyle); cStyle -= cThis; cStrip -= cThis; x += cThis; // Short stroke vectors can handle lines that are a maximum of // 15 pels long. When we have to draw a longer consecutive // segment than that, we simply break it into 16 pel portions: while (cThis > 15) { // Draw two horizontal strokes together to make up one 16 pel // segment: IO_FIFO_WAIT(ppdev, 1); IO_SHORT_STROKE(ppdev, 0x1f11); cThis -= 16; } // Draw the remaining lit part of the strip: IO_FIFO_WAIT(ppdev, 1); IO_SHORT_STROKE(ppdev, dirSkip | cThis); 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 vStripStyledVertical * * 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 vStripStyledVertical( PDEV* ppdev, STRIP* pstrip, LINESTATE* pls) { LONG x; LONG y; ULONG dirSkip; ULONG dirSkip16; LONG dy; LONG* plStrip; LONG cStrips; LONG cStyle; LONG cStrip; LONG cThis; ULONG bIsGap; 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): dirSkip = 0x0150; dirSkip16 = 0x5f51; // For drawing 16 pels straight up dy = -1; } 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): dirSkip = 0x01d0; dirSkip16 = 0xdfd1; // For drawing 16 pels straight down dy = 1; } cStrips = pstrip->cStrips; // Total number of strips we'll do plStrip = pstrip->alStrips; // Points to current strip x = pstrip->ptlStart.x; // x position of start of first strip y = pstrip->ptlStart.y; // y position of start of first strip // Warm up the hardware so that it will know we'll be outputing // short-stroke vectors, and so that it will have the current position // correctly set if we're starting in the middle of a 'dash': IO_FIFO_WAIT(ppdev, 3); IO_CUR_X(ppdev, x); IO_CUR_Y(ppdev, y); IO_CMD(ppdev, DRAW | WRITE | MULTIPLE_PIXELS | DIR_TYPE_RADIAL | LAST_PIXEL_OFF | BUS_SIZE_16 | BYTE_SWAP); 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: x++; plStrip++; cStrips--; if (cStrips == 0) goto AllDone; cStrip = *plStrip; SkipAGap: cThis = min(cStrip, cStyle); cStyle -= cThis; cStrip -= cThis; y += (dy > 0) ? cThis : -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; // We're gonna need the current position to be correct when we // start outputing short-stroke vectors: IO_FIFO_WAIT(ppdev, 2); IO_CUR_Y(ppdev, y); // If 'cStrip' is zero, we also need a new strip. if (cStrip != 0) { // There's more to be done in the current strip, so set 'x' // to be the current column: IO_CUR_X(ppdev, x); goto OutputADash; } // Set 'x' to be the column we're about to move to, because we've // finished with the current strip: IO_CUR_X(ppdev, x + 1); while (TRUE) { // Each time we loop, we move to a new column and need a new strip: x++; plStrip++; cStrips--; if (cStrips == 0) goto AllDone; cStrip = *plStrip; OutputADash: cThis = min(cStrip, cStyle); cStyle -= cThis; cStrip -= cThis; y += (dy > 0) ? cThis : -cThis; // Short stroke vectors can handle lines that are a maximum of // 15 pels long. When we have to draw a longer consecutive // segment than that, we simply break it into 16 pel portions: while (cThis > 15) { // Draw two vertical strokes together to make up one 16 pel // segment: IO_FIFO_WAIT(ppdev, 1); IO_SHORT_STROKE(ppdev, dirSkip16); cThis -= 16; } // Draw the remaining lit part of the strip: IO_FIFO_WAIT(ppdev, 1); IO_SHORT_STROKE(ppdev, dirSkip | cThis); 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; }