WWW.DISSERS.RU

БЕСПЛАТНАЯ ЭЛЕКТРОННАЯ БИБЛИОТЕКА

   Добро пожаловать!

Pages:     | 1 |   ...   | 2 | 3 ||

«Михаил Краснов OpenGL ГРАФИКА В ПРОЕКТАХ DELPHI Дюссельдорф • Киев • Москва • Санкт-Петербург Книги посвящена использованию стандартной графической OpenGL в Delphi. Начиная с самой минимальной ...»

-- [ Страница 4 ] --

tex[p][1] := 255;

tex[p][2] 255;

end end;

// собственно создание текстуры GL_TEXTURE_2D, 0, 3, width, height, C, GL_RGB, FILTER, MAG FILTER, GL NEAREST;

;

If not HaveTexObj then giEndList;

Перед рисованием примитивов вызывается нужный список:

giPushMatrix;

-1.0, 0.0, 0.0);

Angle, 0.0, 0.0, 1.0);

if HaveTexObj // какой из типов списков вызывать then else только параметры glBegin( 0.0, -1.0, 1.0, 0.0);

glVertex2f( 1.0, 1.0, 1.0);

1.0, 1.0);

0.0, 1.0);

-1.0, 1.0);

В работы, как это принято в среде культурных программистов, память освобождается:

if HaveTexObj then 2, // для списков else glDeleteLists ;

Возможно, вы захотите использовать для своих проектов традиционную для демонстрационных программ текстуру в виде кирпичной кладки, тогда мо жете взять в качестве шаблона проект из Ех85, где найдете все необходимые "стройматериалы" (рис. 4.58).

Но чаше всего вы будете нуждаться в том, чтобы использовать текстуру, за гружаемую из файла. Следующие примеры помогут нам разобраться, как это сделать.

Замечание Поскольку я установил ограничение для примеров этой книги, содержащееся в том, что все они должны компилироваться в Delphi третьей версии, то буду OpenGL. Графика в проектах Delphi 26G использовать В старших версиях среды вы легко можете зовать другие форматы, что будет экономнее по отношению к дисковому про странству.

4.59 показывает один из моментов работы примера из подкаталога в котором образ текстуры загружается из я из дистрибутива Builder Кирпичная стена Такая текстура часто Текстура загружается из демонстрационных Если мы заранее знаем размер файла, то использовать класса для загрузки текстуры, а размеры массива образа задавать под размеры растра:

В : T3i 0..2] of // массив образа,..., i ;

:

- Create;

// загрузка текстуры из массива.

_. s. : j J ' : i 5 i, j ;

! j i 1. Canvas. i i, j 1 ;

;

i FILTER, GL Глава 4. Визуальные эффекты 0, 6А, здесь задается О, // объекта не на текстуру MODE, ;

;

Обратите внимание, что здесь используются функции значение веса для цветовых составляющих пиксела, поскольку OpenGL вначале идет красный в растре же первым идет синий Замечание Для простоты в примерах я часто включаю режим использования текстуры при инициализации приложения. С точки зрения оптимизации надо включать и вы ключать ее для каждого кадра.

Следующий пример, проект из содержит быть в случае, если мы заранее не знаем размер растра или хотим использо вать универсальный подход к этому вопросу. К тому же этот проект помога ет тем читателям, которые приняли мое предложение о чтобы знако миться с программированием, основанным только на функ ций API ) Для экономии места на дискете в оставшихся примерах я буду использовать ограниченный набор растров, хотя для многих примеров можно подобрать и более подходящие картинки.

Этот и некоторые следующие примеры будут крутиться вокруг астрономиче ской 4.60).

Файл растра с картой Земли я взял из DireclX SDK фирмы Microsoft Функция чтения растра основана на коде для методов класса // функция о&раза и указатель на массив образ з t : ring ;

var pointer;

const i с Header) ;

// размеры заголовка растра ype В : G.

end;

Array С.. 0 TRGB;

262 OpenGL. Графика в проектах Delphi : Fi l e ;

"И i заголовок фа;

i i : / ' и in ;

Reset 1};

Size FileSize (BmpFile) — — ;

в растр bfn, ;

// заголовки i ;

<> формат не подходит 'Invalid,, MB OK;

;

Result :-.

:-.

// память е, Size;

;

собственно х : to do / / синий красный do begin :- R;

R B;

4.60. Теперь мы можем гордиться своими астрономическими моделями Глава 4. Визуальные эффекты В программе есть несколько упрощений, скорректируйте их, если получить профессиональный код.

Я не стал загромождать текст и использовать режим но вы должны обязательно его использовать для обработки возможных ис ключений.

Кроме вы должны помнить о том, что описанная функция не считывать монохромные растры. Ниже я приведу более универсальный код, но для примеров, основанных на низкоуровневом я бы посонеювал вам посмотреть функцию чтения монохромных из последней главы Чтобы применить функцию ReaaBi используем временно указатель:

:

s Wi dt h, t He i g h t :

с о з д а н фу нкцие й i, С, следующем примере мы познакомимся сразу с несколькими важными ве щами. Во-первых, в нем используется немного другой подход к считыванию данных а во-вторых, мы еще раз как использовать не сколько текстур в кадре.

В проекте из подкаталога вокруг планеты вращается из объектов имеет свою текстуру 4.61).

4. 61. Предлагаю вам дорисовать звезды 264 OpenGL. Графика в проектах Delphi Должен сразу извиниться астрономами за множество допущенных этой модели ошибок, с позиций современной науки она совершенно без и использовать ее для уроков астрономии нельзя!

В процедуру подготовки образа текстуры передается имя растра, соз образа текстуры включено в код процедуры:

•••• ;

.' ' массива, код подходит всех [ С.. С j • : / / образ текстуры, о не : : // '., ! : Integer;

// вспомогательные переменные : // для перестановки цветов :

;

// из файла do begin Si zeOf, / / считываем ze ;

:= := ;

:

:- : [0) ;

3);

// создаем динамический массив Bitmap. Handle, 0, Height, // ;

// в растр // битового массива - :

-- 0 — 1. do // переставляем цвета :

-• Data ;

: • ;

I, :•- [ 3 ?} ;

"• 2;

), 0, 3, // оОра Height, GL_RGB, ;

(Dar.a) ;

// освобождаем память ;

Глава 4. Визуальные эффекты 3i. Free;

• end;

Это универсальная процедура и годится для любых форматов.

В осуществляется сравнительно много действий, и вызывается она два раза— для подготовки рисования и планеты, и спутника.

дисплейные списки:

Quadric := gluQuadricTexture (Quadric, TRUE};

// параметры текстуры 7.. ;

;

// текстуры для оптимизации надо бы Б ;

// для Земли glNewList: [Earth, '.. ) // подготавливаем образ 24, 24};

// (Moon, COMPILE);

'.,. ) ;

// образ другой // будет перемещение {1.3, 0.3);

24, 24);

возвращаемся на место glEndList;

/'/ после больше не нужны Это очень важно, поэтому хочу еще раз повторить: списки таких случаях являются крайне эффективным решением, иначе бы нам при ходилось подготавливать и переключать образы текстуры многократно.

каждого кадра.

При описании списка мы обращаемся к процедуре файла Здесь мог бы быть и более обширный код, но в дисплейный список компилируется только одна единственная строка, строка с пол готов кой текстуры. При вызове списка все промежуточные строки вызывают ся, файл не считывается и. в принципе, вы можете его даже удалить, к. он больше не используется.

По сценарию Земля вращается вокруг своей оси, а Луна вращается в проти воположную Земле сторону:

OpenGL. Графика в проектах Delphi glRotatef (-10, 1.0, 0.0);

glRotatef (Angle, 0.0, 0.0, // поворот Земли вокруг своей оси // для Луны необходимо добавить вращение вокруг своей оси glRotatef (-Angle, 0.0, 0.0, 1.0);

// угол вращения противоположный Переходим к следующему примеру, проекту из подкаталога Ех89, в котором показывается работа с полупрозрачной текстурой (рис. 4.62).

Рис. 4.62. Только континенты непрозрачны Для использования альфа-компонента потребовался вспомогательный дина мический массив, в который последовательно перебрасываются данные из основного. Согласно замыслу точки с преобладанием синего цвета должны быть полупрозрачными, значение для них задается для всех остальных точек это значение равно I (вы можете варьировать все па раметры для получения своих собственных эффектов):

(Data, 3);

// обычный массив образа 4) / вспомогательный + // для точек try GetDIBits 0, Data, BMInfo, DIB RGB COLORS);

Глава 4. Визуальные эффекты переставляем синий и красный цвета For I := 0 to — 1 do begin Temp := Data [I * 3] ;

Data Data Data := Temp;

end;

// с преобладанием синего делаем полупрозрачными For I := 0 to ImageSize - 1 do begin [I 4] := Data [I * 3];

// перебрасываем данные Data Data If (Data > 50) and // чтобы участки белого цвета (Data [I * 3 + 1] < 200) and // не стали полупрозрачными (Data [I 3] < then DataA :=27 // степень прозрачности синего else DataA := 255;

// сплошным end;

// !!! — при подготовке текстуры добавился 0, 3, biHeight, 0, GL_RGBA, // здесь надо было скорректировать DataA);

При описании списка не забываем сортировать многоугольники, иначе по явится ненужный узор:

glBlendFunc ;

(Earth, // оптимальнее включать режимы только при необходимости glEnable (GLJ3LEND) ;

// сортировка многоугольников {Quadric, 1.0, 24);

gluSphere (Quadric, 1.0, 24, 24);

// отключаем режимы (GL_BLEND);

glEndList;

Думаю, здесь все понятно, и мы можем перейти к следующему примеру, чтобы научиться накладывать несколько текстур, что реализуется в проекте из подкаталога Ех90 (рис. 4.63).

Код процедуры подготовки текстуры ничем не отличается от предыдущего, только поверхность океанов сделана более "плотной". По сценарию разметка Графика в проектах Delphi только на поверхности воды, поэтому помимо сферы планеты один список для сферы чуть меньшего радиуса:

Gi ;

/ '. ;

;

i_ ;

FRONT) ;

BACK) ;

1. 0, 2 4 ;

;

: : ~> --::. ;

'.. ' ;

;

4 •: FACE) ;

24, ) ;

//' радиус чуть меньш 2 4, 4.63. Теперь мы можем накладывать несколько одновременно Теперь объекты в правильном порядке (мы разбирали в разделе, посвященном смешиванию иначе не на ложения текстур:

Глава 4. Визуальные эффекты 0.0,.1.0, 0.0) ;

0.0, 0.0, 1.0);

;

// так ;

//' вначале - внутреннюю сферу (Earth! ;

/'/ — ;

Основные связанные с использованием текстуры, мы с изу чили, теперь уточним некоторые вопросы.

На рис. 4.64 представлена работа следующего примера, проекта из подката лога где наша знакомая модель неузнаваемо преобразилась.

Файл растра для этого примера я из DirectX SDK фирмы Microsoft.

4.64. Текстуру можно использовать для эмуляции зеркального отражения примера состоит не в удачном подборе образа текстуры, при любом другом картинка будет выглядеть так же превосходно. Главное в нем — режим генерации координат который задается приближенным к искажениям на поверхности сферы:

MODE, T, ;

// включается генерац еих GF,N_T};

Советую вам неспешно разобраться с этим примером, попробуйте пооче редно отключать генерацию то одной, то другой координаты и посмотреть получающийся результат.

Такой же эффект эмуляции зеркального отражения, но на поверхности ци линдра, демонстрируется проекте из подкаталога (рис. 4.65).

OpenGL. Графика в проектах Delphi 4.65. Металлические детали покрывайте текстурой для повышения зрелищности Значения всех параметров текстуры задаются такими, которые обеспечивают максимальное качество изображения:

// текстуру накладывать медленно, но точно // смешивать накладывающиеся цвета // карта координат подобна сфере ;

// иначе будет нарисована Земля Обратите внимание, что в этом примере перемешается не объект, а точка зрения наблюдателя:

(spin), *sin,,. 0.0, 1.0, 0.0, 0.0);

;

забывайте об этом примере, когда будете рисовать модели, где вуют цилиндрические детали, сделанные из металла.

Поверхности, покрытые текстурой, вполне пригодны для создания специ альных эффектов. В проекте из подкаталога Ех93 на такой поверхности вид но отражение объектов, располагающихся над ней 4.66).

Само создание эффекта традиционно и заключается в том, что объекты сце ны рисуются дважды, а для того чтобы скрыть от наблюдателя эту хитрость, используется буфер трафарета:

Глава 4. Визуальные эффекты eyez, 0.0, 0.0, 0. 0, 1. 0, 0. 0 ) // рисуем стол в плоскости отражения // буфер трафарета заполняем 1 там, где стол 1, 1);

// рисовать всегда, шаблон задаем // стол не рисуется в буфере кадра FALSE, FALSE, FALSE);

// рисуем стол TRUE, TRUE, TRUE);

// точка отражения If eyey > 0.0 then begin 1, 1);

// рисуем при 1, только там, где стол -1.0, 1.0);

// объекты сцены ;

// на стол накладывается отражение (table) ;

// смотрим сверху // объекты рисуются обычным образом glPopMatrix;

4.66. Эффект зеркального отражения можно распространять и на поверхности, покрытые текстурой Графика в проектах Delphi пора узнать, как в OpenGL можно текстуру в качестве фона, и нам поможет пример из подкаталога Ех94 (рис. 4.67).

4.67. Текстуру можно использовать и в фона плане сцены рисуем квадрат, покрытый 1 ;

нормальное матрицы проекций / подгоняем квадрат занял 0,-50.0, 50. 200. с, 300.0) ;

// нужное i Е глубины ;

текстура только ;

// текстурой L.0) ;

;

, ;

;

00. 0. 0.

;

оо.о, ;

;

// использование буфера глубины ;

/ важно /'/ нормальное состояние в матрице проекций ;

// рисуем объекты сцены Глава 4. Визуальные эффекты glTrar.slatef (50.0, 50.0, ;

1.0, 1.0, 0.0);

), 0. 0, 1. 0 ) / (random (1) + станем ограничиваться единственным использованием текстуры — по пробуем получить такую же фантастическую картинку, как на рис. 4.68.

Рис. 4.68. Эффект стеклянного обьекта Для этого добавьте следующие строки в процедуру инициализации:

glTexGer.i GL_SPHERE_MAPj ;

(GL_T, MAP) ;

GL_DECAL);

Туда же переместите строку с включением режима использования текстуры, а генерацию координат текстуры надо включать только при рисовании объ ;

glEnable (1.0);

glDisable ;

;

В последнем примере главы я попытаюсь ответить сразу на несколько во просов, часто возникающих у начинающих.

В проекте из подкаталога Ех95 рисуется волнообразная поверхность, на которой искаженно выводится текстура 4.69).

274 Графика в проектах Delphi 4.69. Искажения образа текстуры позволяют добиться разнообразных эффектов Для движения узлов поверхности необходимо менять значения элементов массива контрольных точек, после чего вычислитель также необходимо перезаряжать" Для нанесения текстуры на поверхность требуется вспомогательный массив с координатами текстуры, а также включение специального режима.

В программе рисование объектов сводится к одной строке:

0, 20, 0, 20);

// вывод поверхности В обработчике таймера пересчитываются координаты опорных точек по верхности, а также меняются координаты текстуры (для искажения образа):

А А + 0.5;

// увеличиваем управляющую переменную init surface;

// пересчитываем координаты опорных точек // ! — зарядить вычислитель новыми данными 0, 1, 3, 17, 0, 1, 51, 17, ;

// двигаем точки координат текстуры texpts texprg [0][0][0j - step;

texpts := texpts - step;

// ограничиваем искажения некоторыми пределами I f [ 0 ] [ 0 ] [ 0 ] < - 4. 0 } o r { t e x p t s > then step := — step;

// принять во внимание измененные значения координат 1, 2, 0, 4, 2, ;

При инициализации должна присутствовать строка с включением режима использования текстуры для поверхностей:

2) ;

Глава 4. Визуальные эффекты Использование искажения координат текстуры открывает перед нами столь широкие возможности, что единственным ограничением является только наша фантазия.

