181 lines
5.3 KiB
C++
181 lines
5.3 KiB
C++
|
|
#define CLIP_TOP 1
|
|
#define CLIP_BOTTOM 2
|
|
#define CLIP_RIGHT 4
|
|
#define CLIP_LEFT 8
|
|
|
|
|
|
static int _L1OutCode( clip_t *clip, int x, int y )
|
|
/*=================================
|
|
|
|
Verify that a point is inside or outside the active viewport. */
|
|
{
|
|
int flag;
|
|
|
|
flag = 0;
|
|
if( x < clip->xmin ) {
|
|
flag |= CLIP_LEFT;
|
|
} else if( x > clip->xmax ) {
|
|
flag |= CLIP_RIGHT;
|
|
}
|
|
if( y < clip->ymin ) {
|
|
flag |= CLIP_TOP;
|
|
} else if( y > clip->ymax ) {
|
|
flag |= CLIP_BOTTOM;
|
|
}
|
|
return( flag );
|
|
}
|
|
|
|
|
|
static void line_inter( int * x1, int* y1, int x2, int y2, int x )
|
|
/*===========================================================================
|
|
|
|
Find the intersection of a line with a boundary of the viewport.
|
|
(x1, y1) is outside and ( x2, y2 ) is inside the viewport.
|
|
NOTE : the signs of denom and ( x - *x1 ) cancel out during division
|
|
so make both of them positive before rounding. */
|
|
{
|
|
int numer;
|
|
int denom;
|
|
|
|
denom = abs( x2 - *x1 );
|
|
numer = 2L * (long)( y2 - *y1 ) * abs( x - *x1 );
|
|
if( numer > 0 ) {
|
|
numer += denom; /* round to closest pixel */
|
|
} else {
|
|
numer -= denom;
|
|
}
|
|
*y1 += numer / ( denom << 1 );
|
|
*x1 = x;
|
|
}
|
|
|
|
|
|
int LineClip( clip_t *clip, int *x1, int *y1, int *x2, int *y2 )
|
|
/*=============================================================
|
|
|
|
Clips the line with end points (x1,y1) and (x2,y2) to the active
|
|
viewport using the Cohen-Sutherland clipping algorithm. Return the
|
|
clipped coordinates and a decision drawing flag. */
|
|
{
|
|
int flag1;
|
|
int flag2;
|
|
|
|
flag1 = _L1OutCode( clip, *x1, *y1 );
|
|
flag2 = _L1OutCode( clip, *x2, *y2 );
|
|
for( ;; ) {
|
|
if( flag1 & flag2 ) break; /* trivially outside */
|
|
if( flag1 == flag2 ) break; /* completely inside */
|
|
if( flag1 == 0 ) { /* first point inside */
|
|
if( flag2 & CLIP_TOP ) {
|
|
line_inter( y2, x2, *y1, *x1, clip->ymin );
|
|
} else if( flag2 & CLIP_BOTTOM ) {
|
|
line_inter( y2, x2, *y1, *x1, clip->ymax );
|
|
} else if( flag2 & CLIP_RIGHT ) {
|
|
line_inter( x2, y2, *x1, *y1, clip->xmax );
|
|
} else if( flag2 & CLIP_LEFT ) {
|
|
line_inter( x2, y2, *x1, *y1, clip->xmin );
|
|
}
|
|
flag2 = _L1OutCode( clip, *x2, *y2 );
|
|
} else { /* second point inside */
|
|
if( flag1 & CLIP_TOP ) {
|
|
line_inter( y1, x1, *y2, *x2, clip->ymin );
|
|
} else if( flag1 & CLIP_BOTTOM ) {
|
|
line_inter( y1, x1, *y2, *x2, clip->ymax );
|
|
} else if( flag1 & CLIP_RIGHT ) {
|
|
line_inter( x1, y1, *x2, *y2, clip->xmax );
|
|
} else if( flag1 & CLIP_LEFT ) {
|
|
line_inter( x1, y1, *x2, *y2, clip->xmin );
|
|
}
|
|
flag1 = _L1OutCode( clip, *x1, *y1 );
|
|
}
|
|
}
|
|
return( flag1 & flag2 );
|
|
}
|
|
|
|
|
|
static void block_inter( clip_t *clip, int *x, int *y, int flag )
|
|
/*======================================================
|
|
|
|
Find the intersection of a block with a boundary of the viewport. */
|
|
{
|
|
if( flag & CLIP_TOP ) {
|
|
*y = clip->ymin;
|
|
} else if( flag & CLIP_BOTTOM ) {
|
|
*y = clip->ymax;
|
|
} else if( flag & CLIP_RIGHT ) {
|
|
*x = clip->xmax;
|
|
} else if( flag & CLIP_LEFT ) {
|
|
*x = clip->xmin;
|
|
}
|
|
}
|
|
|
|
|
|
int BlockClip(clip_t *clip, int *x1, int *y1, int *x2, int* y2 )
|
|
/*==============================================================
|
|
|
|
Clip a block with opposite corners (x1,y1) and (x2,y2) to the
|
|
active viewport based on the Cohen-Sutherland algorithm for line
|
|
clipping. Return the clipped coordinates and a decision drawing
|
|
flag ( 0 draw : 1 don't draw ). */
|
|
{
|
|
int flag1;
|
|
int flag2;
|
|
|
|
flag1 = _L1OutCode( clip, *x1, *y1 );
|
|
flag2 = _L1OutCode( clip, *x2, *y2 );
|
|
for( ;; ) {
|
|
if( flag1 & flag2 ) break; /* trivially outside */
|
|
if( flag1 == flag2 ) break; /* completely inside */
|
|
if( flag1 == 0 ) {
|
|
block_inter( clip, x2, y2, flag2 );
|
|
flag2 = _L1OutCode( clip, *x2, *y2 );
|
|
} else {
|
|
block_inter( clip, x1, y1, flag1 );
|
|
flag1 = _L1OutCode( clip, *x1, *y1 );
|
|
}
|
|
}
|
|
return( flag1 & flag2 );
|
|
}
|
|
|
|
|
|
int blit_clip(clip_t *dst_clip,int *dst_x,int *dst_y,
|
|
clip_t *src_clip,int *src_x, int *src_y,
|
|
int *w, int *h)
|
|
{
|
|
int sx0, sy0, sx1, sy1;
|
|
|
|
sx0 = *src_x;
|
|
sy0 = *src_y;
|
|
|
|
sx1 = sx0 + *w - 1;
|
|
sy1 = sy0 + *h - 1;
|
|
|
|
|
|
if( ! BlockClip( src_clip, &sx0, &sy0, &sx1, &sy1))
|
|
{
|
|
int dx0, dy0, dx1, dy1;
|
|
|
|
dx0 = *dst_x + sx0 - *src_x;
|
|
dy0 = *dst_y + sy0 - *src_y;
|
|
|
|
dx1 = dx0 + sx1 - sx0;
|
|
dy1 = dy0 + sy1 - sy0;
|
|
|
|
if( ! BlockClip( dst_clip, &dx0, &dy0, &dx1, &dy1))
|
|
{
|
|
*w = dx1 - dx0 + 1;
|
|
*h = dy1 - dy0 + 1;
|
|
|
|
*src_x += dx0 - *dst_x;
|
|
*src_y += dy0 - *dst_y;
|
|
|
|
*dst_x = dx0;
|
|
*dst_y = dy0;
|
|
|
|
return 0;
|
|
};
|
|
}
|
|
return 1;
|
|
};
|
|
|