|
|
/******************************************************************************\
* * $Workfile: LineTo.c $ * * Contents: * This file contains the DrvLineTo function and simple line drawing code. * * Copyright (c) 1996 Cirrus Logic, Inc. * * $Log: V:/CirrusLogic/CL54xx/NT40/Archive/Display/LineTo.c_v $ * * Rev 1.4 12 Aug 1996 16:53:50 frido * Added NT 3.5x/4.0 auto detection. * * Rev 1.3 29 Jul 1996 12:23:04 frido * Fixed bug in drawing horizontal lines from right to left. * * Rev 1.2 15 Jul 1996 15:56:12 frido * Changed DST_ADDR into DST_ADDR_ABS. * * Rev 1.1 12 Jul 1996 16:02:06 frido * Redefined some macros that caused irratic line drawing on device bitmaps. * * Rev 1.0 10 Jul 1996 17:53:40 frido * New code. * \******************************************************************************/
#include "PreComp.h"
#if LINETO
#define LEFT 0x01
#define TOP 0x02
#define RIGHT 0x04
#define BOTTOM 0x08
bIoLineTo( PDEV* ppdev, LONG x1, LONG y1, LONG x2, LONG y2, ULONG ulSolidColor, MIX mix, ULONG ulDstAddr) { BYTE* pjPorts = ppdev->pjPorts; LONG lDelta = ppdev->lDelta; LONG dx, dy; LONG cx, cy;
if (ulSolidColor != (ULONG) -1) { if (ppdev->cBpp == 1) { ulSolidColor |= ulSolidColor << 8; ulSolidColor |= ulSolidColor << 16; } else if (ppdev->cBpp == 2) { ulSolidColor |= ulSolidColor << 16; }
CP_IO_WAIT_FOR_BLT_COMPLETE(ppdev, pjPorts); CP_IO_ROP(ppdev, pjPorts, gajHwMixFromMix[mix & 0x0F]); CP_IO_SRC_ADDR(ppdev, pjPorts, ppdev->ulSolidColorOffset); CP_IO_BLT_MODE(ppdev, pjPorts, ENABLE_COLOR_EXPAND | ENABLE_8x8_PATTERN_COPY | ppdev->jModeColor); CP_IO_FG_COLOR(ppdev, pjPorts, ulSolidColor); }
// Calculate deltas.
dx = x2 - x1; dy = y2 - y1;
// Horizontal lines.
if (dy == 0) { if (dx < 0) { // From right to left.
ulDstAddr += PELS_TO_BYTES(x2 - 1) + (y2 * lDelta); cx = PELS_TO_BYTES(-dx) - 1; } else if (dx > 0) { // From left to right.
ulDstAddr += PELS_TO_BYTES(x1) + (y1 * lDelta); cx = PELS_TO_BYTES(dx) - 1; } else { // Nothing to do here!
return(TRUE); }
CP_IO_WAIT_FOR_BLT_COMPLETE(ppdev, pjPorts); CP_IO_XCNT(ppdev, pjPorts, cx); CP_IO_YCNT(ppdev, pjPorts, 0); CP_IO_DST_ADDR_ABS(ppdev, pjPorts, ulDstAddr); CP_IO_START_BLT(ppdev, pjPorts);
return(TRUE); }
// Vertical lines.
else if (dx == 0) { if (dy < 0) { // From bottom to top.
ulDstAddr += PELS_TO_BYTES(x2) + ((y2 + 1) * lDelta); cy = -dy - 1; } else { // From top to bottom.
ulDstAddr += PELS_TO_BYTES(x1) + (y1 * lDelta); cy = dy - 1; }
cx = PELS_TO_BYTES(1) - 1;
CP_IO_WAIT_FOR_BLT_COMPLETE(ppdev, pjPorts); CP_IO_XCNT(ppdev, pjPorts, cx); CP_IO_YCNT(ppdev, pjPorts, cy); CP_IO_DST_Y_OFFSET(ppdev, pjPorts, lDelta); CP_IO_DST_ADDR_ABS(ppdev, pjPorts, ulDstAddr); CP_IO_START_BLT(ppdev, pjPorts);
return(TRUE); }
// Diagonal lines.
else if ((dx == dy) || (dx == -dy)) { if (dy < 0) { if (dx < 0) { // Diagonal line from bottom-right to upper-left.
ulDstAddr += PELS_TO_BYTES(x2 + 1); } else { // Diagonal line from bottom-left to upper-right.
ulDstAddr += PELS_TO_BYTES(x2 - 1); } ulDstAddr += (y2 + 1) * lDelta; cy = -dy - 1; } else { // Diagonal line from top to bottom, either from left to right or
// right to left.
ulDstAddr += PELS_TO_BYTES(x1) + (y1 * lDelta); cy = dy - 1; }
if (dx == dy) { // Diagonal line from top-left to bottom-right or vice versa.
lDelta += PELS_TO_BYTES(1); } else { // Diagonal line from top-right to bottom-left or vice versa.
lDelta -= PELS_TO_BYTES(1); }
cx = PELS_TO_BYTES(1) - 1;
CP_IO_WAIT_FOR_BLT_COMPLETE(ppdev, pjPorts); CP_IO_XCNT(ppdev, pjPorts, cx); CP_IO_YCNT(ppdev, pjPorts, cy); CP_IO_DST_Y_OFFSET(ppdev, pjPorts, lDelta); CP_IO_DST_ADDR_ABS(ppdev, pjPorts, ulDstAddr); CP_IO_START_BLT(ppdev, pjPorts);
return(TRUE); }
// All other lines.
if (dx < 0) { dx = -dx; } if (dy < 0) { dy = -dy; } ulDstAddr += PELS_TO_BYTES(x1) + (y1 * lDelta);
// Horizontal major.
if (dx > dy) { LONG run = dy;
cy = (y1 > y2) ? -lDelta : lDelta;
CP_IO_WAIT_FOR_BLT_COMPLETE(ppdev, pjPorts);
//
// We would like to set the YCNT register once
// here (outside the loops below). However, on
// the CL5428, this register does not hold its value
// after one iteration through the loop. So, I'll
// have to set it inside the loop.
//
if (x1 < x2) { while (x1 < x2) { cx = 1 + (dx - run) / dy; if ((x1 + cx) < x2) { run += cx * dy - dx; } else { cx = x2 - x1; } x1 += cx; cx = PELS_TO_BYTES(cx);
CP_IO_WAIT_FOR_BLT_COMPLETE(ppdev, pjPorts); CP_IO_YCNT(ppdev, pjPorts, 0); CP_IO_XCNT(ppdev, pjPorts, cx - 1); CP_IO_DST_ADDR_ABS(ppdev, pjPorts, ulDstAddr); CP_IO_START_BLT(ppdev, pjPorts);
ulDstAddr += cx + cy; } } else { cy -= PELS_TO_BYTES(1);
while (x1 > x2) { cx = 1 + (dx - run) / dy; if ((x1 - cx) > x2) { run += cx * dy - dx; } else { cx = x1 - x2; } ulDstAddr -= PELS_TO_BYTES(cx - 1); x1 -= cx; cx = PELS_TO_BYTES(cx);
CP_IO_WAIT_FOR_BLT_COMPLETE(ppdev, pjPorts); CP_IO_YCNT(ppdev, pjPorts, 0); CP_IO_XCNT(ppdev, pjPorts, cx - 1); CP_IO_DST_ADDR_ABS(ppdev, pjPorts, ulDstAddr); CP_IO_START_BLT(ppdev, pjPorts);
ulDstAddr += cy; } } }
// Vertical major.
else { LONG run = dx;
cx = (x1 > x2) ? PELS_TO_BYTES(-1) : PELS_TO_BYTES(1);
CP_IO_WAIT_FOR_BLT_COMPLETE(ppdev, pjPorts); CP_IO_XCNT(ppdev, pjPorts, PELS_TO_BYTES(1) - 1); CP_IO_DST_Y_OFFSET(ppdev, pjPorts, lDelta);
if (y1 < y2) { while (y1 < y2) { cy = 1 + (dy - run) / dx; if ((y1 + cy) < y2) { run += cy * dx - dy; } else { cy = y2 - y1; } y1 += cy;
CP_IO_WAIT_FOR_BLT_COMPLETE(ppdev, pjPorts); CP_IO_YCNT(ppdev, pjPorts, cy - 1); CP_IO_DST_ADDR_ABS(ppdev, pjPorts, ulDstAddr); CP_IO_START_BLT(ppdev, pjPorts);
ulDstAddr += cx + cy * lDelta; } } else { cx -= lDelta;
while (y1 > y2) { cy = 1 + (dy - run) / dx; if ((y1 - cy) > y2) { run += cy * dx - dy; } else { cy = y1 - y2; } ulDstAddr -= (cy - 1) * lDelta; y1 -= cy;
CP_IO_WAIT_FOR_BLT_COMPLETE(ppdev, pjPorts); CP_IO_YCNT(ppdev, pjPorts, cy - 1); CP_IO_DST_ADDR_ABS(ppdev, pjPorts, ulDstAddr); CP_IO_START_BLT(ppdev, pjPorts);
ulDstAddr += cx; } } }
return(TRUE); }
bMmLineTo( PDEV* ppdev, LONG x1, LONG y1, LONG x2, LONG y2, ULONG ulSolidColor, MIX mix, ULONG ulDstAddr) { BYTE* pjBase = ppdev->pjBase; LONG lDelta = ppdev->lDelta; LONG dx, dy; LONG cx, cy;
if (ulSolidColor != (ULONG) -1) { if (ppdev->cBpp == 1) { ulSolidColor |= ulSolidColor << 8; ulSolidColor |= ulSolidColor << 16; } else if (ppdev->cBpp == 2) { ulSolidColor |= ulSolidColor << 16; }
CP_MM_WAIT_FOR_BLT_COMPLETE(ppdev, pjBase); CP_MM_ROP(ppdev, pjBase, gajHwMixFromMix[mix & 0x0F]); CP_MM_SRC_ADDR(ppdev, pjBase, ppdev->ulSolidColorOffset); CP_MM_BLT_MODE(ppdev, pjBase, ENABLE_COLOR_EXPAND | ENABLE_8x8_PATTERN_COPY | ppdev->jModeColor); CP_MM_FG_COLOR(ppdev, pjBase, ulSolidColor);
// if (ppdev->flCaps & CAPS_IS_5436)
if (ppdev->flCaps & CAPS_AUTOSTART) { CP_MM_BLT_EXT_MODE(ppdev, pjBase, ENABLE_SOLID_FILL); } }
// Calculate deltas.
dx = x2 - x1; dy = y2 - y1;
// Horizontal lines.
if (dy == 0) { if (dx < 0) { // From right to left.
ulDstAddr += PELS_TO_BYTES(x2 + 1) + (y2 * lDelta); cx = PELS_TO_BYTES(-dx) - 1; } else if (dx > 0) { // From left to right.
ulDstAddr += PELS_TO_BYTES(x1) + (y1 * lDelta); cx = PELS_TO_BYTES(dx) - 1; } else { // Nothing to do here!
return(TRUE); }
CP_MM_WAIT_FOR_BLT_COMPLETE(ppdev, pjBase); CP_MM_XCNT(ppdev, pjBase, cx); CP_MM_YCNT(ppdev, pjBase, 0); CP_MM_DST_ADDR_ABS(ppdev, pjBase, ulDstAddr); CP_MM_START_BLT(ppdev, pjBase);
return(TRUE); }
// Vertical lines.
else if (dx == 0) { if (dy < 0) { // From bottom to top.
ulDstAddr += PELS_TO_BYTES(x2) + ((y2 + 1) * lDelta); cy = -dy - 1; } else { // From top to bottom.
ulDstAddr += PELS_TO_BYTES(x1) + (y1 * lDelta); cy = dy - 1; }
cx = PELS_TO_BYTES(1) - 1;
CP_MM_WAIT_FOR_BLT_COMPLETE(ppdev, pjBase); CP_MM_XCNT(ppdev, pjBase, cx); CP_MM_YCNT(ppdev, pjBase, cy); CP_MM_DST_Y_OFFSET(ppdev, pjBase, lDelta); CP_MM_DST_ADDR_ABS(ppdev, pjBase, ulDstAddr); CP_MM_START_BLT(ppdev, pjBase);
return(TRUE); }
// Diagonal lines.
else if ((dx == dy) || (dx == -dy)) { if (dy < 0) { if (dx < 0) { // Diagonal line from bottom-right to upper-left.
ulDstAddr += PELS_TO_BYTES(x2 + 1); } else { // Diagonal line from bottom-left to upper-right.
ulDstAddr += PELS_TO_BYTES(x2 - 1); } ulDstAddr += (y2 + 1) * lDelta; cy = -dy - 1; } else { // Diagonal line from top to bottom, either from left to right or
// right to left.
ulDstAddr += PELS_TO_BYTES(x1) + (y1 * lDelta); cy = dy - 1; }
if (dx == dy) { // Diagonal line from top-left to bottom-right or vice versa.
lDelta += PELS_TO_BYTES(1); } else { // Diagonal line from top-right to bottom-left or vice versa.
lDelta -= PELS_TO_BYTES(1); }
cx = PELS_TO_BYTES(1) - 1;
CP_MM_WAIT_FOR_BLT_COMPLETE(ppdev, pjBase); CP_MM_XCNT(ppdev, pjBase, cx); CP_MM_YCNT(ppdev, pjBase, cy); CP_MM_DST_Y_OFFSET(ppdev, pjBase, lDelta); CP_MM_DST_ADDR_ABS(ppdev, pjBase, ulDstAddr); CP_MM_START_BLT(ppdev, pjBase);
return(TRUE); }
// All other lines.
if (dx < 0) { dx = -dx; } if (dy < 0) { dy = -dy; } ulDstAddr += PELS_TO_BYTES(x1) + (y1 * lDelta);
// Horizontal major.
if (dx > dy) { LONG run = dy;
cy = (y1 > y2) ? -lDelta : lDelta;
CP_MM_WAIT_FOR_BLT_COMPLETE(ppdev, pjBase); CP_MM_YCNT(ppdev, pjBase, 0);
if (x1 < x2) { while (x1 < x2) { cx = 1 + (dx - run) / dy; if ((x1 + cx) < x2) { run += cx * dy - dx; } else { cx = x2 - x1; } x1 += cx; cx = PELS_TO_BYTES(cx);
CP_MM_WAIT_FOR_BLT_COMPLETE(ppdev, pjBase); CP_MM_XCNT(ppdev, pjBase, cx - 1); CP_MM_DST_ADDR_ABS(ppdev, pjBase, ulDstAddr); CP_MM_START_BLT(ppdev, pjBase);
ulDstAddr += cx + cy; } } else { cy -= PELS_TO_BYTES(1);
while (x1 > x2) { cx = 1 + (dx - run) / dy; if ((x1 - cx) > x2) { run += cx * dy - dx; } else { cx = x1 - x2; } ulDstAddr -= PELS_TO_BYTES(cx - 1); x1 -= cx; cx = PELS_TO_BYTES(cx);
CP_MM_WAIT_FOR_BLT_COMPLETE(ppdev, pjBase); CP_MM_XCNT(ppdev, pjBase, cx - 1); CP_MM_DST_ADDR_ABS(ppdev, pjBase, ulDstAddr); CP_MM_START_BLT(ppdev, pjBase);
ulDstAddr += cy; } } }
// Vertical major.
else { LONG run = dx;
cx = (x1 > x2) ? PELS_TO_BYTES(-1) : PELS_TO_BYTES(1);
CP_MM_WAIT_FOR_BLT_COMPLETE(ppdev, pjBase); CP_MM_XCNT(ppdev, pjBase, PELS_TO_BYTES(1) - 1); CP_MM_DST_Y_OFFSET(ppdev, pjBase, lDelta);
if (y1 < y2) { while (y1 < y2) { cy = 1 + (dy - run) / dx; if ((y1 + cy) < y2) { run += cy * dx - dy; } else { cy = y2 - y1; } y1 += cy;
CP_MM_WAIT_FOR_BLT_COMPLETE(ppdev, pjBase); CP_MM_YCNT(ppdev, pjBase, cy - 1); CP_MM_DST_ADDR_ABS(ppdev, pjBase, ulDstAddr); CP_MM_START_BLT(ppdev, pjBase);
ulDstAddr += cx + cy * lDelta; } } else { cx -= lDelta;
while (y1 > y2) { cy = 1 + (dy - run) / dx; if ((y1 - cy) > y2) { run += cy * dx - dy; } else { cy = y1 - y2; } ulDstAddr -= (cy - 1) * lDelta; y1 -= cy;
CP_MM_WAIT_FOR_BLT_COMPLETE(ppdev, pjBase); CP_MM_YCNT(ppdev, pjBase, cy - 1); CP_MM_DST_ADDR_ABS(ppdev, pjBase, ulDstAddr); CP_MM_START_BLT(ppdev, pjBase);
ulDstAddr += cx; } } }
return(TRUE); }
BOOL bClipLine(LONG x1, LONG y1, LONG x2, LONG y2, RECTL* prcl) { ULONG ulCode1, ulCode2; RECTL rclClip1, rclClip2; LONG dx, dy;
// Set clipping rectangles.
rclClip1.left = prcl->left; rclClip1.top = prcl->top; rclClip1.right = prcl->right - 1; rclClip1.bottom = prcl->bottom - 1;
rclClip2.left = prcl->left - 1; rclClip2.top = prcl->top - 1; rclClip2.right = prcl->right; rclClip2.bottom = prcl->bottom;
// Set line deltas.
dx = x2 - x1; dy = y2 - y1;
// Set line flags.
ulCode1 = 0; if (x1 < rclClip1.left) ulCode1 |= LEFT; if (y1 < rclClip1.top) ulCode1 |= TOP; if (x1 > rclClip1.right) ulCode1 |= RIGHT; if (y1 > rclClip1.bottom) ulCode1 |= BOTTOM;
ulCode2 = 0; if (x2 < rclClip2.left) ulCode2 |= LEFT; if (y2 < rclClip2.top) ulCode2 |= TOP; if (x2 > rclClip2.right) ulCode2 |= RIGHT; if (y2 > rclClip2.bottom) ulCode2 |= BOTTOM;
if ((ulCode1 & ulCode2) != 0) { // The line is completly clipped.
return(FALSE); }
// Vertical lines.
if (dx == 0) { if (dy == 0) { return(FALSE); }
if (ulCode1 & TOP) { y1 = rclClip1.top; } else if (ulCode1 & BOTTOM) { y1 = rclClip1.bottom; }
if (ulCode2 & TOP) { y2 = rclClip2.top; } else if (ulCode2 & BOTTOM) { y2 = rclClip2.bottom; }
goto ReturnTrue; }
// Horizontal lines.
if (dy == 0) { if (ulCode1 & LEFT) { x1 = rclClip1.left; } else if (ulCode1 & RIGHT) { x1 = rclClip1.right; }
if (ulCode2 & LEFT) { x2 = rclClip2.left; } else if (ulCode2 & RIGHT) { x2 = rclClip2.right; }
goto ReturnTrue; }
// Clip start point.
if (x1 < rclClip1.left) { y1 += dy * (rclClip1.left - x1) / dx; x1 = rclClip1.left; } else if (x1 > rclClip1.right) { y1 += dy * (rclClip1.right - x1) / dx; x1 = rclClip1.right; } if (y1 < rclClip1.top) { x1 += dx * (rclClip1.top - y1) / dy; y1 = rclClip1.top; } else if (y1 > rclClip1.bottom) { x1 += dx * (rclClip1.bottom - y1) / dy; y1 = rclClip1.bottom; } if ((x1 < rclClip1.left) || (y1 < rclClip1.top) || (x1 > rclClip1.right) || (y1 > rclClip1.bottom)) { // Start point fully clipped.
return(FALSE); }
// Clip end point.
if (x2 < rclClip2.left) { y2 += dy * (rclClip2.left - x2) / dx; x2 = rclClip2.left; } else if (x2 > rclClip2.right) { y2 += dy * (rclClip2.right - x2) / dx; x2 = rclClip2.right; } if (y2 < rclClip2.top) { x2 += dx * (rclClip2.top - y2) / dy; y2 = rclClip2.top; } else if (y2 > rclClip2.bottom) { x2 += dx * (rclClip2.bottom - y2) / dy; y2 = rclClip2.bottom; } if ((x2 < rclClip2.left) || (y2 < rclClip2.top) || (x2 > rclClip2.right) || (y2 > rclClip2.bottom)) { // End point fully clipped.
return(FALSE); }
ReturnTrue: prcl->left = x1; prcl->top = y1; prcl->right = x2; prcl->bottom = y2; return(TRUE); }
/******************************************************************************\
* * Function: DrvLineTo * * This function draws a line between any two points. This function only draws * lines in solod color and that are just 1 pixel wide. The end-point is not * drawn. * * Parameters: pso Pointer to surface. * pco Pointer to CLIPOBJ. * pbo Pointer to BRUSHOBJ. * x1 Starting x-coordinate. * y1 Starting y-coordinate. * x2 Ending x-coordinate. * y2 Ending y-coordinate. * prclBounds Pointer to an unclipped bounding rectangle. * mix Mix to perform on the destination. * * Returns: TRUE if the line has been drawn, FALSE oftherwise. * \******************************************************************************/ BOOL DrvLineTo( SURFOBJ* pso, CLIPOBJ* pco, BRUSHOBJ* pbo, LONG x1, LONG y1, LONG x2, LONG y2, RECTL* prclBounds, MIX mix) { PDEV* ppdev = (PPDEV)pso->dhpdev; DSURF* pdsurf = (DSURF *)pso->dhsurf; OH* poh; BOOL bMore;
// If the device bitmap is a DIB, let GDI handle it.
if (pdsurf->dt == DT_DIB) { return(EngLineTo(pdsurf->pso, pco, pbo, x1, y1, x2, y2, prclBounds, mix)); }
// Get the off-screen node.
poh = pdsurf->poh;
if ((pco == NULL) || (pco->iDComplexity == DC_TRIVIAL)) { // No clipping.
return(ppdev->pfnLineTo(ppdev, x1, y1, x2, y2, pbo->iSolidColor, mix, poh->xy)); }
else if (pco->iDComplexity == DC_RECT) { // Clipped rectangle.
RECTL rcl;
rcl = pco->rclBounds; if (bClipLine(x1, y1, x2, y2, &rcl)) { return(ppdev->pfnLineTo(ppdev, rcl.left, rcl.top, rcl.right, rcl.bottom, pbo->iSolidColor, mix, poh->xy)); } return(TRUE); }
// Complex clipping.
CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_ANY, 0);
do { CLIPENUM ce; RECTL* prcl;
bMore = CLIPOBJ_bEnum(pco, sizeof(ce), &ce.c);
prcl = ce.arcl; while (ce.c--) { if (bClipLine(x1, y1, x2, y2, prcl)) { if (!ppdev->pfnLineTo(ppdev, prcl->left, prcl->top, prcl->right, prcl->bottom, pbo->iSolidColor, mix, poh->xy)) { return(FALSE); } } prcl++; } } while (bMore);
return(TRUE); }
#endif // LINETO
|