В программе определен особый тип для хранения координат одной точки:
type
TVector = Array [Q.. 2] of GLdouble;
Для уверенной работы команд данного раздела следует использовать именно гип удвоенной точности.
В процедуре инициализации описана переменная специального типа, введенного для работы с мозаичными объектами. Она инициализируется приблизительно так же, как другие объекты библиотеки glu, но, конечно, другой командой:
var
tobj: gluTesselator;
...
tobj: = gluNewTess;
Теперь посмотрим, как подготавливается список для левой фигуры, квадрата с треугольным отверстием внутри.
С помощью команды gluTessCallback задаются адреса процедур, вызываемых на различных этапах рисования tess-объекта, например:
gluTessCallback{totrj, GLU_TESS_BEGIN, @glBegin); //начало рисования
При начале рисования объекта мы не планируем особых манипуляций, поэтому просто передаем адрес процедуры qlBegin.
Если же нам по сценарию потребуется выполнить какие-то дополнительные действия, необходимо описать пользовательскую несвязанную (не являющуюся частью описания класса) процедуру, обязательно указав ключевое слово stdCall, и передавать адрес этой процедуры.
Синтаксис описания подобных процедур описан в справке по команде glutessCallback. Например, если мы хотим, чтобы перед воспроизведением примитива подавался бы звуковой сигнал, необходимо вызвать следующую процедуру:
procedure beginCalIback(which GLenum); stdcall;
begin
MessageBeep (MB_OK);
glBegin(which);
end;
...
gluTessCallback(tobj, GLU_TESS_BEGIN, @ BeginCallback);
Имя процедуры безразлично, но аргументы ее должны задаваться строго по указаниям, содержащимся в документации.
Внимательно посмотрите на следующие две строки кода:
gluTessCallback (tobj, GLU_TESS_VERTEX, @glVertexJdv); // вершина
glutessCallback(tobj, GLU_TESS_SND, 3glEnd); // конец рисования
To есть при обработке отдельной вершины и в конце рисования примитивов также не будет выполняться чего-то необычного.
Для диагностики ошибок, возникающих при работе с tess-объектами, используем пользовательскую процедуру:
procedure errorCallback(errorCode: GLenum); stdcall;
begin
ShowMessage (gluErrorString(errorCode));
end;
...
gluTessCallback(tobj, GLU_TESS_ERROR, @errorCallback]; //ошибка
Команда gluErrorstring возвращает строку с описанием возникшей ошибки. Описание ошибки выдается на русском языке (на языке локализации операционной системы), так что с диагностикой проблем не будет.
Координаты вершин квадрата и треугольника вырезки хранятся в структурах, единицей данных которых должна быть тройка вещественных чисел:
const
rect: Array [0.. 3] of TVector = ((50. 0, 50. 0, 0. 0),
(200. 0, 50. 0, 0. 0),
(200. 0, 200. 0, 0. 0),
(50. 0, 200. 0, 0. 0));
tri: Array[0.. 2] ofTVector= ((75. 0, 75. 0, 0. 0),
(125. 0, 175. 0, 0. 0),
(175. 0, 75. 0, 0. 0));
Наша фигура строится приблизительно по таким же принципам, что и в примере на вырезку в NURBS-поверхности:
glNewList(l, GL_COMPILE);
glColor3f(0. 0, 0. 0, 1-0); //цвет-синий
gluTessBeginPolygon (tobj, nil); // начался tess-многоугольник
gluTessBeginContour(tobj); // внешний контур - квадрат
gluTessVertex(tobj, @rect[0], @rect[Q]); // вершины квадрата
gluTessVertex(tobj, @rect[l], @rect[l]);
gluTessVertex(tob], @rect[2], @rect[2]);
gluTessVertex(tobj, @rect[3], @rect[3]);
gluTessEndContour (tobj);
glutessBeginContour(tobj); // следующие контуры задают вырезки
gluTessVertex(tobj, @tri[0], @tri[0]); // треугольник
gluTessVertex(tobj, @tn[l], @tri[l]);
gluTessVertex(tobj, @tn[2], @tri[2]);
gluTessEndContour(tobj);
gluTessEndPolygon(tobj); // закончили с tess-многоугольником
glEndList;
При перерисовке окна просто вызывается список с именем 1.
После того как список описан, tess-объект можно удалить, это делается в конце процедуры инициализации:
gluDeleteTess(tobj);
Замечание
Обратите внимание: при вызове списка сами объекты библиотеки glu уже не используются. Точно так же вы можете удалять quadric-объекгы сразу после описания всех списков, использующих их.
Надеюсь, с первой фигурой вам все понятно, и мы можем перейти ко второй фигуре, звездочке.
Здесь для наглядности перед вызовом каждой вершины текущий цвет меняется, для чего описана специальная процедура, адрес которой задается вызовом команды gluTessCallback:
procedure vertexCallback (vertex: Pointer); stdcall;
begin
glColor3f (random, random, random);
glVertex3dv (vertex);
end;
...
gluTessCallback{tobj, GLU_TESS_VERTEX, @vertexcallback);
Массив, хранящий координаты вершин звездочки, заполняется приблизительно так же, как в одном из предыдущих примеров на NURBS-поверхность. Многоугольник второго списка состоит из единственного контура. Перечисляем вершины, хранящиеся в массиве:
glNewList(2, GL_COMPILE);
gluTessBeginPolygon (tobj, nil);
gluTessBeginContour(tobj}; For i: = 0 to 20 do
gluTessVertex(tobj, @star [i], @star [i]);
gluTessEndContour (tobj);
gluTessEndPolygon (tobj);
glEndList;
Прототип одной из используемых команд мне пришлось переписать:
procedure gluTessBeginPolygon (tess: GLUtesselator; polygon_data:
Pointer); stdcall; external GLU32;
To, что записано в стандартном заголовочном файле, расходится с документацией и приводит к ошибке.
Мы рассмотрели простейший пример на использование tess-объектов, и надеюсь, вы смогли оценить, как удобно теперь становится рисовать невыпуклые многоугольники.
В качестве исследования можете задать контурный режим воспроизведения многоугольников, чтобы увидеть, как строятся получающиеся фигуры. Приведу еще несколько примеров на мозаичные объекты. Подкаталог Ex6l содержит проект, где строится объект в виде звездочки (Рисунок 3. 36)