OpenGL в Delphi

       

Tess-объекты можно использовать для тех же целей, что и NURBS-поверхности




В программе определен особый тип для хранения координат одной точки:

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)



Содержание раздела