В этой статье я объясню как делать отсечения элементарных примитивов - точки и прямоугольника.
Для начала необходимо условится, что имеются такие типы струкур данных:
typedef struct _C_Vector_2D // Для хранения отдельной вершины
{
int x;
int y;
} C_Vector_2D;
|
typedef struct _C_Rect_2D // Для хранения двух вершин
{
C_Vector_2D v[2];
} C_Rect_2D;
|
Теперь представим, что существует такая структура типа C_Rect_2D, в которой хранятся координаты двух углов
прямоугольной области отсечения, и условно называтся она будет clRect, которую я назвал в честь двух слов
Clipping Rectangle.
Отсечение точки
Несомненно отсечение точки по какой-либо области является наиболее простым.
void DrawPointClip(C_Vector_2D v)
{
// Далее идет проверка вхождения точки в прямоугольную область
if((v.x>clRect.v[0].x)&&(v.x<clRect.v[1].x)&& // Проверка по x
(v.y>clRect.v[0].y)&&(v.y<clRect.v[1].y)) // Проверка по y
b_Surface[v.y*scrWidth+v.x]=curColor; // Запись в буфер
}
|
Теперь необходимо разобраться в некоторых обозначениях. curColor - это переменная, в которой содержится текущий
цвет, так же ее размер должен совпадать с размером данных для хранения цвета пиксела экрана. Например, если работа
осуществляется в 32 битном режиме, то curColor должен быть типа int или DWORD, либо другим 4-байтовым типом.
scrWidth - это ширина экрана. Самое главное это конечно массив данных b_Surface, который должен состоять из
переменных размер которых равен количеству байт на пиксел.
Отсечение прямоугольника
Я приведу два случая отсечения прямоугольника.
Первый случай:
Нужно отрисовать треугольник, только если x0,y0 меньше чем x1,y1, то есть вершины не упорядочиваются по возрастанию.
В таком случае нагрузка процессора будет много меньше.
void DrawFillRectFastClip(C_Rect_2D r)
{
if((r.v[0].x!=r.v[1].x)&&(r.v[0].y!=r.v[1].y))
{
// Создаем переменную для хранения изменных вершин, хотя в данном случае это и не нужно,
// но обязательно создавать переменные, при передачи данных через указатели, иначе
// меняются глобальные данные.
C_Rect_2D rr=r;
int ys; Для оптимизации
// Собственно, нижеследующие 4 условия и есть само отсечение
if(r.v[0].x<clRect.v[0].x)
rr.v[0].x=clRect.v[0].x;
if(r.v[0].y<clRect.v[0].y)
rr.v[0].y=clRect.v[0].y;
if(r.v[1].x>clRect.v[1].x)
rr.v[1].x=clRect.v[1].x;
if(r.v[1].y>clRect.v[1].y)
rr.v[1].y=clRect.v[1].y;
if((rr.v[0].x!=rr.v[1].x)&&(rr.v[0].y!=rr.v[1].y)) // Рисовать ли прямоугольник
{
for(int y=rr.v[0].y;y<rr.v[1].y;y++)
{
// На новых процессорах можно использовть умножение без опасения
// снижения скорости
ys=y*1024;
for(int x=rr.v[0].x;x<rr.v[1].x;x++)
b_Surface[ys+x]=curColor;
}
}
}
}
|
Второй случай:
В этом случае необходимо упорядочивать координаты вершин и поэтому прямоугольник рисуется всегда. Код изменится лишь
немного, и поэтому я не буду приводить полную верию, а приведу лишь места, где произошли изменения.
void DrawFillRectClip(C_Rect_2D r)
{
if((r.v[0].x!=r.v[1].x)&&(r.v[0].y!=r.v[1].y)) // Здесь не было изменений
{
... // Те же переменные
int temp; // Переменная для сортировки
// Упорядочивание
if(r.v[0].x>r.v[1].x)
{
temp=rr.v[1].x;
rr.v[1].x=rr.v[0].x;
rr.v[0].x=temp;
}
if(r.v[0].y>r.v[1].y)
{
temp=rr.v[1].y;
rr.v[1].y=rr.v[0].y;
rr.v[0].y=temp;
}
// Уже 8 условий
if(r.v[0].x<clRect.v[0].x)
rr.v[0].x=clRect.v[0].x;
if(r.v[0].x>clRect.v[1].x) // Новое
rr.v[0].x=clRect.v[1].x;
if(r.v[0].y<clRect.v[0].y)
rr.v[0].y=clRect.v[0].y;
if(r.v[0].y>clRect.v[1].y) // Новое
rr.v[0].y=clRect.v[1].y;
if(r.v[1].x>clRect.v[1].x)
rr.v[1].x=clRect.v[1].x;
if(r.v[1].x<clRect.v[0].x) // Новое
rr.v[1].x=clRect.v[0].x;
if(r.v[1].y>clRect.v[1].y)
rr.v[1].y=clRect.v[1].y;
if(r.v[1].y<clRect.v[0].y) // Новое
rr.v[1].y=clRect.v[0].y;
... // Отрисовка прямоугольника
}
}
|
Вот, пожалуй, все, что необходимо знать об основах отсечения, быть может в дальнейшем будут написаны статьи про
отсечение, но более сложных примитивов.
|