Я бы мог привести еще массу примеров на использование текстуры в OpenGL, однако чувствую потребность остановиться, чтобы дать вам воз можность самим попробовать свои силы.

Нет, все-таки удержусь и приведу один (последний) пример, проект из подкаталога Ех96, иллюстрирующий, как подготовить на основе образа, считанного прямо с чтобы получить эффект увеличения (рис. 4.70).

4.70. В качестве образа текстуры можно взять часть экрана В примере на экране находится лупа, которая передвигается с помощью клавиш управления курсором.

Собственно лупа представляет собой полусферу. Обратите внимание, что кривизну сферы можно менять для варьирования величины искажений:

const cf (0.0,.

0.0, eqn :

(Zoom, ;

{GL_CLTP glScalef {1.0, 0.15, 1.0);

// уменьшаем кривизну полусферы 0.5, 24, 24) ;

276 Графика в проектах Delphi После воспроизведения основного объекта, планеты, считываем в массив часть экрана, затем используем этот массив в качестве образа для накладываемой на полусферу:

(posX, 12S, RGB, GT, з ;

• ;

0, ;

0, 3, 128, 123, 0, На этом примере главу 4 действительно можно считать законченной.

ГЛАВА Пример CAD-системы:

визуализация работы робота В этой главе читатель получит представление о принципах построения срав нительно масштабных проектов, которые иллюстрируют возможности ис пользования для практических целей. Будут рассмотрены два про екта, связанные с визуализацией работы автоматов, робототехнических ус тановок.

Обсуждаются также некоторые решения технических проблем, возникаю щих при выполнении больших проектов.

Примеры к главе располагаются на дискете в каталоге Chapter5.

Постановка задачи Одним из практических применений компьютерной трехмерной графики является визуализация работы робототехнических систем.

При создании новых автоматов и роботов проектировщик нуждается в средствах визуализации для того, чтобы еще до воплощения проектируемой системы "в железе" увидеть своими глазами, как она будет функционировать в реальности.

Примеры программ, которые мы разберем в этой главе, конечно, далеки от того, чтобы решать подобные задачи в полном объеме, реальные автоматы здесь представлены весьма схематично. Однако знакомство с этими приме рами даст представление о том, как пишутся подобные программы, и помо жет получить опыт, необходимый для проектирования действительно слож ных систем.

Первый пример — программа визуализации работы автомата по установке уплотнителей. Это схематическое изображение реального устройства, вклю чающего в себя питатель, наполняемый уплотнителями, в нижней части пи Графика в проектах Delphi тателя расположен шибер, приводимый в штоком ра. Детали, на которые устанавливаются уплотнители, располагаются на шести спутниках, закрепленных на поворотном рабочем столе.

Сценарий фильма состоит в следующем: необходимо отобразить вращение рабочего стола, при приближении очередного спутника к позиции вращение рабочего стола шток поршня пе ремещает шибер, который выталкивает уплотнение из стопки накопителя и устанавливает его на деталь.

На 5.1 показан один из моментов работы программы.

5.1. Работа программы визуализации робота Пользователь может наблюдать работу установки из любой точки зрения.

При нажатии на пробел наблюдатель приближается, а при нажатии на про бел одновременно с наблюдатель удаляется в пространстве. Нажатие на клавиши 'X', 'Y' или 'Z' приводит к повороту системы по соответствую щим осям, если же при этом удерживать , вращение осуществляется в обратную сторону. Клавиша ответственна за отображение координат ных осей, нажатие на клавишу 'Р' позволяет управлять отображением пло щадки, символизирующей поверхность, на которой располагается установка.

Клавиши 'R', 'В' и эти же клавиши с позволяют регулировать цветовую насыщенность источника света. Нажатие на клавишу приводит к изменению оптических свойств материала, из которого "создана" установ ка, в программе заданы восемь материалов. Клавиши управления курсором позволяют манипулировать положением источника света в пространстве;

Глава 5. Пример CAD-системы: визуализация работы робота если нажать клавишу то в точке положения источника света рисуется небольшая сфера.

Эти и некоторые другие параметры отображения системы хранятся в файле конфигурации ARM.dat. Значение текущих установок запоминается в нем при нажатии на клавишу При запуске приложения из файла считывают ся значения установок, так что пользователь всегда может наблюдать работу системы в привычной конфигурации.

Для того чтобы ничто не отвлекало пользователя и не мешало ему, прило жение запускается в полноэкранном режиме, а на время работы приложе ния курсор не отображается.

Если нажать левую кнопку мыши, то курсор становится видимым и появля ется всплывающее меню (рис. 5.2).

5.2. Приложение снабжено всплывающим меню Выбор пункта меню "Помощь" или нажатие клавиши приводит к вы воду содержимого файла справки 5.3).

Управление можно осуществлять не только нажатием клавиш, но и более удобным способом. При выборе пункта меню "Параметры" появляется диа логовое окно "Параметры системы", котором удобным и привычным спо собом с помощью обычных элементов управления можно задать текущую конфигурацию (рис. 5.4).

Графика в проектах Delphi | Помощь по работе в программе i в клавиши, им Space. Удалить Shift-Space Включить источник света L Изменить из которого изготовлена конструкция м Включить / выключить оси XVZ О Включить / выключить • р Повернуть конструкцию по 5.З. Пользователь может Повернуть конструкцию по оси Y - Y, воспользоваться справкой Повернуть конструкцию. Z, по работе с программой • ;

'• ' 5.4. Вспомогательное диалоговое окно программы ••• •'..., • •• Структура программы Программа реализована в виде нескольких модулей. Во-первых, это выпол модуль, самый файл комплекса, хранящий весь основном код. Для работы он нуждается файле динамической библиотеке, хранящей процедуры и данные, связанные с источником света.

Кроме этого, используются еще две библиотеки, и ParForm.dll.

В принципе, основной модуль комплекса может работать и без этих двух библиотек. Первая из них предназначена для вывода окна "Об авторах", а вторая для диалогового окна по заданию параметров системы.

Глава 5. Пример CAD-системы: визуализация работы робота В этом разделе мы основные модули программного комплекса.

Подкаталог ЕхО1 содержит проект основного модуля и обязательную биб лиотеку InitRC.dll.

Проект основного модуля не использует библиотеку классов Delphi, поэтому размер откомпилированного модуля занимает всего Для экономии ресурсов запретим пользователю запускать несколько копий приложения. При запуске приложения определяем, зарегистрированы ли в системе окна такого же класса, и если это так, то прекращаем программу:

<> 0 then Exit;

Это необходимо сделать самым первым действием программы.

Следующий — задание высшего приоритета для процесса:

HIGH ;

Теперь все остальные приложения, выполняемые станут рабо тать значительно медленнее, испытывая острую нехватку в процессорном времени, но мы тем самым обеспечим наивысшую производительность на шего приложения.

Замечание Возможно, более тактичным по отношению к пользователю будет предоставле ние ему возможности самостоятельно решать, стоит ли повышать приоритет процесса. Тогда это действие можно оформить так:

(0,'Для более быстрой работы приложения все остальные про цессы будут замедлены.', = idOK then SetPriorityClass На следующем шаге определяем, доступна ли для использования динамиче ская библиотека InitRC.dll, без которой наше приложение не сможет рабо тать. В проекте описана соответствующая ссылка на библиотеку:

rials :

Значение этой величины — указатель па библиотеку. Если он не может быть информируем пользователя и прекращаем работу:

( ' i If IN STANCE begin MessageBox (0, 'Невозможно файл: библиотеки "., 'Ошибка инициализации Exit end;

Ответ на вопрос, зачем потребовалось выносить в отдельную библиотеку процедуры инициализации источника света, мы дадим чуть позже.

282 Графика в Посмотрим, что происходит дальше в нашем приложении. Откройте модуль WinMain.pas, содержащий описание головной процедуры, и модуль хранящий описание оконной функции.

В предыдущих примерах, построенных полностью на использовании функ ций API, нам не приходилось использовать всплывающее меню, а сейчас разберем, как обеспечивается его функционирование.

В программе должны быть введены целочисленные идентификаторы пунк тов создаваемого меню, обязательно в блоке констант:

const // идентификаторы пунктов меню = 101;

// пункт "Параметры" = 102;

// пункт "Об авторах" id_close = 103;

//' пункт "Выход" = 104;

// пункт "Помощь" Для хранения ссылки на меню должна присутствовать переменная типа В процедуре, соответствующей точке входа в программу, ссылка при нимает ненулевое значение при вызове функции заполне ние ВЫЗОВОМ фунКПИЙ AppendMenu:

:= If MenuPopup <> 0 then begin (MenuPopup, MFEnabled, ' ) ;

AppendMenu (MenuPopup, AppendMenu {MenuPopup, id_about, AppendMenu (MenuPopup, id_close, '&Выход');

end;

В отличие от обычного для Delphi подхода, теперь все действия, связан ные с функционированием меню, необходимо обслуживать самостоятельно, в том числе и его появление. В проекте меню появляется при щелчке левой кнопки мыши в левом верхнем углу экрана, чтобы не загораживать картинку:

:

begin ShowCursor (True);

(MenuPopup, end;

На время функционирования меню включается курсора, чтобы пользователю не пришлось осуществлять выбор пунктов вслепую.

Обработка выбора, произведенного пользователем, связана с сообщением параметр wParam такого сообщения содержит значение, указы вающее на сделанный выбор:

Глава 5. Пример визуализация работы робота Command : // всплывающее меню begin case of выбранный : // "Параметры" id_heip : 0);

// "Помощь" "Выход" : SendMessage (Window, wm_Destroy, : About;

// "Об авторах" end;

// case // рисовать ли курсор = then else ShowCursor (True);

// При завершении работы приложения память, ассоциированную с меню, не обходимо освободить:

Из этого же фрагмента вы можете увидеть, что вывод справки осуществля ется ВЫЗОВОМ фуНКЦИИ WinHelp.

Поскольку справка может вызываться по выбору пункта меня и по нажатию клавиши , обратите внимание, что нажатию этой клавиши в операци онной системе соответствует отдельное сообщение Приложение работает в полноэкранном режиме, что обеспечивается зада нием стиля окна как or or ws EX что соответствует окну без рамки и без границ, располагающемуся поверх остальных окон. Обработчик сообщения начинается с того, что окно развертывается на весь экран — приложение себе сообщение "развернуть окно":

SendMessage (Window, WM 0) ;

Замечание Такой способ создания полноэкранного окна работает для большинства графи ческих карт, но я должен предупредить, что на некоторых картах он все же не срабатывает, т. е. окно не разворачивается на весь экран.

После этого происходит обращение к процедуре, считывающей значения установок и загружающей процедуры из библиотеки Поясним, как это делается, на примере процедуры инициализации источника света.

Введен пользовательский тип:

= procedure 284 OpenGL. Графика в проектах Delphi Затем установить адрес этой процедуры в динамической биб лиотеке:

:= : ;

Первый аргумент используемой функции API — ссылка на рой — имя экспортируемой функции.

Далее в программе происходит считывание массива храня щего значения записанных установок. Если это окажется невозможным, например, из-за отсутствия файла, переменные инициализируются некото рыми предопределенными значениями. Затем создаются quadric-объекты и подготавливаются дисплейные после чего остается только включить таймер. В коде подготовки списков я опираюсь на константу, задающую уровень детализации рисования объектов. Варьируя значение этой констан ты, можно получать приложения, имеющие приемлемые скоростные харак теристики на маломощных компьютерах, конечно за счет качества изобра жения.

Код воспроизведения кадра при использовании дисплейных списков стано вится сравнительно коротким и ясным.

Для максимального сокращения промежуточных я не стал созда вать отдельной процедуры чтобы сэкономить хотя бы де сяток тактов.

begin // используется в case // очистка буфера цвета и буфера глубины or // запомнили текущую систему координат 1, О, О);

glRotatef [2J, 0, 1, 0);

(AngleXYZ [3], 0, 0, 1;

;

// запомнили текущую систему координат - 0, If (4);

// рисуем площадку If then // рисуем оси If then begin // рисуем источник света g.l glTranslatef [1], [3} ;

0.01, 5, ;

end;

glCallList (ID;

// список — основание накопителя (1);

// штыри накопителя // стопка прокладок glTranslatef (0.1, -0.1, 0.0);

Глава 5. Пример визуализация работы робота glEnable TEXTURE ;

на цилинлр текстура // уплотнитель в стопке (0.0, hStopki) ;

(5) ;

// рисуем крышку накопителя 0,0, (10) ;

рисуем (ОЛЬ, 0.0, 0.0, 1.0, 0.0);

(6);

1.0, 0.01;

glTranslatef (-1.4, 0.0, 0.0};

// штырь If then begin // флаг, вращать ли If = 0 then begin hStopki // уменьшить If n5topki < 0 hStopki := 1;

// стопка закончилась end;

(0.9, 0.0, glRotatef (90.0, 0.0, // список •• штырь end;

// рисуем шибер // вращать then glTranslatef !l.25, 0.0, 0.0) else begin 0.0, 0.0);

;

end;

glRotatef "1.0, 0.0:;

// - кубик {9};

If and 4) begin // закончилась flgRotation := True;

Angle := 0;

286 Графика в проектах Delphi 0;

end;

// текущая точка - G, glCallList // ось рабочего стола glRotatef (90.0, 0.0, 1.0, If flgRotation then // флаг, вращать ли стол glRotatef ( Angle, 1.0, 0.0, 0.0);

glCallList (2);

// цилиндров glRotatef (-90.0, 0.0,.0, 0.0: ;

систему координат - назад glRotatef (-30.0, 0.0, 0.0, // // список — шесть кубиков — glCallList (3);

// конец работы ;

end;

Стоит обратить внимание, что стопка уплотнителей симулируется наложе нием текстуры на цилиндр, поскольку прорисовка двух десятков цилиндров приведет к сильной потере производительности. В примере используется одномерная текстура:

const // параметры текстуры = 64;

: Array [0..3] of GLfloat 0.0, 1.0, 0.0);

Texlmage : Array [1.. 3 * of procedure begin While j < Width * 3 do begin Texlmage := 248;

8;

// красный Texlmage + 1] = 150;

/'/ зеленый Texlmage [j +2] = 41;

// Texlmage [j + 3] 205;

красный Texlmage [j +4] 52;

// Texlmage [j + 5] = 24;

синий, 6);

end;

glTexParameteri WRAP 5, GL glTexParameteri GL MAG FILTER, Gi, glTexParameteri GL GL glTexIrnagelD 0, 0, GL UNSIGNED BYTE, Глава 5. Пример визуализация работы робота glEnabie Si;

// чтобы полоски не размывали;

/!.

MODE, // поворачиваем поперек цили.чдра (GL S, ;

end;

В следующей главе мы узнаем, как можно в OpenGL красиво выводить сим волы и текст, а пока буквы, размечающие координатные оси, рисуются от резками. Я не стал создавать дисплейных списков для построения коорди натных осей, пользователь вряд ли нуждается в их воспроизведении, а мне оси требовались больше для отладки проекта.

procedure // Оси координат begin glColor3f (0, ;

glVertex3f (0, 0, 0) ;

(3, С, ;

0, 0) ;

(0, 2, 0) ;

(0, 0, 0} (0,. 0, ;

// буква X glBegin (3.1, - 0. 2, {3.1, 0. 2, (3.1, - 0. 2, 0. 1) glVertex3f // буква glBegin LINES) glVertex3f (0.0, ;

0.

gIVertex3f 1, -C i glVertex3f (0.0, 2. 1, ;

2. J, 1: ;

(CO, 2. 0 ;

0.1) // буква Z gl Begi n ;

- 0. 1, Графика в проектах Delphi glVertex3f (0.1, 0.1, 3.1) ;

glVertex3f 0.1, 3.1);

glVertex3f (-0.1, 3.1);

glVertex3f (0.1, 0.1, 3.1) ;

// Восстанавливаем значение цвета glColor3f (Colors [1], Colors [2], Colors Модули приложения Головной модуль программы только с использованием функций API, что обеспечивает миниатюрность откомпилированного файла.

Желание облегчить взаимодействие пользователя с программой привело ме ня к мысли о необходимости включения диалогового окна, в котором поль зователь мог бы удобным и привычным для себя образом задавать конфигу рацию системы. Если бы я и этот модуль создавал без VCL, эта книга ни когда не была бы написана — страшно даже представить объем работы по кодированию диалоговых окон вручную. Поэтому вспомогательный модуль я разработал обычным для Delphi способом, а для взаимодействия с голов ной программой использовал подход, основанный на вызове динамической библиотеки.

Окно "Параметры системы" снабжено интерфейсными элементами, позво ляющими задавать установки. Это окно имеет также кнопку реализующую стандартное для подобных диалогов действие. Пользователь имеет возможность попробовать, как будет происходить работа системы при выбранных значениях установок. Вот эта самая кнопка потребовала значи тельного усложнения структуры программы.

Начнем изучение модулей комплекса с самого неответственного с модуля About.dll, содержащего окно "Об авторах" 5.5).

Подкаталог ЕхО2 содержит соответствующий проект.

Логотип автора приложения представляет собой стилизацию логотипа биб лиотеки OpenGL.

5.5. "Все права зарезервированы" Глава 5. Пример визуализация работы робота Чтобы впоследствии поместить окно в динамическую библиотеку, в разделе interface модуля формы окна "Об авторах" я поместил следующую строку с forward-описанием процедуры:

procedure export;

Код процедуры, это уже в разделе implementation модуля совсем простой создание и отображение окна:

procedure export;

begin ( Application);

end;

Итак, модуль содержит описание экспортируемой функции AboutForm, связанной с отображением окна "Об авторах".

Проект из подкаталога ЕхО2 предназначен для компоновки файла динамической библиотеки library About;

uses in exports AboutForm;

// функция, размещаемая в DLL begin end.

Откомпилируйте этот проект, выбрав соответствующий пункт меню среды Delphi или нажав комбинацию клавиш +.

Замечание Обращаю ваше внимание, что запускать проекты с заголовком l i brary бес смысленно, невозможно "запустить" динамическую библиотеку.

После компиляции получается файл About.dll, который необходимо пере местить в каталог приложения, использующего эту библиотеку, то есть туда же, где располагается модуль ARM.exe.

Головной модуль при выборе пользователем пункта меню "Об авторах" об ращается к процедуре AboutForm, загружаемой из библиотеки. Если при за грузке функции происходит ошибка, исключительная ситуация, приложение ее снимает. Я оставляю пользователя в неведении по поводу произошедшей аварии в силу ее малозначительности.

В модуле головного проекта содержится описание соответствую щих типов и процедуры:

290 Графика в проектах Delphi type = procedure // тип загружаемой из About Form : // переменная procedure About;

// процедура begin try // режим защиты от ошибок := // ссылка на соответствующую If hCDll begin // ошибка hCDll :- NULL;

// освобождаем память Exit // остальные действия не end else // пытаемся получить адрес процедуры в dll About := GetProcAddress (hCDll, ) ;

If not Assigned then Exit // ошибка, не содержит такую процедуру else // все в порядке, запускаем процедуру dll If not hCDll = NULL then begin // освобождение памяти hCa.l 1 NULL;

end;

except Exit // в случае снять аварийную ситуацию и закончить //try Итак, при использовании процедуры из динамической библиотеки необхо димо описать процедурный тип и создать ссылку на библиотеку, после чего можно загружать процедуру.

Обмен данными с DLL Напомню, что головной модуль не использует библиотеку классов Delphi, однако проектировать без визуальных средств диалоговые окна — дело слишком тяжелое. Поэтому будем использовать для их реализации все мощ ные и удобные средства, предоставляемые Delphi специально для этих целей.

Диалоговые окна размещены о динамических но должны иметь общие с головной программой данные. Решить проблему обмена дан ными с различными модулями можно различными путями, в частности, в этом примере используются указатели на данные.

диалоговое окно "Параметры системы" имеет флажок "Пло щадка", с помощью которого пользователь может задавать режим отображе ния этого объекта. После задания режима при воспроизведении кадра не обходимо соответствующим образом отобразить текущие значения установки.

Глава 5. Пример визуализация работы робота Значение установки хранит в головном модуле булевская переменная-фла жок если она равна то при перерисовке кадра вызывается дисплейный список площадки:

If then (4);

// рисуем площадку Откройте модуль в подкаталоге ЕхОЗ и посмотрите сание процедуры размещаемой в динамической библиотеке которая связана с отображением и функционированием диало гового окна "Параметры системы". Первые четыре аргумента этой процеду ры указатели на переменные булевского типа;

каждая из них задает опре деленный флаг, управляющий режимом отображения осей, точника света или указателя курсора. При вызове этой процедуры из головного модуля в качестве фактических аргументов процедуры передаются ссылки на соответствующие переменные:

@flgCursor, Вы можете увидеть это в модуле ParForm.pas головного проекта Теперь при нажатии кнопки "Применить" окна "Параметры системы", как и при закрытии этого окна, переменной по заданному адресу устанавливается соответствующее значение:

If then : else := False;

При очередном перерисовывании тику таймера главного окна системы это значение задаст, отображать ли площадку.

Таким образом, передавая в библиотеки ссылки, т. е. адреса данных, пере менных и массивов головного модуля, я делаю эти данные доступными для использования, чтения и модификации за его пределами.

Использование ссылок является простым и удобным средством обмена дан ными между модулями программных систем. Я не претендую на роль пер вооткрывателя этого механизма, но уверен, что многим начинающим будет очень полезно освоить его, чтобы понять, почему многие команды OpenGL требуют в качестве аргумента именно адрес данных, а не сами данные.

Замечание если команда OpenGL имеет несколько форматов, то использова ние формата, основанного на ссылочной адресации данных, является более предпочтительным в целях экономии памяти и повышения скорости работы.

Для изменения оптических свойств материала и свойств источника света, таких как его положение и направление, необходим вызов соответствующих команд OpenGL. Простая передача данных о заданных значениях парамет 292 Графика в проектах Delphi ров решит проблему только, если при каждой перерисовке экрана будет происходить обращение к процедуре инициализации источника света.

нятно, что это слишком накладно и не может считаться удовлетворительным.

Одно из возможных решений состоит в том, что все процедуры, связанные с источником света, размещаются в отдельной библиотеке, к которой по мере необходимости обращаются головной модуль программы и сервисный модуль параметров системы. Менее элегантным решением является дубли рование кода, когда одни и те же команды OpenGL вызываются из разных модулей системы.

Окно параметров системы снабжено также кнопкой "Отменить" на случай, если пользователь захотел отказаться от внесенных изменений, но не нажал еще кнопку "Применить". В этом случае, а также при появлении окна пара метров необходимо иметь возможность получения данных о текущих значе ниях установок. Для этого библиотеку InitRC пришлось дополнить процеду рой, возвращающей адреса переменных, являющихся, по сути, локальными данными модуля:

procedure GetData (var :

var PLPosition :

var PFAmbient :

var PLDirection : export;

begin PMaterials PLPosition := PFAmbient := @FAmbient;

:= end;

В подкаталоге ЕхО4 я поместил исходные файлы пользовательской библио теки Обратите внимание, что "головная часть" проекта динамической библиотеки соответствует этапу ее инициализации. В данном примере на этом этапе я задаю оптические свойства материала конструкции и инициализирую пе ременные.

begin // инициализация библиотеки Materials := Material [1] := Material [2] := Material [3] := // цвет материала и диффузное отражение материала - значения из Material [1]);

Material [2]);

Material [3]);

GL_SHININESS, 51.2);

end.

Глава 5. Пример визуализация работы робота Дополнительные замечания Приложению требуется несколько секунд для завершения работы. Чтобы у пользователя не сложилось впечатление, что система зависла, по оконча нии работы я убираю (минимизирую) окно приложения в панель задач:

0);

Возможно, дотошный читатель обратит внимание на то, как я громоздко провожу проверку на правильность заполнения полей редактирования в мо дуле, реализующем диалоговое окно "Параметры системы": каждое поле ре дактирования контролируется отдельно.

Замечание Здесь я сознательно не использовал операторы Delphi as и i s, упрощающие и сокращающие код, поскольку их использование заметно замедляет работу приложения.

Серьезным упреком к процедуре проверки может быть то, что для перевода вещественных чисел в строку и наоборот используются процедуры и str, не учитывающие, какой разделитель дробной части установлен в систе ме, поэтому могут возникнуть неудобства, если пользователь сильно привык к запятой в качестве такого разделителя.

При проверке содержимого каждого поля в случае допущенной пользовате лем ошибки применяется "тихая" исключительная ситуация — стандартный прием:

If edtFAmbientR.Text = then rai se ('Заполните все поля! ' );

(edtFAmbientR.Text, iW);

If then raise ('Числовые данные введены с Обращение к процедуре проверки осуществляется в защищенном блоке, при возникновении ошибки класса EAbort пользователь получает соответствую щую информацию, и попытка применить введенные значения прекращается:

try except on E : EAbort do With Forml do begin := False;

False;

:= False;

False;

True;

:= Графика в проектах Delphi True;

Exit;

// ошибка, применять нельзя end;

// end;

// try Разобранную программу можно использовать в шаблона для проек тирования других приложений подобного типа. Подкаталог ЕхО5 содержит еще один проект по визуализации также схематично демонстри рующий работу реальной установки (рис. 5.6).

Рис. 5.6. Еще один пример на визуализацию работы роботов Программа помимо сценария кадра ничем не отличается от разобранного ранее в этой главе примера: каркас проекта не изменился, только ние дополнилось клавишами '<' и '>', с помощью которых можно сдвигать точку зрения в пространстве.

На поверхностный, взгляд может показаться, что здесь решается более простая задача по сравнению с первоначальным проектом, работа не такая объемная и значительно менее зрелищная. Однако самое интересное кроется как раз в мелких деталях.

Болты, ограничивающие движение верхней детали системы, "продеты" сквозь отверстия в плите. Для рисования этих отверстий верхнюю и ниж Глава 5. Пример CAD-системы: визуализация работы робота нюю часть плиты пришлось разбить на десять отдельных частей. Сами от верстия рисуются по принципам, знакомым нам по главе 2, когда мы учи лись рисовать дырки. На рис. 5.7 приведен вариант воспроизведения плиты в каркасном режиме, когда хорошо выделены все секторы, на которые на самом деле разбита поверхность.

5.7. Для того чтобы нарисовать отверстия в плите, пришлось потрудиться Замечание Использование буфера трафарета привело бы здесь к потере производитель ности в десятки раз. Напоминаю, что есть еще один способ решения таких за дач — использование Код воспроизведения кадра, как и в предыдущем примере, становится срав нительно кратким после того, как вся система поэлементно описана в дис плейных списках:

begin // в case // очистка буфера цвета и буфера глубины // запомнили текущую систему координат — 0, // сдвиг [1], AddXYZ [21, [31 — ;

Графика в проектах Delphi glRotatef (AngleXYZ [1], 1, 0);

glRotatef (AngleXYZ [2], 0, 1, 0);

glRotatef (AngleXYZ [3], 0, 0, 1);

If flgSquare then glCallList (1);

// рисуем площадку (плоскость узла) If then OcXYZ;

// рисуем оси If flgLight then begin // рисуем источник света glTranslatef [1], [3] ) ;

(ObjSphere, 0.01, 5) ;

glTranslatef [1], [2], [3] end;

glScalef (CoeffX, CoeffY, CoeffZ);

glTranslatef (0.0, 0.0, glCallList (3);

// пружина glCallList (10);

// дырки в плите под болты glCallList f5);

// плита 1.0, 0.0, 0.0);

glRotatef (AngleX, glRotatef (AngleY, 0.0, 1.0, 0.0, glTranslatef (0.0, / glCallList (4);

/ / первый болт glCallList (8);

/ / второй glCallList (9);

/.

0.0, 0.0, 1.0);

glRotatef (AngleZ, glCallList (2);

/,/ со шпинделем glCallList (6);

/ патрон / деталь glCallList (7) ;

/, // конец работы SwapBuffers(DC) ;

end;

Конечно, вызываемые подряд списки можно также объединить, и после этого код вообще уложится в десяток строк.

ГЛАВА Создаем редактор Эта глава посвящена разработке графического редактора на основе OpenGL.

Она будет особенно полезна программистам, занимающимся созданием и систем визуализации ввода исходных данных для подобных приложений. Рассматриваются также вопросы, связанные с выбором объек тов и выводом символов в OpenGL.

Примеры располагаются на дискете в каталоге Chapter6.

Выбор элементов Задача выбора определенных элементов на экране является очень распро страненной для многих интерактивных приложений, поэтому достойна под робного рассмотрения. Решений ее несколько. Одно из самых простых со стоит в том, что элементы раскрашиваются в уникальные цвета, и для выбо ра элемента просто определяется цвет пиксела в нужной точке.

Рассмотрим проект из подкаталога ЕхО1. Это плоскостная картинка, содер жащая изображения двух треугольников: красного и синего. При нажатии кнопки мыши определяем цвет пиксела под курсором и выделяем его ставляющие, по которым вычисляем выбранный элемент. Для красного тре угольника код, например, может быть следующим:

ColorToGL [X,Y], G, B);

If <> 0) and (B 0) then красный Здесь для определения составляющих цвета пиксела вызывается пользова тельская процедура, знакомая по главе 1.

Графика в проектах Delphi В примере для определения цвета пиксела под курсором используются сред ства Delphi — прямое обращение к цвету пиксела формы.

В проекте из подкаталога ЕхО2 делается все то же самое, но пиксела определяется с помощью команды OpenGL:

: Array of glReadPixels (X, Y, (wrk [0] <> 0} {wrk = 0) then ShowMessage ('Выбран If (wrk [0] = and о then синий else ShowMessage ('Ничего не Выбор объектов, основанный на определении пиксела под немногим отличается от простого анализа координат точки выбора.

Достоинства такого метода — простота и высокая скорость. Но есть и недостатки:

G метод неприменим при источнике света;

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

можно выбрать лишь элемент, нарисованный последним и лежащий сверху.

Следующий метод выбора похож на предыдущий: элементы, раскрашенные в уникальные цвета, рисуются в заднем буфере кадра, без вызова команды Для выбора элементов анализируем цвет заднего буфера в по зиции, в которой осуществляется выбор. В заднем буфере элементы рисуют ся без текстуры и выключенном источнике чтобы не портить чистые цвета.

Обратимся для к проекту из подкаталога ЕхОЗ, где рисуются два треугольника одинакового цвета, при нажатии кнопки сообщается, какой треугольник выбран, левый или правый.

В процедуре перерисовки окна после команды код рисования треугольников однако каждый треугольник раскрашивается в уникальные цвета. Цвет фона для простоты дальнейших манипуляций за дается черным.

Обработка нажатия кнопки начинается так:

-• Y, I, 1, GL RGB, GL UNSIGNED BYTE, Глава 6. Создаем свой редактор If (Pixel [0] о 0) and (Pixel [2] = then ('Выбран левый есть считываем пиксел в текущем, заднем., буфере кадра в позиции кур сора, для чего необходимо предварительно установить контекст воспроиз ведения. Массив, хранящий цвета пиксела — массив трех элементов типа Для разнообразия в этом примере я не занимаю контекст воспроизведения один раз на все время работы приложении, а это дважды: один раз при окна для сцены и второй раз при нажа тии кнопки мыши для того, чтобы воспользоваться командами OpenGL чте ния пиксела. Каждый раз после работы контекст, освобождается.

Чтобы не сложилось впечатление, что такой метод применим только для плоскостных построений, предлагаю посмотреть пример из подкаталога ЕхО4, где рисуются сфера и конус из одного материала и осуществляется выбор между ними. Можете перенести вызов команды в конец кода перерисовки окна, чтобы увидеть, как сцена выглядит в заднем буфере.

Буфер выбора В режиме выбора OpenGL возвращает так называемые нажатия (hit которые содержат информацию о выбранном элементе.

Для идентификации элементов они должны быть поименованы, именование осуществляется С ПОМОЩЬЮ КОМаНД ИЛИ Имя объекта в OpenGL — любое целое число, которое позволяет уникально идентифицировать каждый выбранный элемент. OpenGL хранит имена в стеке имен.

ДЛЯ ВЫЗВатЬ КОМаНДу с аргументом GL_SELECTION. Однако прежде чем сделать это, требуется опре делить буфер вывода, куда будут помешаться записи нажатия. При нахожде нии в режиме выбора содержимое заднего буфера кадра закрыто и не может быть изменено.

Библиотека OpenGL будет возвращать запись нажатия для каждого находящегося в отображаемом объеме. Для выбора только среди объектов, находящихся под курсором, необходимо изменить отображаемый объем. Биб лиотека ПОЗВОЛЯЮЩУЮ ЭТО сделать— которая создает небольшой отображаемый объем около координат курсора, передаваемых в команду в качестве параметров. После задания области вы вода можно только выбирать объекты. Напоминаю, что перед рисованием Объектов ИЛИ После осуществления выбора необходимо выйти из режима выбора вызовом команды с аргументом С этого момента команда Графика в проектах Delphi будет возвращать число записей нажатия, и буфер выбора может быть про анализирован. Буфер выбора представляет собой массив, где каждая запись нажатия содержит следующие элементы:

число имен в стеке имен на момент нажатия;

минимум и максимум оконной координаты Z примитивов в отобра жаемом объеме на последнее нажатие;

эти значения лежат в пределах от нуля до единицы, но перед выводом в буфер выбора умножаются на фактическое содержание буфера имен на момент нажатия, начиная с верхнего.

Каждый именованный объект внутри отображаемого объема заканчивается записью нажатия. Используя информацию записей нажатия, можно узнать, какой элемент был выбран. Если возвращается более одной записи, необхо димо в цикле пройти по ним.

Важные преимущества функций выбора OpenGL заключаются в следующем:

они входят в стандартную часть OpenGL и не требуют дополнительного кодирования;

буфер выбора предоставляет гибкий путь для выбора группированных или иерархических элементов.

Однако есть и недостатки:

необходимый размер буфера выбора должен быть известен до входа в ре жим выбора для определения размера требуемой памяти;

глубина стека имен ограничена, поэтому очень сложные иерархические модели будут определяться как nil, т. е. не определяться вообще.

Обратимся к простому примеру из подкаталога ЕхО5, чтобы уяснить исполь зование техники выбора в OpenGL. На экране рисуются два треугольника — синий и красный. При нажатии кнопки мыши на поверхности окна выдает ся сообщение, на каком треугольнике сделан выбор, либо выводится фраза "Пустое место", если под курсором нет ни одного треугольника.

Само построение треугольников вынесено в процедуру, начало описания которой выглядит так:

procedure Render (mode : // параметр — режим (выбора/рисования) begin // красный треугольник If mode = then (1) // называем именем glColor3f (1.0, 0.0, 0.0};

Процедурой Render будем пользоваться для собственно построения изобра жения и для выбора объекта, режим передается в качестве параметра. В слу чае, если действует режим выбора, перед рисованием объекта загружаем его Глава 6. Создаем свой редактор имя командой аргумент которой — целое число, задаваемое раз работчиком. В примере для первого, красного треугольника, загружаем еди ницу, для второго треугольника загружаем двойку.

При нажатии кнопки мыши координаты курсора передаются в функцию Это важная часть программы, поэтому приведем описание функ ции целиком.

function : GLint;

у : GLint) : GLint;

hits : GLint;

begin // включаем режим выбора // режим выбора нужен для работы следующих команд // инициализация стека имен // помещение имени в стек имен windH — у, 2, 2, @vp);

SELECT);

// рисуем объекты с именованием объектов hits := if hits <= then Result := — else Result := SelectBuf [(hits - 1) 4 + 3];

end;

Функция начинается с включения режима выбора. Команда очищает стек имен, команда glPushName помещает аргумент в стек имен.

Значение вершины стека заменяется потом на аргумент команды giLoadName.

Команда gluPickMatrix задает область выбора. Первые два аргумента — центр области выбора, в них передаем координаты курсора. Следующие два аргумента задают размер области в пикселах, здесь задаем размер области 2x2. Последний аргумент — указатель на массив, хранящий текущую матри Ее запоминаем в обработчике события при каждом изменении размеров окна:

@vp);

После этих приготовлений воспроизводим картинку параллельно с загруз кой имен в стек.

Последние строки — собственно выбор: снова задаем режим выбора и ана лизируем возвращаемый результат. Здесь SelectBuf — массив буфера выбо ра, подготовленный в начале работы приложения:

// создание буфера выбора Графика в проектах Delphi Первый аргумент — буфера выбора, в примере задан равным ровно под один объект, поскольку в проекте выбирается и перекрашивается один, самый верхний {ближайший к наблюдателю) объект.

Более элегантный код для этого действия записывается так:

Выражение для извлечения имени элемента - • з) в если нам нужно получить имя только последнего, верхнего объекта, можно заменить на просто 3, тем более что в данном примере больше одного эле мента в буфер не помещается. Как следует из документации и из вводной части этого раздела, номер выбранного элемента располагается четвертым в буфере выбора, поэтому, если требуется извлечь имя только одного, самого верхнего объекта, можно использовать явное выражение для получения но мера выбранного элемента:

Result := SeiectBuf [3];

В этом примере для определения имени выбранного элемента команда вызывается с аргументом GL_SELECT. Согласно документации, в этом случае команда возвращает количество записей нажатия, помещенных в буфер выбора, а при вызове с аргументом эта команда возвраща ет всегда ноль. Однако в примере на выбор элемента из пакета SDK при выбо ре элемента эта команда вызывается именно с аргументом В на шем примере не будет разницы в результате, если аргументом брать любую из этих двух констант, однако некоторые последующие проекты будут корректно работать только при значении аргумента ЭТО следует понимать как возвращение обычного режима воспроизведения — вос произведения в буфер кадра.

Рассмотрим пример из подкаталога На экране рисуется двадцать тре угольников со случайными координатами и цветом, при нажатии кнопки мыши на каком-либо из них треугольник перекрашивается При проектировании собственного модельера мы возьмем из этого примера некоторые приемы работы с объектами.

В программе вводится тип используемых геометрических объектов:

type = record // треугольник Array of v2 : Array of v3 : Array [0..1} of color : Array of // цвет объекта Глава 6. Создаем свой редактор Рис. 6.1. В примере осуществляется выбор среди двадцати объектов со случайными координатами Объект, треугольник, состоит из трех вершин, для хранения координат каж дой из которых используем массивы из двух вещественных чисел, X и Y.

Цвет каждого объекта записывается в массиве из трех вещественных чисел.

Система объектов хранится в массиве:

: Array - 1] of Массивы координат и цветов объектов при инициализации в начале работы приложения заполняются случайными числами. Воспроизведение массива геометрических объектов вынесено в отдельную процедуру по тем же при чинам, что и в предыдущем этой процедурой будем пользоваться в двух случаях: для собственно воспроизведения и для заполнения стека имен.

Во втором случае помещаемые в стек имена объектов совпадают с номером элемента в массиве:

If mode = then ;

// загрузка имени При нажатии кнопки мыши обращаемся к функции код которой ОТЛИЧаеТСЯ ОТ ТОЛЬКО ФУНКЦИИ при ее втором вызове. Полученное имя выбранного элемента передаем в процедуру, перекрашивающую объект заданного номера и перерисовываю щую экран. Поскольку все координаты случайны, мы убеждаемся, что дей ствительно происходит выбор объекта.

Замечание Очень важно подчеркнуть, что все, что воспроизводится между очередными вызовами LoadName, считается одноименным. Это очень удобно для выбора между комплексными геометрическими объектами, но отсутствие возможности явной командой прекратить именовать выводимые объекты требует продуман ного подхода к порядку вывода объектов: то, что не должно участвовать в вы боре элементов, необходимо выводить до первого вызова LoadName или не выводить вообще.

304 Графика в проектах Delphi Разберем еще один полезный пример по этой теме, проект из подкаталога ЕхО7. Здесь выводится поверхность, построенная на основе 229 патчей, образующих модель, предоставленную Геннадием Обуховым (вообще-то картинка немного жутковата, рис. 6.2).

6.2. Каждый патч поверхности можно перекрасить Модель выводится в красном цвете, при щелчке на любой точке модели со ответствующий патч перекрашивается в зеленый цвет.

Для хранения модели в этом примере используется не список, а динамиче ский массив. Формат файла, хранящего данные модели, здесь немного дру гой: первая строка содержит количество патчей в модели, далее каждое чис ло записывается с новой строки.

Помимо массива патчей введен массив цвета каждого патча:

type PPointArray // динамический массив модели TPointArray Array [0..0] of AVector;

ColorArray Array [0..2] of // массив цвета патча PColorArray = // указатель на массиз TColorArray = Array [0..0] of ColorArray;

// собственно массив При считывании модели создаем массив цвета патчей, массив цвета для каждого патча заполняем красным:

procedure var f :

i, j : Integer;

begin AssignFile ReSet (f);

Глава 6. Создаем свой редактор (f, // количество патчей в модели (Model, (numpoint + 1) * SizeOf (AVector));

// выделяем память // создаем динамический массив цвета GetMem (PatchColor, (numpoint + 1) * SizeOf (ColorArray));

For i := 0 to numpoint do begin For j := 0 to 15 do begin // считываем очередной патч модели ReadLn (f, Model [i][j].x);

// каждое число с новой строки ReadLn (f, Model [i][j].y);

ReadLn (f, Model end;

// массив цвета очередного PatchColor [i][0] := 1.0;

// красный PatchColor [i][1] 0.0;

PatchColor [i][2] end;

CloseFile (f);

end;

Вывод собственно модели вынесен в отдельную процедуру, при обращении к которой с аргументом каждый патч именуется, в качестве имени берется его порядковый номер:

procedure (Mode :

var i : Integer;

begin glScalef (2.5, 2.5, 2.5);

For i := 0 to numpoint do begin If mode GL_SELECT then (i) // именование воспроизводимого патча else // при выборе цвет безразличен // построение очередного патча 0, 1, 4, 4, 0, 1, 16, 4, 0, 4, 0, 4);

end;

glPopMatrix;

end;

Как я подчеркнул в комментарии, при обращении к этой процедуре с вос произведением в режиме выбора объектов можно не тратить время на уста новку текущего цвета. Для обычного режима воспроизведения перед собст венно воспроизведением очередного патча задаем текущий цвет, воспользо вавшись вызовом команды в векторной форме с аргументом — указателем на массив цвета.

OpenGL. Графика в проектах Delphi При нажатии кнопки мыши осуществляется выбор объекта под курсором:

hits := ;

И если номер объекта либо равен нулю, меняем цвет соответствую щего патча и перерисовываем экран:

PatchColor [hits] [0] := 0.0;

1-0;

PatchColor [hits][2] False);

Если же нажимать кнопку на пустом месте, то при движении курсора дель вращается, так что легко убедиться, что выбор осуществляется при лю бом положении точки зрения в пространстве.

Обратите внимание, что размер буфера выбора я задач сравнительно боль шим, 128. Если брать его, как в предыдущих примерах, равным то приложение работает устойчиво, но при выходе из появляется ние об ошибке, знакомое каждому программисту (рис.

S EXE Рис. 6.3. Малопонятный сбой в программе В примере по нажатию пробела визуализируются опорные точки по сценарию выбора среди них осуществляется:

If then begin glScalef (2.5, 2.5, 2.5) glDisable glBegin (GL POINTS);

For i 0 to do // цикл по For j 0 to 15 do // цикл по (model ]. x, model [i] [ j ]. y, ] " }.

// предпочтительнее в форме:

// ] ;

;

end;

Еще один пример на выбор объектов, проект из подкаталога ЕхО8 — здесь под курсором может оказаться несколько объектов 6.4).

Шесть кубиков по кругу пронумерованы от нуля до пяти, некоторые из них перекрывают друг друга в плоскости зрения. При нажатии кнопки мыши Глава 6. Создаем свой редактор с правой стороны экрана в компоненте класса выводится информа ция, сколько кубиков располагается под курсором, и последовательно выво дятся их имена в порядке удаления от глаза наблюдателя.

Процедура выбора в этом примере отличается тем, что возвращает не номер верхнего элемента, а количество объектов под курсором:

Result Имена объектов располагаются в буфере выбора через четыре, начиная с третьего элемента, поэтому для анализа содержимого буфера остается только последовательно считывать эти элементы:

procedure TObject;

Shift: X, Y: Integer);

var hit, begin hits := DoSelect (X, Y);

// объектов под курсором Lines (Format под курсором :, [hits] ) ) ;

// считываем имена — каждый четвертый элемент массива, начиная с 3-го For hit := 1 to hits do Объект + + Имя: + [ (hit - 1 ) * 4 + 3]));

end;

Замечание Соседние элементы массива, напоминаю, содержат значения буфера глубины отдельно для каждого объекта, но эти величины редко используются, ведь по рядок перечисления объектов и так предоставляет полную информацию о рас положении объектов.

6.4. Все объекты, располагающиеся под курсором, доступны для выбора, в том числе и закрытые другими объектами Графика в проектах Delphi Этот пример полезен для решения задач по обработке серии элементов.

Проект из подкаталога ЕхО9 представляет собой модификацию примера с перекрашиванием треугольников: количество объектов увеличено в десять раз, чтобы было больше перекрывающихся элементов. При нажатии кнопки мыши перекрашиваются все треугольники под курсором. Размер буфера бора потребовалось а функцию выбора переписать в процедуру, заканчивающуюся циклом по именам всех треугольников под курсором, где эти объекты перекрашиваются:

For hit 1 to do - 1) * 4 + // перекрашиваем объект Вывод текста Первое применение библиотеки OpenGL, которое я обнаружил на своем компьютере и с которого собственно и началось мое знакомство с ней — это экранная заставка "Объемный текст", поставляемая в составе онной системы в наборе "Заставки OpenGL". Думаю, вам знакома эта за ставка, выводящая заданный текст (по умолчанию — "OpenGL") или теку щее время красивыми объемными буквами, шрифт которых можно менять.

Поняв, что это не мультфильм, а результат работы программы, я загорелся желанием научиться делать что-нибудь подобное, после чего и началось мое увлекательное путешествие в мир OpenGL.

Выводить текст средствами OpenGL совсем несложно. Библиотека имеет готовую команду, строящую набор дисплейных списков для символов за данного шрифта типа TrueType — команду После товки списков при выводе остается только указать, какие списки (символы) нам необходимы.

Посмотрим проект из подкаталога простейший пример на вывод текста (рис. 6.5).

Замечание Обратите внимание, что при описании формата пикселов я явно задаю значе ние поля cDepthBits, иначе буквы покрываются ненужными точками.

При начале работы приложения вызывается команда, подготавливающая списки для каждого символа текущего шрифта формы:

255, 0.15, FONT POLYGONS, nil);

Замечание В этом примере для получения контекста воспроизведения обязательно нужно использовать самостоятельно полученную ссылку на контекст устройства. Если Глава 6. Создаем свой редактор вместо DC использовать вывод может получиться неустой чивым: при одном запуске приложения окно черное, а при следующем — все в порядке.

6.5.

в OpenGL совсем несложно Цвет шрифта, установленного в окне, при выводе текста не учитывается, в этом отношении выводимые символы ничем не отличаются от прочих геометрических объектов. Свойства материала и источника света необходи мо задавать самостоятельно.

Возможно, кому-то из читателей потребуется использовать вывод текста в приложениях, написанных без использования VCL. В примере из подката лога делается то же, что и в предыдущем, но шрифт отличается. Ну и, конечно, вырос размер кода:

hFontNew, hOldFont // подготовка вывода текста SizeOf(lf), 0] -28;

CLIP_DEFAULT_PRECIS;

FF DONTCARE OR DEFAULT PITCH;

hFontNew := hOldFont := Графика в проектах Delphi 0, 255, GLF_START_LIST, 0.0, ni l ) ;

Рассмотрим команду Первый параметр — ссылка на контекст устройства, в котором должен быть установлен соответствующий шрифт. Второй и третий параметры задают интервал кодов символов, для которых будут строиться списки. Четвертый параметр задает базовое значе ние для идентификации списков — для каждого символа создается отдель ный список, нумеруются они по порядку, начиная с задаваемого числа. Пя тый параметр, называемый "отклонение", задает точность воспроизведения символов;

чем меньше это число, тем аккуратнее получаются символы, за счет ресурсов, конечно. Шестой параметр, выдавливание, задает глубину получаемых символов в пространстве. Седьмой параметр определяет формат построения, линиями или многоугольниками. Последний, восьмой, па раметр — указатель на массив специального типа ИЛИ NULL, если эти величины не используются (в Delphi здесь необходимо зада вать nil).

Думаю, вы заметили, что операция построения 256 списков сравнительно длительная, после запуска приложения на это тратится несколько секунд.

Для собственно вывода текста я прибегнул к небольшой уловке, написав следующую, хоть и небольшую, но отдельную, процедуру:

procedure OutText (Litera :

begin //' смещение для имен списков // вызов списка для каждого символа Litera);

end;

Здесь скрыто использование преобразования типа выводимого символа в PChar, и вызов процедуры, например, ('Проба'), выглядит привыч ным образом.

Вывод текста состоит из двух действий — команда задает базовое смещение для вызываемых списков, а команда вызывает на вы полнение списки, соответствующие выводимому тексту.

Замечание Смещение имен списков в общем случае использовать не обязательно, обыч но это делается для того, чтобы отделить собственные списки программы от вспомогательных списков для символов. Второй аргумент команды указатель на список имен дисплейных списков;

если аргумент имеет тип то мы передаем этим аргументом список кодов нужных сим волов выводимой строки.

Глава 6, Создаем свой редактор Используемые для вывода символов списки должны по окончании работы приложения удаляться точно так же, как и прочие дисплейные списки:

glDeleteLists 256) Как я уже отмечал, подготовка списков для всех 256 символов — процесс сравнительно длительный, и очень желательно сократить время его выполне ния. Для этого можно брать не все символы таблицы, а ограничиться только некоторыми пределами. Например, если будут выводиться только заглавные буквы латинского алфавита, третий параметр команды достаточно взять равным 91, чтобы захватить действительно используемые А теперь посмотрим проект из подкаталога Ех12, пример на анимацию:

текст крутится в пространстве, меняя цвет изменяются свойства материа ла. На символы текста накладывается одномерная текстура.

Замечание В примерах этого раздела на сцене присутствуют только символы текста. При их выводе текущие настройки сцены сбиваются. Начинающие очень часто, на тыкаясь на эту проблему, оказываются всерьез озадаченными. Необходимо перед выводом символов запоминать текущие настройки, вызывая команду с аргументом а после вывода символов вызывать Рассмотрим другой режим вывода текста, основанный на использовании команды Такой способ, пожалуй, редко будет вами приме няться, поскольку с успехом может быть заменен на использование текстур.

Посмотрите пример из подкаталога Ех13, отличающийся от первого приме ра на вывод текста только тем, что команда заменена на wgiuseFontBitmaps. Символы в этом случае выводятся аналогично обыкно венному выводу Windows, то есть текст выглядит просто как обычная метка.

Как сказано в справке по команде wgiuseFontBitmaps, ею удобно пользовать ся, когда вывод средствами GDI в контексте воспроизведения невозможен.

Обратите внимание, что, хотя все связанные с пространственными преобра зованиями команды присутствуют в тексте программы, вывод выглядит пло ским, а перед выводом директивно задается опорная точка для вывода текста:

;

Как следует из документации, для вывода символов, подготовленных коман дой wgiuseFontBitmaps, ВЫЗЫВаеТСЯ Подобный вывод текста предлагается использовать для подрисуночных подпи сей, что и проиллюстрировано примером из подкаталога Ех14 (рис. 6.6).

Разберем подробнее команду Начнем с самого простейшего при мера, проекта из подкаталога Ех15. Массив rasters содержит образ буквы Графика в проектах Delphi При воспроизведении задается позиция вывода растра и три раза вызывает ся (20.5, 20.5);

glBitmap 12, 0.0, 0.0, 12.0, 0.0, ;

При каждом вызове glBitmap текущая позиция вывода растра смешается, поэтому на экране выводимые буквы не слипаются и не накладываются (рис. 6.7).

В этом примере для наглядности растр выводится желтым.

Рис. 6.7. Пример на использование команды glBitmap 6.6. Без подписи и не догадаешься, что изображено Замечание Обратите внимание, что вызов команды glRasterPos не только задает пози цию вывода растра, но и позволяет использовать цвет для его окрашивания.

Без вызова этой команды текущий цвет на выводимый растр не распро страняется, он будет выводиться белым.

Следующий пример, проект из подкаталога Ех16, позволяет понять, каким обраЗОМ ВЫВОДЯТСЯ СИМВОЛЫ, КОМаНДОЙ wglUseFontBitmaps.

Массив rasters представляет собой битовый образ 95 символов, коды кото рых располагаются в таблице с 32 по 127 позицию. В примере вручную сде лано то, что получается при вызове команды wglUseFontBitmaps. В начале работы приложения вызывается процедура, подготавливающая дисплейные списки, по одному списку для каждого символа:

procedure i :

Глава 6. Создаем свой редактор begin 1);

fontoffset glGenLists (128);

// стартовое смещение имен списков For := 32 to 127 do begin fontoffset, // список очередного символа 13, 0.0, 2.0, 10.0, 0.0, [i ) end;

end;

Каждый список состоит из одного действия, вывода растра, соответствую procedure : String);

begin BYTE, glPopAttrib;

end;

Проект из Ех17 содержит пример вывода монохромного настоя считанного из с использованием команды (рис 6.8. В программе из bmp-файла монохромный растр Растр с помощью самостоятельно написанной функции указатель ссылку на считанные данные Здесь не удастся применить стандартные классы Delphi, иначе растр ванную нами для чтения файлов при подготовке текстуры, в отличиях мо жете разобраться самостоятельно.

Собственно вывод содержимого монохромного растра прост:

0, 0, 0, 0, PText);

Графика в проектах Delphi Ненулевые параметры здесь размеры растра и ссылка на него.

Следующий пример, продолжающий тему, — проект из подкаталога Ех18, результат работы которого представлен на рис. 6.9.

6.9. Выводимые символы корректно располагаются в пространстве Здесь текст подготавливается и выводится аналогично предыдущему приме ру, однако символы рисуются в пространстве и в цвете. Для этого устанав ливается нужный цвет, и точка воспроизведения пикселов задается с по мощью фуНКЦИИ glRasterPos3f gl Coi or3f {1.0, 1.0, 0. 0);

// текущий цвет — желтый (-0.4, 0.9, -2. 0) ;

// позиция воспроизведения пикселов 0, 0, 0, 0, PText);

// вывод растра Выводимый текст действительно располагается в пространстве, в чем легко убедиться, меняя размеры окна — треугольники корректно располагаются в объеме относительно выводимого текста.

Изменяя размеры окна, обратите внимание: надпись выводится или вся це ликом, либо не выводится совсем, если хотя бы один ее пиксел не помеща ется на экране.

Завершая данный раздел, надо обязательно назвать еще один способ вывода текста, самый простой: вручную расписать по примитивам списки, соответ ствующие символам алфавита. Так это сделано в проекте из подкаталога Связь экранных координат с пространственными При создании приложений типа редакторов и модельеров проблема связи оконных координат с пространственными становится весьма важной. Не достаточно выбрать объект или элемент на экране, необходимо соотнести перемещения указателя мыши с перемещением объекта в пространстве или изменением его размеров.

Глава 6. Создаем свой редактор Один из часто задаваемых вопросов звучит так: "Какой точке в пространстве соответствует точка на экране с координатами, например, 100 и 50?".

Ответить на такой вопрос однозначно невозможно, ведь если на экране присутствует проекция области пространства, то под курсором в любой точ ке окна находится проекция бесконечного числа точек пространства. Одна ко ответ станет более определенным, если имеется в виду, что под курсором не пусто, есть объект. В этом случае, конечно, содержимому соответствую щего пиксела соответствует лишь одна точка в пространстве.

Для решения несложных задач по переводу координат можно воспользо ваться готовой командой библиотеки переводящей окон ные координаты в пространственные координаты. Пример из подкаталога Ех20 поможет нам разобраться с этой командой. В нем рисуется куб, при щелчке кнопки выводится информация о соответствующих мировых коор динатах (рис. 6.10).

6.10. Для простейших задач перевода координат может использоваться gi uUnProj ect Обработка щелчка выглядит следующим образом:

procedure TObject;

Button:

Shift: TShiftState;

X, Y: Integer);

var Viewport : Array [0..3] of // область вывода // матрица модели : Array of GLDouble;

// матрица проекций : // OpenGL у - координата : // возвращаемые мировые x, у, z координаты : // оконная z — координата // матрица области вывода // заполняем массивы матриц (GL PROJECTION MATRIX, Графика в проектах Delphi // [3] — высота окна в пикселах, соответствует Height.

RealY - Y - 1;

Caption := 'Координаты курсора ' + IntToStr + ' ' + FloatToStr RealY, 1, 1, giuUnProject (X, RealY, wx, ('Мировые координаты для + + : + (13) + + + ';

' + + + + end;

Команда giuUnProject требует задания трех оконных координат — X, Y, Z.

Третья координата здесь значение буфера глубины соответствующего пиксела, для получения которого пользуемся командой glReadPixels, указав в качестве аргументов координаты пиксела и задав размер области Обратите внимание, что при нажатии кнопки на пустом месте значение бу фера глубины максимально и равно единице, для точек, наименее удален ных от точки зрения, значение буфера глубины минимальное.

Команда giuUnProject имеет парную команду — переводящую координаты объекта в оконные координаты. Для ознакомления с этой командой предназначен проект из подкаталога Ех21. Действие приложения заключается в том, что в пространстве по кругу перемещается точка, а ее оконные координаты непрерывно выводятся в компоненте класса в правой части экрана (рис. 6.11).

Для проверки достоверности результатов в заголовке окна выводятся коор динаты курсора.

у = г Команда позволяет узнать, в какой точке экрана осуществляется воспроизведение Глава 6. Создаем свой редактор Программа важная, поэтому разберем ее поподробнее. С течением времени изменяется значение угла поворота по оси X, увеличивается значение пере менной Angle. При перерисовке окна происходит поворот системы коорди нат на этот угол и воспроизведение точки с координатами 0, —0.5):

glRotatef (angle, 0, // поворот системы координат glColor3f (1, 1, 0) ;

// текущий цвет glBegin // воспроизведение точки в пространстве (0, 0, -1) ;

glVertex3f 0, Print;

// обращение к процедуре вывода оконных координат Процедура вывода оконных координат выглядит так:

procedure Viewport : Array [0..3] of GLint;

: Array of GLdouble;

wx, wy, : GLdouble;

// оконные координаты begin // заполнение массивов матриц glGetDoublev ;

glGetDoublev @ProjMatrix) ;

// перевод координат объекта в оконные координаты gluProject (0, 0, —0.5, wx, wy, wz);

// собственно вывод полученных оконных координат координаты:');

x = + FloatToStr (wx));

у + FloatToStr - wy));

{' z = ' + FloatToStr end;

Первые три аргумента команды gluProject — мировые координаты точки, следующие три аргумента — массивы с характеристиками области вывода и матриц, последние три аргумента — возвращаемые оконные координаты.

что по оси Y возвращаемую координату требуется преобразовать к обычной оконной системе координат, здесь я вывожу значение выражения (ClientHeight - wy). Следя указателем курсора за точкой, легко убедиться в полном соответствии результатов.

OpenGL. Графика в проектах Delphi Режим обратной связи Библиотека OpenGL предоставляет еще один механизм, облегчающий по строение ИНТеракТИВНЫХ — ВОСПрОИЗВедеНИЯ обратной связи. При этом режиме OpenGL перед воспроизведением каждой очередной вершины возвращает информацию о ее оконных координатах и цветовых характеристиках.

Обратимся к примеру, проекту из подкаталога Ех22, мгновенный снимок работы которого показан на рис.

В крутятся площадка и точка над ней, в компоненте класса выводится информация о каждой воспроизводимой вершине. Сразу же обращаем внимание, что говорится о воспроизведении двух многоуголь ников по трем вершинам и одной отдельной вершины — точки, или при митиву типа Многоугольники соответствуют воспроизводимому программе примитиву типа (В главе 2 мы говорили о том, что каждый многоугольник при построении разбивается на треугольники).

В программе введен тип для операций с массивом буфера обратной связи:

type TFBBuffer Array [0..1023] of GLFloat;

При начале работы приложения сообщаем системе OpenGL, что в качестве буфера обратной связи будет использоваться переменная fb описанного выше типа:

(fb), @fb};

Константа, стоящая на месте второго аргумента, задает, что для каждой вершины будет возвращаться информация о трех координатах и четырех цветовых составляющих. Полный список констант вы найдете в файле справки.

6.12. В режиме обратной связи библиотека OpenGL уведомляет о всех своих действиях Глава 6. Создаем свой редактор Собственно построение оформлено в виде отдельной процедуры, обращение к которой происходит с аргументом, принимающим значения GL_RENDER ИЛИ Если аргумент равен второму возможному значению, то перед воспроизведением каждого примитива в буфер обратной связи вызовом команды маркер:

procedure Render (mode:

begin If = then // помещаем маркер - glColor3f (1.0, 0.0, (0.0, 0.0, -1.0);

glBegin glVertex3f (-0.5, -0.5, 0.0);

glVertex3f (0.5, -0.5, 0.0);

glVertex3f (0.5, 0.5, 0.0);

(-0.5, 0.5, If mode GL_FEEDBACK then // помешаем маркер - glColor3f (1.0, 1.0, 0.0);

glBegin (0.0, -1.0);

(0.0, 0.0, -0.5);

end;

При перерисовке экрана процедура Render вызывается с аргументом для собственно воспроизведения. Затем режим воспроизведения задается режимом обратной связи, и снова происходит воспроизведение, но в установленном режиме оно не влияет на содержимое буфера кадра:

При последующем переключении в обычный режим воспроизведения коман да glRenderMode возвращает количество числовых значений, помещенных в буфере обратной связи. Как подчеркивается в файле справки, это не число вершин. Полученную величину передаем пользовательскую заполняющую n := If n > 0 then Процедура вывода содержимого буфера обратной связи выглядит так:

procedure n: Integer);

var i, vcount :

320 Графика в проектах Delphi token : Single;

vert : String;

begin очищаем содержимое Memo n;

While i <> 0 do begin // цикл анализа содержимого буфера token := b[n-i];

// тип последующих данных DEC(i);

If token then begin // маркер end else If token = then begin // полигон := // количество вершин полигона - vertices (XYZ For := 1 to vcount do begin // анализ вершин полигона vert := ' ';

// для типа возвращается чисел (XYZ and RGBA).

For j 0 to 6 do begin vert := vert + [b[n-i]j);

DEC(i) ;

end;

end;

end else If token then begin // точки - RGBA}:');

vert ';

For j := 0 to 6 do begin vert vert + [b[n-i]]);

DEC{i);

end;

end;

end;

end;

Из комментариев, надеюсь, становится ясно, как анализировать содержимое буфера обратной связи.

Для сокращения кода я реализовал анализ только для двух типов — точек и полигонов. В документации по команде вы найдете опи сание всех остальных типов, используемых в этом буфере.

Глава 6. Создаем свой редактор Чтобы легче было разбираться, я предусмотрел остановку движения объек тов по нажатию клавиши пробела и вывод координат курсора в заголовке окна. Обратите внимание на две вещи на то, что оконная координата вершин по оси Y выводится без и на то, что координаты по осям выводятся через пробел. Запятая здесь может сбить с толку, если в системе установлен именно такой разделитель дробной части.

Механизм обратной связи легко приспособить для выбора объектов.

необходимые оконные например координаты курсора, легко выяснить по меткам какие вершины лежат вблизи этой точки.

Подкрепим это утверждение примером. Проект из Ех23 пред ставляет собой модификацию примера на где рисовались треуголь ники в случайных точках экрана и со случайным цветом, при нажатии кнопки мыши треугольник под курсором перекрашивался. Сейчас при на жатии кнопки перекрашиваются все треугольники, находящиеся вблизи курсора. Массив буфера достаточно сотней элементов:

: Array При создании окна создаем буфер обратной сообщая что нам достаточно знать только положение вершины в окне:

(SizeOf 2D, ;

Процедура воспроизведения массива объектов предназначена для использо вания двух режимах: воспроизведения в буфер кадра и воспроизведения в режиме обратной при котором в буфер обратной связи помещаются маркеры:

: ;

/ / параметр — режим ;

i :

For := 0 to - "1 do // очередного имени — метка в буфере обратной связи if FEEDBACK then glPassThrough. ;

// для очередного POLYGON:;

треугольник gi j. ;

f v [ i j. ;

;

end;

При каждой перерисовке окна картинка воспроизводится дважды: первый раз в буфер кадра, второй раз — в буфер обратной связи:

OpenGL Графика в проектах Delphi // рисуем массив объектов без выбора // режим обратной связи Render (GL // воспроизведение в режиме обратной связи n := // передано чисел в буфер обратной связи выбора из первоначального проекта переписана в процедуру, пе рекрашивающую треугольники в районе точки, координаты которой пере даются при ее вызове. Теперь при щелчке кнопки мыши вызывается эта процедура, и окно перерисовывается:

procedure : GLint;

у :

var i, k : GLint;

token :

w, ny :

begin i : n;

While i <> 0 do begin // цикл анализа содержимого буфера token := // признак DEC(i) ;

If token = then begin // метка w [n-i]);

// запомнили номер треугольника DEC(i);

end else If token then begin vcount := // количество вершин полигона For k 1 to vcount do begin nx := round // оконная координата х вершины ;

ny windH - round // оконная координата у вершины DEC(i) ;

// одна из вершин треугольника находится вблизи курсора, // т. е. внутри круга радиусом If (nx + 30 > х) and (nx - 30 < x) and (ny + 30 > y) and (ny - 30 < y) then RecolorTri // перекрашиваем треугольник end;

end;

;

end;

Замечание Теперь мы все знаем о режиме обратной связи, использование которого позво ляет открыть многие секреты OpenGL и во многом облегчает отладку проектов.

Глава 6. Создаем свой редактор Использование этого механизма для выбора объектов отличает простота, од нако за эту простоту приходится расплачиваться потерей скорости, ведь в от личие от использования буфера выбора в этом случае перерисовывается весь кадр, а не небольшая область вокруг курсора.

Трансформация объектов В предыдущих разделах мы разобрали несколько способов выбора объектов и поговорили о соотношении экранных координат с пространственными координатами. Попробуем совместить полученные знания, чтобы интерак тивно трансформировать экранные объекты, как это делается в графических редакторах и модельерах. Проект из подкаталога Ех24 содержит пример про стейшего редактора, я его назвал редактор сетки. При запуске на экране по является двумерная сетка с выделенными опорными точками, имитирующая проекцию трехмерной поверхности (рис. 6.13).

Нажатием пробела можно управлять режима сглаживания. Самое ценное в этом примере — это возможность интерак тивно сетку. С помощью курсора любая опорная точка пере в пределах экрана, что позволяет получать разнообразные псевдо пространственные картинки (одна из них приведена на рис. 6.14).

При выводе контрольных точек в режиме выбора точки последовательно именуются:

For i 0 t o 3 do For j := 0 to 3 do begi n If = t hen * 4 j ) ;

// загрузка имени } // вершины массива опорных точек Рис. 6.13. Простейший интерактивный графи ческий редактор OpenGL. Графика в проектах Delphi Рис. 6.14. Картинки плоскостные, но выглядят как пространственные При шслчке кнопки находим номер опорной точки под курсором:

у ) ;

/ точка При выборе воспроизводятся только опорные точки, саму сетку воспроизво дить ист смысла. Перемещая курсор, вызываем команду для получения соответствующих пространственных координат:

>= / / координаты, соответствующие / положению курсора (x, — у, 0. 95, у, obj ;

// передвигаем точку div 4, mod 4, 0] := div selected Point mod 1 ] nil, False);

end Используемые массивы с характеристиками видовых матриц заполняются Обработке Этот пример может оказаться полезным для построения несложных редак торов. Положение точки в пространстве здесь находится независимо от текущих установок видовых параметров, опорные точ ки перемешаются за курсором. Хотя получаемые построения выглядят вполне "объемно", здесь мы имеем дело с двумерными изображениями. При в пространство, несмотря на легкость перевода экранных коорди нат в координаты модели, избежать неоднозначности определения положе ния точки в пространстве не удается. При изометрической проекции пых объектов нелегко понять замысел пользователя, перемещающего эле мент и пространстве. Многие редакторы и модельеры имеют интерфейс, Глава 6. Создаем свой редактор подобный интерфейсу рассмотренного примера, когда элементы перемеша ются в точности вслед за курсором, однако лично я часто становлюсь п ту пик, работая с такими приложениями. При проектировании нашего венного редактора мы предложим несколько иной подход, избавляющий от этой неопределенности.

Постановка задачи Сейчас мы полностью подготовлены тому, чтобы рассмотреть из подкаталога Ех25, представляющий собой пример графического редактора или построителя модельера. Практическая ценность полученной программы будет, возможно, небольшой, однако она вполне может стать шаблоном для создания более мощной системы. разработчики рабо тают над модулями ввода данных и визуализации для различных CAD систем, и создаваемый редактор, думаю, будет им очень полезен. Но глав ные цели, которые мы здесь преследуем, носят все же скорее чем практический характер.

Пространство модели представляет собой опорную площадку и оси нат (рис. 6.15).

Пространство модели нашего собственного модельера Оси координат красиво подписаны объемными буквами, а по трем плоско стям нанесена разметка, которую будем называть сеткой. Размер сетки огра 326 Графика в проектах Delphi ничивается длиной осевых линий. Площадка, как и все остальные элемен ты, строится только для удобства ориентирования в пространстве, объекты могут располагаться где угодно, без каких-либо ограничений.

В правой части экрана располагается панель, содержащая элементы управ ления: компоненты класса позволяющие устанавливать точку зре ния в любое место в пространстве, а также компонент того же класса, по зволяющий менять длину осевых линий.

Кроме того, на панели располагаются кнопки, отвечающие за чтение/запись проектируемой модели, а также кнопка "Освежить" — перерисовка экрана.

Внизу панели помещены несколько компонентов класса задаю щих режимы рисования: наличие осей, сетки, тумана и площадки.

Так, по нажатию на кнопки элемента с надписью "Расстояние" можно при ближать или удалять точку зрения к пространству модели, элементы "Сдвиг" позволяют передвигать точку зрения по соответствующей оси, а элементы "Угол" — поворачивать модель в пространстве относительно указанной оси.

Пара замечаний по поводу этих действий. Перспектива задается с помощью команды vRight, zNear, zFar);

При нажатии на кнопки элемента "Расстояние" (компонент назван изменяются значения параметров перспективы в зависимости от того, какая нажата кнопка, нижняя или верхняя:

If < Perspective then begin := + 0.025;

vRight := vRight - 0.025;

vTop := vTop - 0.025;

vBottom := vBottom + 0.025;

end else If > Perspective then begin vLeft := vLeft - 0.025;

vRight := vRight + 0.025;

vTop := vTop + 0.025;

vBottom vBottom - 0.025;

end;

Perspective : Переменная — вспомогательная и хранит значение свойства объекта.

После изменения установок проекции экран перерисовывается.

Здесь я неожиданно столкнулся с небольшой проблемой, связанной с тем, что стандартный компонент класса TCheckBox работает не совсем корректно.

Вы можете заметить, что первое нажатие на кнопку срабатывает так, как Глава 6. Создаем свой редактор будто была нажата кнопка с противоположным действием. Я потратил много времени на устранение этой ошибки, однако избавиться от нее так и не смог, по-видимому, ошибка кроется в самой системе. Ре шение я нашел в том, что самостоятельно описал все действия по обработке событий, связанных с компонентом: положения курсора в пределах компонента, т. е. на какой кнопке он находится, включение таймер, по тику которого производятся соответствующие действия, и выключение его, когда курсор уходит с компонента. Все эти действия я в элементах, связанных с поворотом и сдвигом пространства модели, и вы можете срав нить соответствующие фрагменты кода. программа громозд кой и менее читабельной, однако более простого решения проблемы найти не получилось.

Использование элементов управления для перемещения точки зрения на блюдателя является обычным для подобных приложений подходом, однако необходимо продублировать эти действия управлением с клавиатуры. По этому предусмотрена обработка нажатий клавиш 'X', 'Y' и 'Z' для поворотов пространства моделей по осям, а комбинация этих клавиш с аналогич на нажатию элементов сдвига по нужной оси. Если при этом удерживать еще и то соответствующие величины сдвига или поворота умень шаются. Также введена клавиша, по которой можно быстро переместиться в привычную точку зрения (я назвал ее изометрической).

Шаг изменения величин поворота и сдвига можно менять, для чего соответ ствующие элементы управления имеют всплывающие меню, при выборе пунктов которых появляются дочерние окна (рис. 6.16).

6.16. Пользователю привычнее работать с такими окнами, чем с клавишами клавиатуры 328 Графика в проектах Delphi Поведение дочерних окон в этой программе необходимо рассмотреть особо тщательно. Заметьте, что при потере активности дочернего окна оно закры чтобы не загромождать экран. Также для каждого дочернего окна перехватчики сообщений, связанных с перемещением окна.

При перемещении и изменении размера каждого дочернего окна содержи мое главного окна перерисовывается. Конечно, это приводит к потере ско рости обработки сообщения, зато главное окно не засоряется по ходу рабо покрываясь серыми дырами. Подобными мелочами не стоит пренебре гать, если мы хотим придать нашему приложению черты профессиональной работы.

Точку зрения наблюдателя можно переместить еще одним способом: просто щелкнуть на букве, именующей ось. В этом случае точка зрения займет та кое что выбранная буква повернется лицом к наблюдателю. Для выбора элементов в этом проекте я использовал механизм, основанный на применении буфера выбора. Если смотреть на площадку сверху, то при про хождении курсора над границей площадки он принимает вид двунаправлен ных стрелок, подсказывающих пользователю, что размеры площадки в этих направлениях можно менять. Если после этого удерживать кнопку мыши и перемешать курсор, площадка изменяется в размерах вслед за ним.

Разберем принципы трансформаций площадки, они лежат также основе перемещений и изменения размеров объектов модели.

При воспроизведении площадки я пользуюсь небольшой уловкой, чтобы выделить ее границы. По границе площадки рисуются отдельные линии, каждая из которых при выборе именуется уникально, что дает возможность определить, над какой стороной площадки производятся манипуляции.

Главное, на что надо обратить особое внимание — это процедура, перево дящая экранные координаты в мировые:

: var X, Y :

;

v :

/ ( zFar zNear ) ;

// := zFar '' / (zFar + zNear) // Width •/0 4 * / f zNear) ;

// 4 zFar / zNear) ;

// Heigth X + - xO;

/ (ClientWidth Panell ;

Y yO * - / • Перевод здесь условный, в результате него получаются только две простран ственные координаты из трех. Первые два аргумента процедуры — экранные координаты. Для перевода в пространственные координаты используется Глава 6. Создаем свой редактор что перспектива задается с помощью команды Координаты край них точек окна выражаются через координаты передаваемые экранные координаты приводятся к этому интервалу.

При изменении размеров площадки с помощью этой процедуры условные пространственные координаты для предыдущего и текущего по ложений курсора. Приращение этих координат дает величину, на которую пользователь сместился в пространстве. Но это условная величина, и при переводе в реальное пространство требуется ее корректировка (в ваемой программе при переводе она умножается на 5). В результате не по лучается, конечно, совершенно точного соответствия, но погрешность здесь вполне терпимая, и в принципе, не должен испытывать силь ных неудобств. Что касается изменения площадки, то ее длина умножается на 10, т. е. приращение удваивается, чтобы собственно коорди наты вершин смещались с множителем 5. При изменении размеров и поло жения объектов модели два этих множителя комбинируются, чтобы полу чить удовлетворительную чувствительность.

Если же требуется точное соответствие с курсора, можно опирать ся на значение вспомогательной переменной Perspective, косвенно связан ной с текущими видовыми параметрами.

При трансформациях объектов в изометрической проекции для устранения неопределенности с положением точки в пространстве приращение по каж дой экранной оси по отдельности переводится в пространственные коорди наты и трактуется в контексте объемных преобразований. То если пользователь передвигает курсор вверх, уменьшается координата Y если курсор идет вправо, увеличивается координату X. Объект "уплывает" из-под курсора, однако у наблюдателя не возникает вопросов по поводу третьей координаты. Если же удерживается клавиша , то изменение экранной координаты Y указателя берется для трансформации по оси Z ми ровой системы координат. Конечно, это не идеальный интерфейс, но я на хожу его вполне удовлетворительным. Иначе придется заставлять пользова теля работать только в плоскостных проекциях, наблюдая постоянно модель со стороны какой-либо из осей.

Для хранения данных об объекте модели введен тип:

record // тип объекта : (Cube, Sphere, Cylinder);

// координаты Б пространстве X, Y, z, L, W, H : GLDouble;

// длина, высота // углы поворота RotX, RotZ : GLDouble;

// цвет : Array GLFloat;

end;

В качестве примера взяты три базовые фигуры: параллелепипед, сфера и цилиндр. Этот список базовых фигур можно произвольно OpenGL Графика в проектах Delphi ственное, что необходимо при этом сделать- подготовить список для нового объекта.

хранится в массиве При воспроизведении системы трансформируем систему координат и вызы ваем соответствующий дисплейный список:

For i 1 to do begin AND DIFFUSE, x, objects objects[i] glRotatef 0.0);

glRotatef 0.0, 1.0, glRotatef 0.0, 1 0)' If mode then case objects of Cube Sphere : ;

Cylinder ;

end;

{case} If glPopMatrix;

end;

Рис. 6.17. Маркированный объект можно трансформировать Глава 6. Создаем свой редактор Один из объектов может быть помеченным, маркированным. Такой объект выделяется среди прочих тем, что объем, занимаемый им, размечен восемью маленькими кубиками, маркерами (рис. 6.17).

При прохождении курсора над маркерами он меняет вид, и при нажатии кнопки мыши можно визуально менять размеры объекта. Помеченный объ ект можно также перемещать указателем так, как мы обсудили выше. Эле менты управления панели при наличии маркированного объекта действуют только на него, т. е. нажатие на кнопку уменьшения угла по оси X приведет к повороту не всей модели, а только маркированного объекта. Для точного задания значений параметров маркированного объекта предусмотрен вывод по нажатию клавиши дочернего окна "Параметры объекта".

Структура программы Думаю, нет необходимости рассматривать подробно всю программу модель ера, я постарался сделать код читабельным, а ключевые моменты поясняют ся комментариями.

Однако несколько вещей требуют дополнительного рассмотрения.

Пользователь должен иметь возможность отмены ошибочных действий. Вес ти протокол всех манипуляций накладно, поэтому я ограничился только возможностью отмены одного последнего действия. Перед выполнением операции редактирования система объектов копируется во вспомогательный массив, а отмена последнего действия пользователя заключается в процеду ре обратного копирования.

Систему в любой момент можно записать в файл одного из двух типов.

Файлы первой группы (я их назвал "Файлы системы") имеют тип TGLObject, это собственный формат модельера. Файлы второй группы имеют расширение это текстовые файлы, представляющие собой готовые кус ки программы, пригодные для включения в шаблоны программ Delphi. По смотрите пример содержимого такого файла для единственного объекта:

glTranslatef ( 1.00, 3.00) ;

color 0.967;

color 0.873;

color [2] 0.533;

;

(DrawCube) В зависимости от расширения, выбранного пользователем при записи моде ли, вызываются разные процедуры, каждая из которых по-своему анализи рует массив объектов.

332 Графика в проектах Delphi Этими я попытался придать нашему модельеру больше прак тического смысла, теперь он может стать удобным инструментом, облег чающим кодирование систем из множества объектов.

Несколько советов Если потребность попрактиковаться в написании больших программ, но не имеете пока собственных то разобранная выше про грамма может стать хорошим полигоном для этих целей. Думаю, среди чита найдутся желающие разнить наш графический редактор. Для них я подготовил несколько замечаний и рекомендаций, касающихся возможных изменений и улучшений:

При компиляции в Delphi пятой появляется совершенно неожи данная ошибка с отображением осевых линий, длина которых после за пуска обнуляется.

Для подобных систем чтобы координатные оси раскраши вались различными цветами: ось X — красным, ось Y — зеленым, ось Z — синим. Понятно, что это облегчает ориентирование в пространстве.

Можно дополнить интерфейс возможностью навигации в пространстве с использованием мыши, если помеченных объектов.

Можно включить возможность изменения положения источника света.

Достаточно его визуализировать и перемещать по тем принципам, что и объекты модели.

• Объектам модели можно добавить свойство невидимости, чтобы на время скрывать некоторые их них. дабы не загромождать экран.

Необходимо добавить масштабирование всей модели, иначе для больших объектов изображение получается чересчур искаженным.

Я разделил запись параметров системы и саму модель по различным файлам. Некоторые такие как положение точки зрения и масштаб модели, удобнее записывать в файл системы.

Система хранится в массиве, следовательно, имеет ограничение по коли честву объектов, Использовать список для устранения этого ограничения.

Можно добавить возможность наложения текстуры на объекты. В этом случае нужно решить, записывать ли с моделью образы текстур объек тов или для экономии дискового пространства достаточно ограничиться записью имен файлов текстур.

Желательно реализовать стандартные операции по работе с буфером об мена Windows. Самое простое решение — эмуляция этих операций с пользованием еще одного массива, подобного массиву для отмены по следнего действия пользователя.

Глава 6. Создаем свой редактор Полезной будет возможность объединения нескольких объектов в набор.

Операции по перемещению, копированию и удалению распространить в этом случае на все объекты набора.

Конечно, тени, прозрачность и зеркальность объектов придадут моделье ру совершенно новый облик.

Необходима возможность записи модели в открытых форматах, таких как DXF, WRL, Также можно предусмотреть возможность встраи вания модулей других разработчиков для записи в любом формате.

Переход на использование патчей потребует структуры но я верю, что решение этой задачи вполне вам по силам.

Выполнить все предыдущие пункты и добавить анимацию объектов и под держку некоего внутреннего языка для написания (скриптов) — это единственное, что вам необходимо сделать для того, чтобы создать не победимого конкурента на рынке подобных систем и заработать все деньги мира. Если же вы предпочитаете работать над открытой и свободно распро страняемой системой, то свяжитесь со мной и включайтесь в работу.

Заключение Несмотря на сравнительно небольшой объем, эту книгу вполне можно счи тать полным руководством по использованию библиотеки В част ности, для режима RGBA не оставлено без внимания ни одной команды.

Поэтому я уверен, что даже опытные программисты, работающие с OpenGL, найдут здесь для себя много полезного. Однако главный замысел книги со стоял все же в том, чтобы предоставить начинающему пользователю инфор мацию OpenGL достаточную для того, чтобы легко и быстро научиться применять эту библиотеку в Delphi.

Мне, автору, трудно судить о том, удался ли мой замысел, поэтому я очень заинтересован том, чтобы узнать мнение читателей об этой книге.

После того как книга была написана, у меня родилась идея написать ее продолжение. Оно может касаться использования DirectX в или со держать расширенный набор примеров по созданию визуальных эффектов с помощью OpenGL. Либо это может быть подробное руководство по всем темам использования графики в Delphi. Возможно, читатели будут заинтере сованы в учебнике — готовящейся к выпуску среде программиро вания для Linux.

Вы можете высказать замечания и пожелания по адресу Вы также можете обращаться ко мне с вопросами по поводу использования OpenGL, я постараюсь обязательно помочь. Я отвечаю на все письма.

Создание книги — большой труд, который компенсируется за счет ее про дажи. Если вам понравилась эта книга, а приводимые в ней примеры оказа лись для вас полезными, пожалуйста, не распространяйте их в качестве сво бодных программ. Вы, конечно, можете использовать примеры в собственных целях, иначе какой же в них но при распространении ваших модулей оставляйте оригинальный копирайт. Так поступил и я с теми модулями, которые взял у других авторов для построения некоторых примеров — все первоначальные источники указаны в тексте книги и текстах модулей.

В заключение хочу выразить искреннюю благодарность фирме Microsoft за право использовать в книге содержимое файла справки opengl.hlp, Марку (Mark — за предоставленное им право использовать, кон вертировать и копировать исходные модули библиотеки glut и корпорации SGI за право использования исходных модулей программ.

ПРИЛОЖЕНИЕ OpenGL в Интернете Ниже приводится список сайтов, где можно получить актуальную цию по библиотеке OpenGL и связанным с ней темам.

С этого сайта необходимо начинать знакомство с библиотекой OpenGL.

Пример использования OpenGL в Delphi, из этого источника я взял мо дуль DGLUT.pas.

Редактор на основе компонента TOpenGL.

Автор — Enzo Заголовочные файлы gl.pas и glu.pas.

Автор — Alexander Staubo:

• Сайт Mike содержит Opener, программу просмотра (viewer) 3DS файлов, а также пакет GLScene.

http://www.delphi-jedi.org/DelphiGraphics/OpenGL/OpenGL.7Jp Альтернативный заголовочный файл opengl.pas. Автор — Mike Lischke.

336 OpenGL. Графика в проектах Delphi Сайт Nuydens, содержит пакет CgLib и массу примеров и докумен тации на его основе. Здесь можно подучить заголовочный файл для ис пользовании GLUT.

http://www.scitcchsoft.com программирования графики Личные Web-страницы использующих OpenGL проек тах Delphi.

Набор компонентов Visit.

Сайт "OpenGL в России".

Ссылки па сайты и российские конференции.

Курсы программирования для OpenGL.

На этом сайте вы можете получить альтернативную версию OpenGL.

Страница Геннадия модели для примеров этой http://delphi.vitpc.com Великолепный сайт "Королевство на котором, в частности, нахо дится и мой раздел с дополнительными примерами по ПРИЛОЖЕНИЕ Содержимое прилагаемой дискеты и требования к компьютеру На дискете находится самораспаковывающийся архив SAMPLES.EXE с при мерами к книге — исходными файлами проектов.

Установку примеров на компьютер можно провести двумя способами:

Запустить файл SAMPLES.EXE и в появившемся диалоговом окне задать путь к папке, в которую распаковать файлы примеров, и на жать кнопку "Extract".

Скопировать файл SAMPLES.EXE с дискеты в папку, в которую необ ходимо распаковать файлы примеров, запустить его и нажать кнопку "Extract".

После этого каждый пример распакуется в отдельный каталог. Примеры главы 1 находятся в каталоге Chapterl, главы 2 — Chapter2 и т. д. Каж дый отдельный пример пометен в подкаталог с совпадающим с его номером в главе, т. с. файлы примера 10 главы 4 находятся в каталоге Chapter4\Exl0.

Все примеры используют только стандартные модули и компоненты поэтому для компиляции любого проекта вам не потребуется устанавливать дополнительные средства.

Если говорить точно, то некоторые проекты все же содержат ссылки на вспомогательные модули, описывающие пользовательские процедуры, одна ко эти модули также есть на дискете.

Тексты программ, как правило, идут без комментариев, последние приведе ны в тексте книги.

В программах синтаксис третьей версии Delphi и не использу ются нововведения, внесенные в последующих версиях этого продукта. Объ яснение этому консерватизму приведено в главе 1 книги.

338 Графика в проектах Delphi Изначально проекты создавались в Delphi третьей версии, затем для тести рования я компилировал их в четвертой и пятой версиях. За исключением проекта графического редактора главы 6, примеры работают во всех слу чаях одинаково. Описание исключения приведено в той же главе 6.

Проекты используют модуль opengl.pas, входящий в стандартную Delphi, начиная с третьей версии.

Некоторые разработчики стремятся упростить работу с OpenGL путем ис пользования собственных компонентов или Это имеет массу плю сов, но и не меньшее количество минусов: скорость воспроизведения замет но падает, а привязанность к нестандартным подходам затрудняет изучение Если вы не можете откомпилировать какой-либо проект, то ско рее всего, является то, что вы установили в среду Delphi какой-то нестан дартный пакет или компонент. Иногда такие пакеты содержат собственный заголовочный файл с тем же именем opengl.pas. В этом случае вам необхо димо переустановить Delphi или удалить мешающий пакет. Другие причи ны, по которым вы не смогли бы использовать примеры этой книги, мне не известны.

Для экономии места я удалил dof-файлы, поэтому в некоторых проектах при компиляции среда Delphi выдает предупреждения и замечания — не обра щайте на них внимания.

Для работы откомпилированных приложений подходит любая версия 32-раз рядной операционной системы Windows, для Windows 95 потребуется са мостоятельно установить файлы opengI32.dll и glu32.dll.

Для сокращения кода используется стандартная палитра OpenGL, начиная с 16 бит на пиксел. При необходимости работы с палитрой в 256 цветов в каждый проект потребуется внести изменения, описанные в разделе "Вы вод на палитру в 256 цветов" главы 4.

Особых требований к аппаратной части не предъявляется, но, конечно, ско рость работы приложений сильно зависит от мощности компьютера.

Приложения не требуют наличия акселератора, и нет необходимости компилировать проекты, если поменялась графическая карта компьютера.

Откомпилированные приложения сначала на компьютере, не оснащенным акселератором, затем на компьютерах с картами Riva TNT (детонатор 3.68) и Intel 740. Работа большинства примеров во всех трех слу чаях отличается только качеством и скоростью воспроизведения, однако не которые примеры все же ведут себя в зависимости от карты по-разному.

При описании таких примеров я обращаю внимание читателя на возможные различия в работе приложения.

Список литературы 1. Тихомиров Ю. В. Программирование трехмерной графики в Visual C++. — СПб.: — Санкт-Петербург, 1998. — 256 с: ил.

2. Майкл Янг. Программирование графики в Windows 95: Векторная гра фика на языке С++/Пер. с англ. — М.: Восточная книжная компания, 1997. - 368 с: ил.

3. Шикин А. В., Боресков А. В. Компьютерная графика. Динамика, стические изображения. М.: ДИАЛОГ-МИФИ, 1998. — 288 с.

Предметный указатель в GL_ALL_ATTRIB_BITS 141, 200, GL_ALWAYS bmp GL_AMBIENT 166, GL_BLEND 202. 203. GL_CLIP_PLANE GL_COLOR_BUFFER_BiT GL_COLOR_MATER1AL 132, 169, D 17, Describe Pixel Format 174, DirectDraw GL_CW 174. Dispatch Message GL_DECAL 255. DLL 164, 165, 166.

12 205, FormatMessage GL_EDGE_FLAG_ARRAY_EXT 165, GL_EXP GL_EXP2 GL_EXT_vertex_array GL_EXTENSIONS GL_FALSE GetMessage GetRValue GL 62.

GL 3D COLOR Предметный указатель 64. GL_POS1TION GL_REPLACE GL_GREATR GL_GREEN GL_S GL_KEEP GL_LIGHT 169, GL_SPECULAR 164, GL_SPHERE_MAP GL_SRC_ALPHA 191. GL_STENCIL_TEST GL_LINE_STIPPLE GL_LINE_WIDTH_RANGE GL_LINEAR 252. GL_L1NES GEN T 251. GL_TEXTURE_MIN_FILTER 251, GL_TRIANGLE_FAN GL_MAP2_VERTEX_3 GL_TR1ANGLES 3i 134, Begin glBindTcxturc glBitMap 75, 202, 53, GLboolean 143.

GL POLYGON glClear 32. Предметный указатель glClearAccum glHint 205, glClearStencil GLint giColor3f glLight 200, 163, glColorPointer glLightModelfv glCopyPixels glCullFace 200, glLineStipple 258 143, Load Identity 53, 163, 252, 255, 70 glDrawArrays 70 129, 188, 274, glDrawArraysEXT 70 glMaplf 237, 238 glMap2f 73, 218 128, glEdgeFlag 73 glMaterialf glEnable 53, 110, 123, 129, glMaterialfv 166, 130, 134. 172, 175, 177. 101, 226. 231, 247, 249, 252, 273, 274 99. glEnableCIientState 124, glEndList glEvalCoord 188, 75, 318, glPixelZoom 50, Polygon Mode glPopAttrib glPopMatrix 84, 141. 200, 174, 84, 299, glGenLists 75. 236. 73, 84, 100, glReadPixels 76, 213, 218, 236, 237. 298, glGetError Предметный указатель 299. 299, 316, glRotatcf gluPwlCurve glScalef gluQuadricCallback glScissor 56, 215, 217, gluQuadricDrawStyle 62, 115.

glStencilFunc 194, 231, 238, glStencilOp 190, 231, gluTessBeginContour 146, gluTessBeginPolygon 146, glTexGenfv 145, 147, glTexGeni 252, GLUtesselator gluTessEndContour 146, glTexImage2D gluTessEndPolygon 146, glTexParameter 251, gluTessProperty 251, Vertex 146. glTexSublmage2D glTranslatef glutSolidCube gliitSolidDodecahedron glutSolidSphere glutSolidTeapot glutSoiidTorus giuBeginSurface 316, giVertex glVertexPointer 50.

H Handle 245, HGLRC hit records HWND 133, 1CD gluOrtho2D L Предметный указатель м SendMessage Format 51, О Error Code TBitmapFileHeadcr TColor PeekMessage TransIateMessage PFD DRAW TThread 34, PFD_NEED_PALETTE w WaitMessage PostMessage wglCreateContext Messages wglDeleteContext R 308, WM_ACT[VATEAPP Register-Class wParam RGBA Предметный указатель м Массивы вершин Матрица модели Матрица проекций Мини-драйвер Буфер глубины О В Оконная функция Вектор нормали ПО Орто проекция Вычислитель п Передний буфер кадра Графический акселератор Перспективная проекция Полный клиентский драйвер Д Дескриптор \ Сервер Синтаксис команд Событие Единичная матрица Сообщения Сплайн Ссылка на контекст воспроизведения Задний буфер кадра Ссылка на окно Запись нажатия Стек имен К Ф Класс окна 12, Формат пиксела Клиент Функция Контекст воспроизведения Книги издательства "БХВ-Петербург" в продаже:

Серия подлиннике" Андреев А. и др. Windows 2000 Professional. Русская версия 700 с.

Андреев А. и др. Microsoft Windows 2000 Server. Русская версия 960 с.

Андреев А. и др. Новые технологии Windows 2000 576 с.

Андреев А. и др. Microsoft Windows 2000 Server и Professional. Русские версии с.

Беленький Власенко С. Word 2000 992 с.

Браун М. HTML 3.2 (с компакт-диском) 1040 с.

Вебер Дж. Технология Java (с компакт-диском) с.

Власенко С. Microsoft Word 2002 992 с.

Гантер Д. Инеграция Windows NT и Unix (с компакт-диском) 464 с.

Гофман В. A. Delphi 6 с.

Долженков В. MS Excel 2000 1088 с.

Закер К. Компьютерные сети. Модернизация и поиск неисправностей 1008 с.

Колесниченко О., И. Аппаратные средства PC, 4-е издание 1024 с.

Матросов А. и др. HTML 4.0 672 с.

Мамаев Е. MS SQL Server 2000 1280 с.

Михеева В., Харитонова И. Microsoft Access 2000 1088 с.

Новиков Яценко A. Microsoft Office 2000 в целом 728 с.

Новиков Ф., Яценко A. Microsoft Office в целом 928 с.

Нортон П. Персональный компьютер;

аппаратно-программная организация. 848 с.

Книга Нортон П, Windows 98 с.

Ноутон П., Шилдт Г. Java 2 1072 с.

Персон P. Word Пилгрим А. Персональный компьютер: модернизация и ремонт. Книга 2 528 с.

КиркЧ. XML 736 с.

Пономаренко С. Macromedia FreeHand 9 432 с.

Пономаренко С. Adobe Illustrator 9.0 608 с.

Пономаренко С. CorelDRAW 9 576 с.

Пономаренко С. Adobe Photoshop 6.0 с.

Русеев С. WAP: технология и приложения 432 с.

Секунов Н. Обработка звука на PC (с дискетой) с.

Тайц А. М., Тайц A. A. CorelDRAW 10: все программы пакета с.

Тайц А. М., Тайц A. A. CorelDRAW 9: все программы пакета с.

Тайц А. М., Тайц A. A. Adobe InDesign 500 с.

Тайц А. М., Тайц A. A. PageMaker 6.5 832 с.

Тихомиров Ю. Microsoft SQL Server 7.0 720 с.

Э. и др. Active Server Pages (с компакт-диском) 672 с.

Усаров Г. Microsoft Outlook 2002 656 с.

Ханкт Ш. Эффекты CorelDRAW (с компакт-диском) 704 с.

CD-ROM с примерами к книгам серии "В подлиннике" Access 2000, Excel 2000, 2000, Office 2000 в целом Серия "Мастер" Microsoft Press. Электронная коммерция. 368 с.

(с компакт-диском) С. Dynamic HTML (с компакт-диском) 496 с.

Анин Б. Защита компьютерной информации 384 с.

Березин С. Факс-модемы: выбор, подключение, выход в Интернет 256 с.

Березин С. Факсимильная связь в Windows 250 с.

Бухвалов А. и др. Финансовые вычисления для профессионалов 320 с.

Борн Г. Реестр Windows 98 (с дискетой) 496 с.

Габбасов 2000 448 с.

Гарбар П. Novell 5.5: система электронной почты 480 с.

и коллективной работы Гарнаев A. Visual Basic 6.0: разработка приложений (с дискетой) 448 с.

Гарнаев A. Excel, VBA, Internet в экономике и финансах с.

Гарнаев A. Microsoft Excel 2000: разработка приложений 576 с.

Гордеев О. Программирование звука в Windows (с дискетой) 384 с.

Гофман В., Хомоненко А. Работа с базами данных в Delphi 656 с.

Дарахвелидзе П. и др. Программирование в 5 (с дискетой) 784 с.

Дронов В. JavaScript в Web-дизайне 880 с.

Дубина А. и др. MS Excel в электронике и электротехнике 304 с.

Дубина А. Машиностроительные расчеты в среде Excel 97/2000 (с дискетой) с.

Дунаев С. Технологии Интернет-программирования 480 с.

Зима В. и др. Безопасность глобальных сетевых технологий 320 с.

Киммел П. Borland. 976 с.

Кокорева О. Реестр Windows ME 448 с.

Кокорева О. Реестр Windows 2000 352 с.

А. в Web-дизайне 592 с.

Краснов М. DirectX. Графика в проектах Delphi (с компакт-диском) 416 с.

Краснов М. Open в проектах Delphi (с дискетой) 352 с.

А. Создание и обработка структур данных в примерах на JAVA 336 с.

Кулагин Б. 3ds max 4: от объекта до анимации 448 с.

Купенштейн В. MS Office и Project в управлении и делопроизводстве 400 с.

Куприянов М. и др. Коммуникационные контроллеры фирмы Motorola 560 с.

Лавров С. Программирование. Математические основы, средства, теория 304 с.

Лукацкий А. Обнаружение атак 624 с.

Матросов A. Maple 6. Решение задач высшей математики и механики 528 с.

Медведев Е. Трусова В. "Живая" музыка на PC (с дискетой) 720 с.

Мешков А., Тихомиров Visual C++ и MFC, 2-е издание (с дискетой) 1040 с.

Миронов Д. Создание Web-страниц в MS Office 2000 320 с.

Мещеряков Е., Хомоненко А. Публикация баз данных в Интернете 560 с.

Михеева В., Харитонова И. Microsoft Access 2000: разработка приложений 832 с.

Новиков Ф. и др. Microsoft Office 2000: разработка приложений 680 с.

Нортон П. Разработка приложений в Access 97 (с компакт-диском) 656 с.

Олифер В., Олифер Н. Новые технологии и оборудование IP-сетей 512 с.

Полещук Н. Visual LISP и секреты адаптации AutoCAD 576 с.

Понамарев В. и ActiveX в Delphi 320 с.

Пономаренко С. InDesign: дизайн и верстка 544 с.

Попов А. Командные файлы сценарии Windows Scripting Host 320 с.

Приписное Д. Моделирование в 3D Studio 3.0 (с компакт-диском) 352 с.

Роббинс Дж. Отладка приложений 512 с.

Рудометов В., Рудометов Е. PC: настройка, оптимизация и разгон, 336 с.

2-е издание Соколенко П. Програмирование SVGA-графики для IBM 432 с.

Тайц А. Каталог Photoshop Plug-Ins 464 с.

Тихомиров Ю. MS SQL Server 2000: разработка приложений с.

Тихомиров SQL Server 7.0: разработка приложений 370 с.

Тихомиров Ю. Программирование трехмерной графики Visual C++ 256 с.

(с дискетой) Трельсен Э. Модель библиотека ATL 3.0 (с дискетой) 928 с.

Федорчук А. Офис, графика, Web в Linux 416 с.

Чекмарев A. Windows 2000 Active Directory 400 с.

Чекмарев А. Средства проектирования на Java (с компакт-диском) 400 с.

Шапошников И. Интернет-программирование 224 с, Шапошников И. Справочник Web-мастера. XML 304 с.

Шапошников И. Web-сайт своими руками 224 с.

Шилдт Г. Теория и практика C++ 416 с.

Яцюк О., Романычева Э. Компьютерные технологии в дизайне. 432 с.

Эффективная реклама (с Ресурсы Microsoft Windows NT Server 4.0 752 с.

Сетевые средства Microsoft Windows NT Server 4.0 880 с.

Visual Basic 992 с CD-ROM к книгам "Ресурсы Windows NT Server 4" и "Сетевые средства Windows NT Server 4" CD-ROM с примерами к книгам серии "Мастер";

"Office 2000", "Excel 2000", "Access 2000". Разработка приложений Серия "Изучаем вместе с BHV" Березин С. Internet у вас дома, 2-е издание 752 с.

Тайц A. Adobe Photoshop 5.0 (с дискетой) 448 с.

Серия "Самоучитель" Ананьев А., Федоров А. Самоучитель Visual Basic 6.0 624 с.

Бекаревич Пушкина Н. Самоучитель Microsoft Access 2000 480 с.

Васильев В. Основы работы на ПК 448 с.

Гарнаев А. Самоучитель VBA с.

Дмитриева М. Самоучитель JavaScript 512 с.

В. Самоучитель Excel 2000 (с дискетой) 368 с.

К. Macromedia Flash 5 368 с.

Исагулиев К. Macromedia Dreamweaver 4 560 с.

Исагулиев К. Macromedia Dreamweaver 3 432 с.

(О. Практика программирования: Бейсик, Си, Паскаль (с дискетой) 480 с.

Кирьянов Д. Самоучитель 2001 544 с.

Котеров Д. Самоучитель 4 576 с.

Культин Н. Программирование на Object Pascal в Delphi 6 (с дискетой) 528 с.

Культин Н. Самоучитель. Программирование в Turbo Pascal 7.0 и Delphi, с.

издание (с дискетой) А. Самоучитель UML 304 с.

Матросов А., Чаунин М. Самоучитель 432 с.

Омельченко Л., Федоров А. Самоучитель Windows Millennium 464 с.

Омельченко Л., Федоров А. Самоучитель FrontPage 2000 512 с.

Омельченко Л. Самоучитель Visual FoxPro 6.0 512 с.

Омельченко Л., Федоров А. Самоучитель Windows 2000 Professional 528 с.

Омельченко Л., Федоров А. Самоучитель Microsoft FrontPage 2002 576 с.

Пекарев Л. Самоучитель 3D Studio 4.0 370 с.

Полещук Н. Самоучитель AutoCad 2000 и Visual LISP, 2-е издание 672 с.

Понамарев В. Самоучитель 416 с.

Н. Самоучитель Visual C++ 6 (с дискетой) 960 с.

Н. Самоучитель С# 576 с.

Сироткин С. Самоучитель WML и WMLScript 240 с.

Тайц А. М., Тайц А. А. Самоучитель Adobe Photoshop 6 (с дискетой) 608 с.

М., Тайц А. А. Самоучитель CorelDRAW 10 640 с.

Тихомиров Самоучитель MFC (с дискетой) 640 с.

Усаров Г. Самоучитель Microsoft Outlook 2000 336 с.

Хабибуллин И. Самоучитель Java 464 с.

Хомоненко А. Самоучитель Microsoft Word 2000 688 с.

Шапошников И. Интернет. Быстрый старт 272 с.

Шапошников И. Самоучитель HTML 4 288 с.

Шилдт Г. Самоучитель C++, 3-е издание (с дискетой) 512 с.

Серия "Одним взглядом" Серебрянский И. Novell NetWare 4.1 одним взглядом 160 с.

Серия "Компьютер и творчество" Деревских В. Музыка на PC своими руками 352 с.

Дунаев В. Сам себе Web-мастер 288 с.

Людиновсков С. Музыкальный видеоклип своими руками 320 с.

Петелин Р., Петелин Музыкальный компьютер. Секреты мастерства 608 с.

Петелин Р., Петелин Музыка на Cakewalk. "Примочки" и плагины 272 с.

Петелин Р., Петелин Ю. Аранжировка музыки на PC 272 с.

Петелин Р., Петелин Звуковая студия в PC 256 с.

Петелин Р., Петелин Ю. Персональный оркестр в PC 240 с.

Петелин Р., Петелин Музыка на Cakewalk Audio 9. Секреты 420 с.

мастерства книги Андрианов В. Автомобильные охранные системы 272 с.

Банков В. Интернет: поиск информации и продвижение сайтов 288 с.

Гурова А. Герои меча и магии 320 с.

Живайкин П. 600 звуковых и музыкальных программ 624 с.

Закарян И., Филатов И. Интернет как инструмент 256 с.

для финансовых инвестиций Коновалов Д. Знакомый английский 64 с.

Мамаев Е. MS SQL Server 7.0: проектирование и реализация баз данных 416 с.

Мамаев Е. Администрирование SQL Server 7.0 320 с.

Мещеряков М. Linux: инсталляция и основы работы (с компакт-диском) с.

Попов С. Видеосистема PC 400 с.

Соломенчук В. Интернет: поиск работы, учеба, гранты 288 с.

Соломенчук В. Как сделать карьеру с помощью Интернета с.

Успенский И. Интернет как инструмент маркетинга 256 с.

Шарыгин М. Сканеры и цифровые камеры с.

Серия "Техника в Вашем доме" Андрианов В. Средства мобильной связи 256 с.

Андрианов В. Сотовые, пейджинговые и спутниковые средств связи 400 с.

Пешков А. Современные фотоаппараты 224 с.

Левченко В. Спутниковое телевидение 288 с.

Пушков А. Домашний кинотеатр на ПК 256 с.

Скоробогатов Н. Современные стиральные машины и моющие средства, 240 с.

2-е издание Миклашевский Н. Чистая вода. Бытовые фильтры и системы очистки воды 238 с.

Серия "Учебное пособие" Бекаревич Ю. Access 2000 за 20 занятий 512 с.

Бенькович Е. Практическое моделирование динамических систем 464 с.

компакт-диском) Васильева В. Персональный компьютер. Быстрый старт 480 с.

Дорот В. Толковый словарь современной компьютерной лексики, 512 с.

2-е издание Культин Н. C/C++ в задачах и примерах 288 с.

Культин Н. Turbo Pascal в задачах и примерах 256 с.

Робачевский Г. Операционная система Unix 528 с.

Сафронов И. Бейсик в задачах и примерах 224 с.

Солонина А. др. Алгоритмы и процессоры цифровой обработки сигналов 464 с.

Солонина А. и др. Цифровые процессоры обработки сигналов фирмы с.

MOTOROLA Угрюмов Е. Цифровая схемотехника 528 с.

Шелест В. Программирование 592 с.

Книги издательства "БХВ-Петербург" можно приобрести:

Москва 1."Библио-Глобус" ул. Мясницкая, 6 928 "Дом книги" ул. Новый Арбат, 8 {095) 203 3. "Дом технической книги" Ленинский пр., 40 137 4."Кнорус" ул. Б. Переяславская, 46 280 Ленинский пр., 29 958 Ленинградский пр., 78 (095) 152 6."Мир" ул. Большая Полянка, 28 (095) 238 7. "Молодая Гвардия" Новоданиловская наб., 9 (095) 954 8."Ридас" ул. Тверская, 8 229 9.ТД "Москва" Санкт-Петербург (812)541 Магазин при издательстве ул. Бобруйская, 4, офис "БХВ-Петербург" 2. "Веком" пр. Славы, 15 (812) 109 3. "Волшебная формула" Наличная ул., 41 (812)350 пр. Большевиков, 19 (812)588 4."Гелиос" Невский пр., 20 "Дом военной книги" Невский пр., 28 (812)312 Загородный пр., 21 (812) 164 7. Книжный клуб "Снарк" П. С, Большой пр., 34 (812) 8. "Книжный мир на Петроградской" Владимирский пр., 15 (812)327 9. "Ланк-Маркет «Владимирский»" Бассейная ул., 41 10. "Ланк-Маркет «Московский»" 11. № 1 СПбГУ Университетская наб.

(Главное здание университета) (812)321 12. "Недра" Средний пр., (812) 273 13. "Подписные издания" Литейный пр., (812) 446 14. "Прометей" ул. Народная, 15. "Рена" Лесной пр., 65, корп. 16. "Родина" Ленинский пр., Кондратьевский пр., 33 17. "Терус" ул. Пушкинская, 2 (812) 164 18. "Техническая книга" Промышленная ул., 19. "Нарвский" Книжная ярмарка (812) 20. "Шанс на Садовой" ул. Садовая, (812)443 21. "Энергия" Московский пр., Города России 46 Архангельск "Техническая книга" ул. Воскресенская, (3852) 44 2. Барнаул "Русское слово" ул. Малахова, З.Брянск "Мысль" пр. Ленина, 4. Белгород Театральный (0722) 22 "Школьник" (0732) 55 5. Воронеж "Светлана" пр. Революции, (8172)72 6. Вологда ул. Мира, (8172)72 7. Вологда ул. Мира, (271) "Книги" ул. Советская, 4/ 59 Э.Екатеринбург ул. А. Валика, (3432) 53 "Книжный магазин № ул. Челюскинцев, (3412) 22 Ижевск "Техника" ул. Пушкинская, (3952) 24 Иркутск "Иркутск книга" ул. Лыткина, 75А 24 13. Калининград "ДОК" ул. Барнаульская, 57 Калуга "Кругозор" ул. Калинина, (3912) 27 15. Красноярск "Эрудит" ул. Ленина, 16. "Книги" ул. Тукая, (8152) 45 17. Мурманск ул. Егорова, (8312)44 18. Нижний ул. Советская, Новгород (8312) Нижний "Знание" пр. Ленина, Новгород (81622) 20. Новгород "Прометей" ул. Б. 21. Новомосковск "Книги" ул. Комсомольская, 36/ (3832) 69 22. Новосибирск ТОО "Эмбер" ул. Спартака, 23. Омск "Магазин № 12" пр. Маркса, 89 (3812) 40 (3422)48 24. Пермь "Знание" ул. Крупской, 25. Петрозаводск пр. Ленина, 16 26. Псков "Сказ" ул. Пушкина, (8632) 66 27. Ростов-на-Дону "Магазин 26" ул. Пушкинская, 123/ 66 28. Ростов-на-Дону "Магазин № 4" ул. Б. Садовая, 27 29. Севастополь ул. Коминтерна, 33 30. Тверь "Кириллица" ул. Советская, (3452) 22 31. Тюмень "Новинка" ул. Республики, (3472) 22 32. Уфа "Азия" ул. Гоголя, 33. Ярославль ул. Кирова, 18 (0852) 30 Книга-почтой Прием заказов:

Санкт-Петербург, а/я тел. факс (812) e-mail: trade@bhv.spb.su, В заявке разборчиво напишите Ваш полный адрес с индексом, телефон, укажи те автора книги, ее полное название и нужное количество экземпляров.

Pages:     | 1 |   ...   | 2 | 3 ||



© 2011 www.dissers.ru - «Бесплатная электронная библиотека»

Материалы этого сайта размещены для ознакомления, все права принадлежат их авторам.
Если Вы не согласны с тем, что Ваш материал размещён на этом сайте, пожалуйста, напишите нам, мы в течении 1-2 рабочих дней удалим его.