您的位置:首页 > 其它

2013年8月28日星期三(8-2,裁剪Cohen_sutherland算法)

2013-08-28 12:37 423 查看
这节就是只保留裁剪区域内的像素,这个例子用直线表示,分为4种情况
1, 直线完全在裁剪区外,不用处理
2, 直线完全在裁剪区之内,也无需改动,直接光栅化
3, 直线的一个端点在裁剪区之外,必须进行裁剪
4, 直线的两个端点都在裁剪区之外,但部分在裁剪区之内。必须进行裁剪

Cohen-Sutherland算法中,把裁剪区分成很多部分,然后给每一段被裁剪的线段的两端分配一位代码,而后,只采用少量的if语句或一个case语句,就能判断具体情况

#define CLIP_CODE_C 0x0000 //裁剪区域
#define CLIP_CODE_N 0x0008 //裁剪区北(上方)
#define CLIP_CODE_S 0x0004 //南(下方)
#define CLIP_CODE_E 0x0002 //东(右)
#define CLIP_CODE_W 0x0001 //西(左)

#define CLIP_CODE_NE 0x000a //东北(右上)
#define CLIP_CODE_SE 0x0006 //东南(右下)
#define CLIP_CODE_NW 0x0009 //西北(左上)
#define CLIP_CODE_SW 0x0005 //西南(左下)

