2019-12-10 12:42:58 -07:00
|
|
|
#include <string.h>
|
2019-12-10 12:55:32 -07:00
|
|
|
#include <stdlib.h>
|
2019-12-10 13:40:23 -07:00
|
|
|
#include "log.h"
|
2019-12-09 17:02:04 -07:00
|
|
|
#include "gfxtype.h"
|
2019-12-10 12:42:58 -07:00
|
|
|
#include "gfxobj.h"
|
2019-12-09 17:02:04 -07:00
|
|
|
#include "devctxt.h"
|
|
|
|
|
2019-12-10 14:30:45 -07:00
|
|
|
inline static BYTE line_clip_outcode(INT32 x, INT32 y, INT32 xmin, INT32 ymin, INT32 xmax, INT32 ymax)
|
2019-12-10 12:42:58 -07:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2019-12-10 14:51:53 -07:00
|
|
|
#define CPX 4 /* clipping precision in bits */
|
|
|
|
|
|
|
|
#define ONE (1 << CPX) /* constant for mathematics */
|
2019-12-10 14:30:45 -07:00
|
|
|
|
|
|
|
/* 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)
|
2019-12-10 12:42:58 -07:00
|
|
|
{
|
2019-12-10 14:06:23 -07:00
|
|
|
BYTE outcode1, outcode2;
|
2019-12-10 14:30:45 -07:00
|
|
|
INT32 tmp;
|
2019-12-10 14:45:02 -07:00
|
|
|
int nloop = 0;
|
2019-12-10 12:42:58 -07:00
|
|
|
|
2019-12-10 14:30:45 -07:00
|
|
|
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);
|
2019-12-10 13:40:23 -07:00
|
|
|
|
2019-12-10 12:42:58 -07:00
|
|
|
/* Cohen-Sutherland line-clipping algorithm (see Foley & Van Dam, pp. 145-149) */
|
|
|
|
for (;;)
|
|
|
|
{
|
2019-12-10 14:45:02 -07:00
|
|
|
if (++nloop == 20)
|
|
|
|
{
|
|
|
|
Log(LDEBUG, "POSSIBLE INFINITE LOOP DETECTED - REJECTING");
|
|
|
|
return FALSE;
|
|
|
|
}
|
2019-12-10 12:42:58 -07:00
|
|
|
outcode1 = line_clip_outcode(x1, y1, xmin, ymin, xmax, ymax);
|
|
|
|
outcode2 = line_clip_outcode(x2, y2, xmin, ymin, xmax, ymax);
|
|
|
|
if ((outcode1 & outcode2) != 0)
|
2019-12-10 13:40:23 -07:00
|
|
|
{
|
2019-12-10 13:43:30 -07:00
|
|
|
Log(LDEBUG,"*REJECT*");
|
2019-12-10 12:42:58 -07:00
|
|
|
return FALSE; /* trivial rejection */
|
2019-12-10 13:40:23 -07:00
|
|
|
}
|
2019-12-10 12:42:58 -07:00
|
|
|
else if ((outcode1 == 0) && (outcode2 == 0))
|
2019-12-10 13:40:23 -07:00
|
|
|
{
|
2019-12-10 13:43:30 -07:00
|
|
|
Log(LDEBUG,"*ACCEPT*");
|
2019-12-10 12:42:58 -07:00
|
|
|
break; /* trivial acceptance */
|
2019-12-10 13:40:23 -07:00
|
|
|
}
|
2019-12-10 12:42:58 -07:00
|
|
|
if (outcode1 == 0)
|
|
|
|
{
|
2019-12-10 13:42:40 -07:00
|
|
|
Log(LDEBUG, "exchange points");
|
2019-12-10 12:42:58 -07:00
|
|
|
tmp = x1;
|
|
|
|
x1 = x2;
|
|
|
|
x2 = tmp;
|
|
|
|
tmp = y1;
|
|
|
|
y1 = y2;
|
|
|
|
y2 = tmp;
|
2019-12-10 14:06:23 -07:00
|
|
|
outcode1 = outcode2; /* we don't reference outcode2 in the rest of the loop */
|
2019-12-10 12:42:58 -07:00
|
|
|
}
|
|
|
|
if (outcode1 & 0x8)
|
|
|
|
{
|
2019-12-10 14:30:45 -07:00
|
|
|
tmp = M(x2 - x1, D(ymin - y1, y2 - y1));
|
2019-12-10 13:59:27 -07:00
|
|
|
x1 += tmp;
|
2019-12-10 12:42:58 -07:00
|
|
|
y1 = ymin;
|
2019-12-10 14:30:45 -07:00
|
|
|
Log(LDEBUG, "clipped against top to point (%d, %d), dx=%d/%d", x1 >> CPX, y1 >> CPX, tmp >> CPX, tmp);
|
2019-12-10 12:42:58 -07:00
|
|
|
}
|
|
|
|
else if (outcode1 & 0x4)
|
|
|
|
{
|
2019-12-10 14:51:53 -07:00
|
|
|
tmp = M(x2 - x1, D(ymax - ONE - y1, y2 - y1));
|
2019-12-10 13:59:27 -07:00
|
|
|
x1 += tmp;
|
2019-12-10 14:51:53 -07:00
|
|
|
y1 = ymax - ONE;
|
2019-12-10 14:30:45 -07:00
|
|
|
Log(LDEBUG, "clipped against bottom to point (%d, %d), dx=%d/%d", x1 >> CPX, y1 >> CPX, tmp >> CPX, tmp);
|
2019-12-10 12:42:58 -07:00
|
|
|
}
|
|
|
|
else if (outcode1 & 0x2)
|
|
|
|
{
|
2019-12-10 14:51:53 -07:00
|
|
|
tmp = M(y2 - y1, D(xmax - ONE - x1, x2 - x1));
|
2019-12-10 14:36:38 -07:00
|
|
|
y1 += tmp;
|
2019-12-10 14:51:53 -07:00
|
|
|
x1 = xmax - ONE;
|
2019-12-10 14:30:45 -07:00
|
|
|
Log(LDEBUG, "clipped against right to point (%d, %d), dy=%d/%d", x1 >> CPX, y1 >> CPX, tmp >> CPX, tmp);
|
2019-12-10 12:42:58 -07:00
|
|
|
}
|
|
|
|
else if (outcode1 & 0x1)
|
|
|
|
{
|
2019-12-10 14:30:45 -07:00
|
|
|
tmp = M(y2 - y1, D(xmin - x1, x2 - x1));
|
2019-12-10 14:36:38 -07:00
|
|
|
y1 += tmp;
|
2019-12-10 12:42:58 -07:00
|
|
|
x1 = xmin;
|
2019-12-10 14:30:45 -07:00
|
|
|
Log(LDEBUG, "clipped against left to point (%d, %d), dy=%d/%d", x1 >> CPX, y1 >> CPX, tmp >> CPX, tmp);
|
2019-12-10 12:42:58 -07:00
|
|
|
}
|
|
|
|
}
|
2019-12-10 14:30:45 -07:00
|
|
|
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;
|
2019-12-10 12:42:58 -07:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static BOOL internal_line(PDCTXT pdctxt, INT32 x1, INT32 y1, INT32 x2, INT32 y2)
|
|
|
|
{
|
|
|
|
INT32 buffer[4];
|
2019-12-10 14:30:45 -07:00
|
|
|
if (line_clip(buffer, x1 << CPX, y1 << CPX, x2 << CPX, y2 << CPX, pdctxt->cliprect.left << CPX, pdctxt->cliprect.top << CPX,
|
2019-12-10 14:48:02 -07:00
|
|
|
pdctxt->cliprect.right << CPX, pdctxt->cliprect.bottom << CPX))
|
2019-12-10 14:30:45 -07:00
|
|
|
return (*pdctxt->funcs->line)(pdctxt->privdata, buffer[0] >> CPX, buffer[1] >> CPX, buffer[2] >> CPX, buffer[3] >> CPX, pdctxt->color, pdctxt->rop2);
|
2019-12-10 12:42:58 -07:00
|
|
|
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 */
|
|
|
|
}
|
|
|
|
|
2019-12-09 17:02:04 -07:00
|
|
|
COLORREF DC_SetPixel(PDCTXT pdctxt, INT32 x, INT32 y, COLORREF color)
|
|
|
|
{
|
|
|
|
if (!G_coords_in_rect(&(pdctxt->cliprect), x, y))
|
|
|
|
return (COLORREF)(-1);
|
2019-12-10 12:55:32 -07:00
|
|
|
return (*(pdctxt->funcs->set_pixel))(pdctxt->privdata, x, y, color, pdctxt->rop2);
|
2019-12-09 17:02:04 -07:00
|
|
|
}
|
2019-12-10 12:42:58 -07:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|