Каждый именованный объект внутри отображаемого объема заканчивается записью нажатия. Используя информацию записей нажатия, можно узнать, какой элемент был выбран. Если возвращается более одной записи, необходимо в цикле пройти по ним.
Важные преимущества функций выбора OpenGL заключаются в следующем:
Однако есть и недостатки:
Обратимся к простому примеру из подкаталога Ex05, чтобы уяснить использование техники выбора в OpenGL. Ha экране рисуются два треугольника - синий и красный. При нажатии кнопки мыши на поверхности окна выдается сообщение, на каком треугольнике сделан выбор, либо выводится фраза "Пустое место", если под курсором нет ни одного треугольника.
Само построение треугольников вынесено в процедуру, начало описания которой выглядит так:
procedure Render (mode : GLenum); // параметр - режим (выбора/рисования)
begin
// красный треугольник
If mode = GL_SELECT then glLoadName (1); // называем именем 1
glColor3f (1.0, 0.0, 0.0);
Процедурой Render будем пользоваться для собственно построения изображения и для выбора объекта, режим передается в качестве параметра В случае, если действует режим выбора, перед рисованием объекта загружаем его
имя командой glLoadName, аргумент которой - целое число, задаваемое разработчиком. В примере для первого, красного треугольника, загружаем единицу, для второго треугольника загружаем двойку.
При нажатии кнопки мыши координаты курсора передаются в функцию DoSelect. Это важная часть программы, поэтому приведем описание функции целиком.
function DoSelect(x : GLint; у : GLint) : GLint;
var hits : GLint;
Begin
glRenderMode(GL_SELECT); // включаем режим выбора
// режим выбора нужен для работы следующих команд
glInitNames; // инициализация стека имен
glPushName(0); // помещение имени в стек имен
glLoadIdentity;
gluPickMatrix(x, windH - у, 2, 2, @vp);
Render(GL_SELECT); // рисуем объекты с именованием объектов
hits := glRenderMode(GL_SELECT);
if hits <= 0
then Result := -1
else Result := SelectBuf [(hits - 1) * 4 + 3];
end;
Функция начинается с включения режима выбора. Команда glInitNames очищает стек имен, команда glPushName помещает аргумент в стек имен. Значение вершины стека заменяется потом на аргумент команды glLoadName.
Команда gluPickMatrix задает область выбора. Первые два аргумента - центр области выбора, в них передаем координаты курсора. Следующие два аргумента задают размер области в пикселах, здесь задаем размер области 2x2. Последний аргумент - указатель на массив, хранящий текущую матрицу. Ее запоминаем в обработчике события WM_SIZE при каждом изменении размеров окна:
glGetIntegerv(GL_VIEWPORT, @vp);
После этих приготовлений воспроизводим картинку параллельно с загрузкой имен в стек.
Последние строки - собственно выбор: снова задаем режим выбора и анализируем возвращаемый результат. Здесь SelectBuf - массив буфера выборa, подготовленный в начале работы приложения:
glSelectBuffer{MaxSelect, @SelectBuf); // создание буфера выбора
Первый аргумент - размер буфера выбора, в примере задан равным 4 - ровно под один объект, поскольку в проекте выбирается и перекрашивается один, самый верхний (ближайший к наблюдателю) объект.
Более элегантный код для этого действия записывается так:
glSelectBuffer(SizeOf(SelectBuf), @SelectBuf);
Выражение для извлечения имени элемента ((hits - 1> * 4 + 3) в случае, если нам нужно получить имя только последнего, верхнего объекта, можно заменить на просто 3, тем более что в данном примере больше одного элемента в буфер не помещается. Как следует из документации и из вводной части этого раздела, номер выбранного элемента располагается четвертым в буфере выбора, поэтому, если требуется извлечь имя только одного, самого верхнего объекта, можно использовать явное выражение для получения номера выбранного элемента:
Result := SelectBuf [3];
Замечание
В этом примере для определения имени выбранного элемента команда glRenderMode вызывается с аргументом GL_SELECT Согласно документации, в этом случае команда возвращает количество записей нажатия, помещенных в буфер выбора, а при вызове с аргументом GL_RENDER эта команда возвращает всегда ноль. Однако в примере на выбор элемента из пакета SDK при выборе элемента эта команда вызывается именно с аргументом GL_RENDER В нашем примере не будет разницы в результате, если аргументом glRenderMode брать любую из этих двух констант, однако некоторые последующие проекты будут корректно работать только при значении аргумента GL_RENDER Это следует понимать как возвращение обычного режима воспроизведения - воспроизведения в буфер кадра.
Рассмотрим пример из подкаталога Ех06. На экране рисуется двадцать треугольников со случайными координатами и цветом, при нажатии кнопки мыши на каком-либо из них треугольник перекрашивается (Рисунок 6.1).