仔细研读了下代码,就是分区-》裁剪-》定两点
具体如下int Clip_Line(
int & x1, int & y1,
int *x2, int & y2 )
{
#define CLIP_CODE_C 0x0000
#define CLIP_CODE_N 0x0008
#define CLIP_CODE_S 0x0004
#define CLIP_CODE_E 0x0002
#define CLIP_CODE_W 0x0001

#define CLIP_CODE_NE 0x000a
#define CLIP_CODE_SE 0x0006
#define CLIP_CODE_NW 0x0009
#define CLIP_CODE_SW 0x0005

int xc1 = x1,
yc1 = y1,
xc2 = x2,
yc2 = y2;

int p1_code = 0,
p2_code = 0;

if( y1 < min_clip_y )
p1_code |= CLIP_CODE_N;
else
if( y1 > max_clip_y )
p1_code |= CLIP_CODE_S;

if( y2 < min_clip_y )
p1_code |= CLIP_CODE_N;
else
if( y2 > max_clip_y )
p1_code |= CLIP_CODE_S;

if( y1 < min_clip_x )
p1_code |= CLIP_CODE_W;
else
if( y1 > max_clip_x )
p1_code |= CLIP_CODE_E;

if( y1 < min_clip_x )
p1_code |= CLIP_CODE_W;
else
if( y1 > max_clip_x )
p1_code |= CLIP_CODE_E;

if( p1_code == 0 && p2_code == 0 )
return ( 1 );

switch( p1_code )
{
case CLIP_CODE_C:
break;

case CLIP_CODE_N:
{
yc1 = min_clip_y;
xc1 = x1 + 0.5 + ( min_clip_y - y1 ) * ( x2 - x1 ) / ( y2 - y1 );
}
break;


case CLIP_CODE_S:
{
yc1 = max_clip_y;
xc1 = x1 + 0.5 + ( max_clip_y - y1 ) * ( x2 - x1 ) / ( y2 - y1 );
}
break;

case CLIP_CODE_W:
{
xc1 = min_clip_x;
yc1 = y1 + 0.5 + ( min_clip_x - x1 ) * ( y2 - y1 ) / ( x2 - x1 );
}
break;


case CLIP_CODE_E:
{
xc1 = max_clip_x;
yc1 = y1 + 0.5 + ( max_clip_x - x1 ) * ( y2 - y1 ) / ( x2 - x1 );
}
break;

case CLIP_CODE_NE:
{
yc1 = min_clip_y;
xc1 = x1 + 0.5 + ( min_clip_y - y1 ) * ( x2 - x1 ) / ( y2 - y1 );
if( xc1 < min_clip_x || xc1 > max_clip_x )
{
xc1 = max_clip_x;
yc1 = y1 + 0.5 + ( max_clip_x - x1 ) * ( y2 - y1 ) / ( x2 - x1 );
}
}
break;


case CLIP_CODE_SE:
{
yc1 = max_clip_y;
xc1 = x1 + 0.5 + ( max_clip_y - y1 ) * ( x2 - x1 ) / ( y2 - y1 );
if( xc1 < min_clip_x || xc1 > max_clip_x )
{
xc1 = max_clip_x;
yc1 = y1 + 0.5 + ( max_clip_x - x1 ) * ( y2 - y1 ) / ( x2 - x1 );
}
}
break;


case CLIP_CODE_NW:
{
yc1 = min_clip_y;
xc1 = x1 + 0.5 + ( min_clip_y - y1 ) * ( x2 - x1 ) / ( y2 - y1 );
if( xc1 < min_clip_x || xc1 > max_clip_x )
{
xc1 = min_clip_x;
yc1 = y1 + 0.5 + ( min_clip_x - x1 ) * ( y2 - y1 ) / ( x2 - x1 );
}
}
break;


case CLIP_CODE_SW:
{
yc1 = max_clip_y;
xc1 = x1 + 0.5 + ( max_clip_y - y1 ) * ( x2 - x1 ) / ( y2 - y1 );

if( xc1 < min_clip_x || xc1 > max_clip_x )
{
xc1 = min_clip_x;
yc1 = y1 + 0.5 + ( min_clip_x - x1 ) * ( y2 - y1 ) / ( x2 - x1 );
}
}
break;

default:
break;
}

switch( p2_code )
{
case CLIP_CODE_C:
break;

case CLIP_CODE_N:
{
yc2 = min_clip_y;
xc2 = x2 + ( min_clip_y - y2 ) * ( x1 - x2 ) / ( y1 - y2 );
}
break;


case CLIP_CODE_S:
{
yc2 = max_clip_y;
xc2 = x2 + ( max_clip_y - y2 ) * ( x1 - x2 ) / ( y1 - y2 );
}
break;

case CLIP_CODE_W:
{
xc2 = min_clip_x;
yc2 = y2 + ( min_clip_x - x2 ) * ( y1 - y2 ) / ( x1 - x2 );
}
break;


case CLIP_CODE_E:
{
xc2 = max_clip_x;
yc2 = y2 + ( max_clip_x - x2 ) * ( y1 - y2 ) / ( x1 - x2 );
}
break;

case CLIP_CODE_NE:
{
yc2 = min_clip_y;
xc2 = x2 + 0.5 + ( min_clip_y - y2 ) * ( x1 - x2 ) / ( y1 - y2 );
if( xc2 < min_clip_x || xc2 > max_clip_x )
{
xc2 = max_clip_x;
yc2 = y2 + 0.5 + ( max_clip_x - x2 ) *( y1 - y2 ) / ( x1 - x2 );
}
}
break;


case CLIP_CODE_SE:
{
yc2 = max_clip_y;
xc2 = x2 + 0.5 + ( max_clip_y - y2 ) * ( x1 - x2 ) / ( y1 - y2 );
if( xc2 < min_clip_x || xc2 > max_clip_x )
{
xc2 = max_clip_x;
yc2 = y2 + 0.5 + ( max_clip_x - x2 ) *( y1 - y2 ) / ( x1 - x2 );
}
}
break;


case CLIP_CODE_NW:
{
yc2 = min_clip_y;
xc2 = x2 + 0.5 + ( min_clip_y - y2 ) * ( x1 - x2 ) / ( y1 - y2 );
if( xc2 < min_clip_x || xc2 > max_clip_x )
{
xc2 = min_clip_x;
yc2 = y2 + 0.5 + ( min_clip_x - x2 ) *( y1 - y2 ) / ( x1 - x2 );
}
}
break;


case CLIP_CODE_SW:
{
yc2 = max_clip_y;
xc2 = x2 + 0.5 + ( max_clip_y - y2 ) * ( x1 - x2 ) / ( y1 - y2 );

if( xc2 < min_clip_x || xc2 > max_clip_x )
{
xc2 = min_clip_x;
yc2 = y2 + 0.5 + ( min_clip_x - x2 ) *( y1 - y2 ) / ( x1 - x2 );
}
}
break;

default:
break;
}

if( ( xc1 < min_clip_x ) || ( xc1 > max_clip_x ) ||
( yc1 < min_clip_y ) || ( yc1 > max_clip_y ) ||
( xc2 < min_clip_x ) || ( xc2 > max_clip_x ) ||
( yc2 < min_clip_y ) || ( yc2 > max_clip_y ) )
{
return ( 0 );
}

x1 = xc1;
y1 = yc1;
x2 = xc2;
y2 = yc2;

return ( 1 );
}

下一步,还要绘制
int Draw_Clip_Line(
int x0, int y0, int x1,int y1, UCHAR color, UCHAR * dest_buffer,
int lpitch )
{
int cxs,
int cys, cxe, cye;

cxs = x0;
cys = y0;
cxe = x1;
cye = y1;

if( Clip_Line( cxs, cys, cxe, cye ) )
Draw_Line( cxs, cys, cxe, cye, color, dest_buffer, lpitch );

return ( 1 );


}
如下。



在成员函数中,先设定矩形裁剪常量

