#include #include #include "log.h" #include "gfxtype.h" #include "gfxobj.h" #include "devctxt.h" inline static BYTE line_clip_outcode(INT32 x, INT32 y, INT32 xmin, INT32 ymin, INT32 xmax, INT32 ymax) { BYTE rc = 0; if (y < ymin) rc |= 0x8; else if (y >= ymax) rc |= 0x4; if (x < xmin) rc |= 0x1; else if (x >= xmax) rc |= 0x2; return rc; } #define CPX 8 /* clipping precision in bits */ /* these macros keep the number of bits straight when doing fixed-point multiply & divide */ #define M(a, b) ((((a) * (b))) >> CPX) #define D(a, b) (((a) << CPX) / (b)) static BOOL line_clip(PINT32 output, INT32 x1, INT32 y1, INT32 x2, INT32 y2, INT32 xmin, INT32 ymin, INT32 xmax, INT32 ymax) { BYTE outcode1, outcode2; INT32 tmp; int nloop = 0; Log(LDEBUG, "clipping line from (%d, %d) to (%d, %d) against bounding box (%d, %d, %d, %d)", x1 >> CPX, y1 >> CPX, x2 >> CPX, y2 >> CPX, xmin >> CPX, ymin >> CPX, xmax >> CPX, ymax >> CPX); /* Cohen-Sutherland line-clipping algorithm (see Foley & Van Dam, pp. 145-149) */ for (;;) { if (++nloop == 20) { Log(LDEBUG, "POSSIBLE INFINITE LOOP DETECTED - REJECTING"); return FALSE; } outcode1 = line_clip_outcode(x1, y1, xmin, ymin, xmax, ymax); outcode2 = line_clip_outcode(x2, y2, xmin, ymin, xmax, ymax); if ((outcode1 & outcode2) != 0) { Log(LDEBUG,"*REJECT*"); return FALSE; /* trivial rejection */ } else if ((outcode1 == 0) && (outcode2 == 0)) { Log(LDEBUG,"*ACCEPT*"); break; /* trivial acceptance */ } if (outcode1 == 0) { Log(LDEBUG, "exchange points"); tmp = x1; x1 = x2; x2 = tmp; tmp = y1; y1 = y2; y2 = tmp; outcode1 = outcode2; /* we don't reference outcode2 in the rest of the loop */ } if (outcode1 & 0x8) { tmp = M(x2 - x1, D(ymin - y1, y2 - y1)); x1 += tmp; y1 = ymin; Log(LDEBUG, "clipped against top to point (%d, %d), dx=%d/%d", x1 >> CPX, y1 >> CPX, tmp >> CPX, tmp); } else if (outcode1 & 0x4) { tmp = M(x2 - x1, D(ymax - y1, y2 - y1)); x1 += tmp; y1 = ymax; Log(LDEBUG, "clipped against bottom to point (%d, %d), dx=%d/%d", x1 >> CPX, y1 >> CPX, tmp >> CPX, tmp); } else if (outcode1 & 0x2) { tmp = M(y2 - y1, D(xmax - x1, x2 - x1)); y1 += tmp; x1 = xmax; Log(LDEBUG, "clipped against right to point (%d, %d), dy=%d/%d", x1 >> CPX, y1 >> CPX, tmp >> CPX, tmp); } else if (outcode1 & 0x1) { tmp = M(y2 - y1, D(xmin - x1, x2 - x1)); y1 += tmp; x1 = xmin; Log(LDEBUG, "clipped against left to point (%d, %d), dy=%d/%d", x1 >> CPX, y1 >> CPX, tmp >> CPX, tmp); } } Log(LDEBUG, "final line is from (%d, %d) to (%d, %d)", x1 >> CPX, y1 >> CPX, x2 >> CPX, y2 >> CPX); output[0] = x1; output[1] = y1; output[2] = x2; output[3] = y2; return TRUE; } static BOOL internal_line(PDCTXT pdctxt, INT32 x1, INT32 y1, INT32 x2, INT32 y2) { INT32 buffer[4]; if (line_clip(buffer, x1 << CPX, y1 << CPX, x2 << CPX, y2 << CPX, pdctxt->cliprect.left << CPX, pdctxt->cliprect.top << CPX, pdctxt->cliprect.right << CPX, pdctxt->cliprect.bottom << CPX)) return (*pdctxt->funcs->line)(pdctxt->privdata, buffer[0] >> CPX, buffer[1] >> CPX, buffer[2] >> CPX, buffer[3] >> CPX, pdctxt->color, pdctxt->rop2); return TRUE; } PDCTXT _DC_Allocate(PDCFUNTABLE funcs, PVOID privdata) { PDCTXT rc = (PDCTXT)malloc(sizeof(DCTXT)); if (!rc) return NULL; memset(rc, 0, sizeof(DCTXT)); _Go_init(&(rc->hdr), DCTXT_SIG_WORD, sizeof(DCTXT)); rc->funcs = funcs; rc->privdata = privdata; rc->rop2 = R2_COPYPEN; return rc; } void _DC_FinalizeCommon(PDCTXT pdctxt) { /* nothing here yet */ } COLORREF DC_SetPixel(PDCTXT pdctxt, INT32 x, INT32 y, COLORREF color) { if (!G_coords_in_rect(&(pdctxt->cliprect), x, y)) return (COLORREF)(-1); return (*(pdctxt->funcs->set_pixel))(pdctxt->privdata, x, y, color, pdctxt->rop2); } BOOL DC_LineTo(PDCTXT pdctxt, INT32 x, INT32 y) { BOOL rc = internal_line(pdctxt, pdctxt->pos.x, pdctxt->pos.y, x, y); if (rc) { pdctxt->pos.x = x; pdctxt->pos.y = y; } return rc; } BOOL DC_MoveTo(PDCTXT pdctxt, INT32 x, INT32 y, PPOINT oldpt) { if (oldpt) memcpy(oldpt, &(pdctxt->pos), sizeof(POINT)); pdctxt->pos.x = x; pdctxt->pos.y = y; return TRUE; } BOOL DC_Rectangle(PDCTXT pdctxt, INT32 left, INT32 top, INT32 right, INT32 bottom) { internal_line(pdctxt, left, top, right - 1, top); internal_line(pdctxt, left, top + 1, left, bottom - 2); internal_line(pdctxt, right - 1, top + 1, right - 1, bottom - 2); internal_line(pdctxt, left, bottom - 1, right - 1, bottom - 1); return TRUE; } UINT32 DC_GetROP2(PDCTXT pdctxt) { return pdctxt->rop2; } UINT32 DC_SetROP2(PDCTXT pdctxt, UINT32 rop) { UINT32 rc = pdctxt->rop2; pdctxt->rop2 = rop; return rc; } COLORREF DC_GetTextColor(PDCTXT pdctxt) { return pdctxt->color; } COLORREF DC_SetTextColor(PDCTXT pdctxt, COLORREF cr) { COLORREF rc = pdctxt->color; pdctxt->color = cr; return rc; } BOOL DC_GetClipRect(PDCTXT pdctxt, PRECT prect) { memcpy(prect, &(pdctxt->cliprect), sizeof(RECT)); return TRUE; } BOOL DC_SetClipRect(PDCTXT pdctxt, PRECT prect) { memcpy(&(pdctxt->cliprect), prect, sizeof(RECT)); return TRUE; }