#define min_clip_x ( SCREEN_WIDTH / 2 ) - 100
#define max_clip_x ( SCREEN_HEIGHT / 2 ) + 100
#define min_clip_y ( SCREEN_HEIGHT / 2 ) - 100
#define max_clip_y ( SCREEN_HEIGHT / 2 ) + 100
进行成员函数。
int DDRAW_Interface::Draw_Clip_Line(int x0,
int y0, int x1,
int y1, UCHAR color, UCHAR * dest_buffer,int lpitch )
{
int cxs, cys, cxe, cye;

cxs = x0;
cys = y0;
cxe = x1;
cye = y1;

if( Clip_Line( cxs, cys, cxe, cye ) )
Draw_Line( cxs, cys, cxe, cye, color, dest_buffer, lpitch );

return ( 1 );


}


int DDRAW_Interface::Clip_Line(int &x1,int &y1,int &x2,int &y2)
{
// this function clips the sent line using the globally defined clipping
// region

// internal clipping codes
#define CLIP_CODE_C 0x0000
#define CLIP_CODE_N 0x0008
#define CLIP_CODE_S 0x0004
#define CLIP_CODE_E 0x0002
#define CLIP_CODE_W 0x0001

#define CLIP_CODE_NE 0x000a
#define CLIP_CODE_SE 0x0006
#define CLIP_CODE_NW 0x0009
#define CLIP_CODE_SW 0x0005

int xc1=x1,
yc1=y1,
xc2=x2,
yc2=y2;

int p1_code=0,
p2_code=0;

// determine codes for p1 and p2
if (y1 < min_clip_y)
p1_code|=CLIP_CODE_N;
else
if (y1 > max_clip_y)
p1_code|=CLIP_CODE_S;

if (x1 < min_clip_x)
p1_code|=CLIP_CODE_W;
else
if (x1 > max_clip_x)
p1_code|=CLIP_CODE_E;

if (y2 < min_clip_y)
p2_code|=CLIP_CODE_N;
else
if (y2 > max_clip_y)
p2_code|=CLIP_CODE_S;

if (x2 < min_clip_x)
p2_code|=CLIP_CODE_W;
else
if (x2 > max_clip_x)
p2_code|=CLIP_CODE_E;

// try and trivially reject
if ((p1_code & p2_code))
return(0);

// test for totally visible, if so leave points untouched
if (p1_code==0 && p2_code==0)
return(1);

// determine end clip point for p1
switch(p1_code)
{
case CLIP_CODE_C:
break;

case CLIP_CODE_N:
{
yc1 = min_clip_y;
xc1 = x1 + 0.5+(min_clip_y-y1)*(x2-x1)/(y2-y1);
} break;
case CLIP_CODE_S:
{
yc1 = max_clip_y;
xc1 = x1 + 0.5+(max_clip_y-y1)*(x2-x1)/(y2-y1);
} break;

case CLIP_CODE_W:
{
xc1 = min_clip_x;
yc1 = y1 + 0.5+(min_clip_x-x1)*(y2-y1)/(x2-x1);
} break;

case CLIP_CODE_E:
{
xc1 = max_clip_x;
yc1 = y1 + 0.5+(max_clip_x-x1)*(y2-y1)/(x2-x1);
} break;

// these cases are more complex, must compute 2 intersections
case CLIP_CODE_NE:
{
// north hline intersection
yc1 = min_clip_y;
xc1 = x1 + 0.5+(min_clip_y-y1)*(x2-x1)/(y2-y1);

// test if intersection is valid, of so then done, else compute next
if (xc1 < min_clip_x || xc1 > max_clip_x)
{
// east vline intersection
xc1 = max_clip_x;
yc1 = y1 + 0.5+(max_clip_x-x1)*(y2-y1)/(x2-x1);
} // end if

} break;

case CLIP_CODE_SE:
{
// south hline intersection
yc1 = max_clip_y;
xc1 = x1 + 0.5+(max_clip_y-y1)*(x2-x1)/(y2-y1);

// test if intersection is valid, of so then done, else compute next
if (xc1 < min_clip_x || xc1 > max_clip_x)
{
// east vline intersection
xc1 = max_clip_x;
yc1 = y1 + 0.5+(max_clip_x-x1)*(y2-y1)/(x2-x1);
} // end if

} break;

case CLIP_CODE_NW:
{
// north hline intersection
yc1 = min_clip_y;
xc1 = x1 + 0.5+(min_clip_y-y1)*(x2-x1)/(y2-y1);

// test if intersection is valid, of so then done, else compute next
if (xc1 < min_clip_x || xc1 > max_clip_x)
{
xc1 = min_clip_x;
yc1 = y1 + 0.5+(min_clip_x-x1)*(y2-y1)/(x2-x1);
} // end if

} break;

case CLIP_CODE_SW:
{
// south hline intersection
yc1 = max_clip_y;
xc1 = x1 + 0.5+(max_clip_y-y1)*(x2-x1)/(y2-y1);

// test if intersection is valid, of so then done, else compute next
if (xc1 < min_clip_x || xc1 > max_clip_x)
{
xc1 = min_clip_x;
yc1 = y1 + 0.5+(min_clip_x-x1)*(y2-y1)/(x2-x1);
} // end if

} break;

default:break;

} // end switch

// determine clip point for p2
switch(p2_code)
{
case CLIP_CODE_C:
break;

case CLIP_CODE_N:
{
yc2 = min_clip_y;
xc2 = x2 + (min_clip_y-y2)*(x1-x2)/(y1-y2);
} break;

case CLIP_CODE_S:
{
yc2 = max_clip_y;
xc2 = x2 + (max_clip_y-y2)*(x1-x2)/(y1-y2);
} break;

case CLIP_CODE_W:
{
xc2 = min_clip_x;
yc2 = y2 + (min_clip_x-x2)*(y1-y2)/(x1-x2);
} break;

case CLIP_CODE_E:
{
xc2 = max_clip_x;
yc2 = y2 + (max_clip_x-x2)*(y1-y2)/(x1-x2);
} break;

// these cases are more complex, must compute 2 intersections
case CLIP_CODE_NE:
{
// north hline intersection
yc2 = min_clip_y;
xc2 = x2 + 0.5+(min_clip_y-y2)*(x1-x2)/(y1-y2);

// test if intersection is valid, of so then done, else compute next
if (xc2 < min_clip_x || xc2 > max_clip_x)
{
// east vline intersection
xc2 = max_clip_x;
yc2 = y2 + 0.5+(max_clip_x-x2)*(y1-y2)/(x1-x2);
} // end if

} break;

case CLIP_CODE_SE:
{
// south hline intersection
yc2 = max_clip_y;
xc2 = x2 + 0.5+(max_clip_y-y2)*(x1-x2)/(y1-y2);

// test if intersection is valid, of so then done, else compute next
if (xc2 < min_clip_x || xc2 > max_clip_x)
{
// east vline intersection
xc2 = max_clip_x;
yc2 = y2 + 0.5+(max_clip_x-x2)*(y1-y2)/(x1-x2);
} // end if

} break;

case CLIP_CODE_NW:
{
// north hline intersection
yc2 = min_clip_y;
xc2 = x2 + 0.5+(min_clip_y-y2)*(x1-x2)/(y1-y2);

// test if intersection is valid, of so then done, else compute next
if (xc2 < min_clip_x || xc2 > max_clip_x)
{
xc2 = min_clip_x;
yc2 = y2 + 0.5+(min_clip_x-x2)*(y1-y2)/(x1-x2);
} // end if

} break;

case CLIP_CODE_SW:
{
// south hline intersection
yc2 = max_clip_y;
xc2 = x2 + 0.5+(max_clip_y-y2)*(x1-x2)/(y1-y2);

// test if intersection is valid, of so then done, else compute next
if (xc2 < min_clip_x || xc2 > max_clip_x)
{
xc2 = min_clip_x;
yc2 = y2 + 0.5+(min_clip_x-x2)*(y1-y2)/(x1-x2);
} // end if

} break;

default:break;

} // end switch

// do bounds check
if ((xc1 < min_clip_x) || (xc1 > max_clip_x) ||
(yc1 < min_clip_y) || (yc1 > max_clip_y) ||
(xc2 < min_clip_x) || (xc2 > max_clip_x) ||
(yc2 < min_clip_y) || (yc2 > max_clip_y) )
{
return(0);
} // end if

// store vars back
x1 = xc1;
y1 = yc1;
x2 = xc2;
y2 = yc2;

return(1);
}
在game_main()中
for( int index = 0; index < 1000; index ++ )
{
ddraw->Draw_Clip_Line( rand() % SCREEN_WIDTH, rand() % SCREEN_HEIGHT,
rand() % SCREEN_WIDTH, rand() % SCREEN_HEIGHT,
rand() % 256,
ddraw->getPrimarybuffer(),ddraw->getPrimarylpitch() );

}

现在再根据t3dlib进行,发现还有个16位的draw_clip_line16()

int DDRAW_Interface::Draw_Clip_Line16(int x0,
int y0, int x1,
int y1, int color, UCHAR * dest_buffer,int lpitch )
{
int cxs, cys, cxe, cye;

cxs = x0;
cys = y0;
cxe = x1;
cye = y1;

if( Clip_Line( cxs, cys, cxe, cye ) )
Draw_Line16( cxs, cys, cxe, cye, color, dest_buffer, lpitch );

return ( 1 );


}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: