OpenGL для начинающих

11 Разное=========а. Получение текста последней ошибки OpenGL MessageBox(0, gluErrorString(glGetError), 'OpenGL error', MB_OK); б. Восстановление состояния режимаЛампа GL_LIGHT0 будет включена или выключена в зависимости от ее состояниемперед началом блока glPushAttrib(GL_LIGHT0); ... glEnable(GL_LIGH0); ... glPopAttrib(); 12 Вывод текста в OpenGL========================Код получен объединением кода Jan Horn, NeHe (уроки 13 и 14) и DRKB Работа с графикой и мультимедиа > DerectX, OpenGL > OpenGL: Каким обpазом выбиpать pазмеp шpифта.Итак, можем выводить текст как растровое изображение и как векторное (буквыэто 3D объекты). Идея такова, что для алфавита подготавливается список (см 09), а при вводе текст разбивается на буквы и потом последовательно длякаждой буквы печатаемой строки выполняется соответствующий набор команд из списка.Ниже код, который реализует как растровый, так и как векторный вывод.(необходимо лишь закоментировать указанные строки).

var
 CharList: GLuint; // Вот этот список
 gmf: array [0..255] of GLYPHMETRICSFLOAT; // массив требуется для векторного
...
{----------------------------------------------------------------}
{ Создание списка букв }
{----------------------------------------------------------------}
procedure glBuildFont;
var
 Font: hFont;
begin
 // Список для 256 букв алфавита
 CharList := glGenLists(256);
 // Создаем шрифт, подробнее см. SDK
 Font := CreateFont(-28, 0, 0, 0, FW_BOLD, 0, 0, 0, RUSSIAN_CHARSET,
  OUT_TT_PRECIS, CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY,
  FF_DONTCARE or DEFAULT_PITCH, 'Comic Sans MS');
 // Устанавливаем шрифт для DC
 SelectObject(DC, Font);
 // Создаем команды списка.
 // Выбираем один из двух вариантов
 // Если используем wglUseFontBitmaps то - это растровое изображение
 if not wglUseFontBitmaps(DC, 0, 256, CharList) then
или
 // Если используем wglUseFontOutlines то - это векторное изображение
 if not wglUseFontOutlines(DC, 0, 255, CharList, 0, 0.2, WGL_FONT_POLYGONS, @gmf) then

  MessageBox(0, 'Font not create', 'glBuildFont', MB_OK);
 // Удаляем шрифт, так как соответствующий список уже создан
 DeleteObject(Font);
end;
{----------------------------------------------------------------}
{ Вывод строки на экран }
{----------------------------------------------------------------}
procedure glPrint(X, Y: Integer; text: String);
begin
 // Расчитывается позиция на экране. Требуется только для растрового
 // вывода. То есть при векторном выводе X и Y gLPrint игнорируются,
 // поэтому перед выводом надо будет воспользоваться glTranslatef
 glRasterPos2i(X, Y);
 glPushAttrib(GL_LIST_BIT);
 // Указыывем, что первая буква алфавита рисуется 1-ым набором команд
 glListBase(1);
 // Выводим текст
 glCallLists(length(text), GL_UNSIGNED_BYTE, PChar(text));
 glPopAttrib();
end;
...
// Где-то перед использованием вывода текста, напр. в MyOpenGL.glInit
// после создания контеста воспроизведения RC
 glBuildFont;
...
// Когда работа с текстом будет уже не нужна, то очистим список
// Напр. в MyOpenGL.glKill перед освобождением RC
 glDeleteLists(CharList, 256);
Добавление теста на сцену немного различается. Далее добавляемый код впроцедуру построения сцены (напр. в MyOpenGL.glDraw).Для растрового текста
// Устанавливаем цвет букв
 glColor3f(1.0, 0.0, 1.0);
 // Добавляем текст на сцену
 glPrint(-150, 0, 'Даст ист фантастиш');
Вывод векторного шрифта несколько сложнее, поскольку команды списка создают 3D объекты с определенными размерами (все буквы маленького размераа типа 0.01) (для растровых шрифтов велична букв определяется только первым параметромфункции CreateFont в glBuildFont) и поэтому, если у матрица проекций работает не с такими размерами (у меня она работает с размерами как напр. 100), то надо увеличить текст glScale. Так же надо подобрать режимы, чтобы текст смотрелся по-настоящему 3D. // Подбираем нужный режим glEnable(GL_LIGHT0); // Включаем стандартную лампу glDisable(GL_LIGHT1); // Отключаем пользовательскую лампу glDisable(GL_NORMALIZE); // Отключаем режим нормалей glLoadIdentity; // Загружаем в GL_MODELVIEW единичную матрицу glTranslatef(-150, 0.0, 0.0); // Добавим перенос от центра glScale(100, 100, 1.0); // Растягиваем текст на 100 по ОХ и OY glRotate(45, 1.0, 1.0, 0.0); // Добавим поворот glColor(1.0, 0.0, 1.0); // Установим цвет букв glPrint(0, 0, 'Даст ист фантастиш'); // Добавим текст на сцену // Возвращаем все как было glDisable(GL_LIGHT0); // Выключаем стандартную лампу glEnable(GL_NORMALIZE); // Включаем режим нормалей glEnable(GL_LIGHT1); // Включаем пользовательскую лампу 13 Компонент для работы с OpenGL================================Напр. на http://glscene.org - GL_Scene - версии для Delphi5-7.Умеет много чего, в частности импорт 3DS файлов.14 Загрузка объектов под отрисовку из файла===========================================Почти всегда хочется, чтобы в функции создании сцены (у меня это MyOpenGL.glDraw)объекты под отрисовку загружались с файла. Обычно реализуют свой формат храненияфигур и функции для работы с ним. Я ленивый, потому предлагаю свой способ - хранить не объекты, а набор gl-комманд ему соответствующий, который будет загружаться в список. Например рассмотрим такой фаил. 2 glNewList glBegin 4 glVertex3f 0 0 0 glVertex3f 100,4 0 0 glVertex3f 50 100 0 glEnd glEndList glNewList glRotate 10 0 1 0 glEndList 2 - это то что в списке 2 набора команд. Соответвенно в самой программе этобудет использоваться так (на примере MyOpenGL)Примечания: 1. дробная часть указывается через запятую!2. Для glBegin значения констант смотреть в OpenGL.pas
uses MyGLU;
...
var
 List: GLuint;
 Count: Integer;
...
// Где-то до использования создания сцены, напр. в MyOpenGL.glInit
 Count := gluLoadList('1.gls', List); // моя функция загрузки скрипта из файла из MyGLU.pas
...
// Где-то в функции создания сцены, напр. в MyOpenGL.glDraw
 for i := 0 to Count - 1 do
 begin
  glCallList(List + i); // Вызываем i-ый набор команд; нумерация с нулевого
 end;
По-моему замечательная идея ;-) Возможно у нее уже есть реализация. А теперь черновой код MyGLU.pas (поддерживаются не все функции gl, да и контроль ошибокминимальный). Дописывать я его уже наверно не буду; если вам понравилась идея, тодоработать его думаю труда не составит - все прозрачно.
unit MyGLU;
interface
uses windows, OpenGL, SysUtils;
// Функция создает список, используя команды из текстового файла
// Возвращаемое значение - число элементов созданного списка
function gluLoadList(FileName: String; var List: GLuint): Integer;
implementation
var
 Param: array [1..10] of Extended;
// Получение из входной строки S подслов, которые конвертируется в Float
// и помещаются в соответствующий Param[i]. S начинает обрабатываться
// с S[Pos].
function GetParam(S: String; Pos: Integer): Integer;
var
 i, j: Integer;
 Value: String;
begin
 for i := 1 to 10 do Param[i] := 0;
 j := 1;
 Value := '';
 for i := Pos + 1 to Length(S) do
  if (S[i] = ' ') then
  begin
  Param[j] := StrToFloat(Value);
  if j = 10 then
  begin
  Result := 10;
  MessageBox(0, PChar('Too many params!'), 'GetParam', MB_OK);
  exit;
  end
  else j := j + 1;
  Value := '';
  end
  else Value := Value + S[i];
 if Value <> '' then Param[j] := StrToFloat(Value);
 Result := j;
end;
function gluLoadList(FileName: String; var List: GLuint): Integer;
var
 F: TextFile;
 S, Command: String;
 Count, CurrList, i: Integer;
 Obj: GLUquadricObj;
begin
 if not FileExists(FileName) then
  begin
  MessageBox(0, PChar('File '+FileName + ' not found'), 'glLoadList', MB_OK);
  end;
 AssignFile(F, FileName);
 Reset(F);
 readln(F, S);
 Count := StrToInt(S);
 CurrList := 0; // сдвиг; иначе номер набора команд.
 List := glGenLists(Count);
 Obj := gluNewQuadric;
  // читаем из файла, если видим знакомую команду, то выполняем
  while not EOF(F) do
  begin
  Command := '';
  readln(F, S);
  for i := 1 to Length(S) do
  if S[i] = ' ' then break
  else Command := Command + S[i];
  GetParam(S, i);
  Command := UpperCase(Command);
  if Command = 'GLNEWLIST' then
  glNewList(List + CurrList, GL_COMPILE);
  if Command = 'GLENDLIST' then
  begin
  glEndList;
  CurrList := CurrList + 1;
  end;
  if Command = 'GLBEGIN' then
  glBegin(round(Param[1]));
  if Command = 'GLEND' then
  glEnd;
  if Command = 'GLROTATE' then
  glRotate(Param[1], Param[2], Param[3], Param[4]);
  if Command = 'GLSCALE' then
  glScale(Param[1], Param[2], Param[3]);
  if Command = 'GLTRANSLATEF' then
  glTranslatef(Param[1], Param[2], Param[3]);

  if Command = 'GLVERTEX3F' then
  glVertex3f(Param[1], Param[2], Param[3]);
  if Command = 'GLCOLOR' then
  glColor(Param[1], Param[2], Param[3], Param[4]);
  if Command = 'GLLOADIDENTITY' then
  glLoadIdentity;
  if Command = 'GLPUSHMATRIX' then
  glPushMatrix;
  if Command = 'GLPOPMATRIX' then
  glPopMatrix;

  if Command = 'GLUSPHERE' then
  gluSphere(Obj, Param[1], round(Param[2]), round(Param[3]));
  if Command = 'GLUCYLINDER' then
  gluCylinder(Obj, Param[1], Param[2], Param[3], round(Param[4]), round(Param[5]));
  if Command = 'GLUDISK' then
  gluDisk(Obj, Param[1], Param[2], round(Param[3]), round(Param[4]));
  end;
 glEndList;
 gluDeleteQuadric(Obj);
 CloseFile(F);
 Result := Count;
end;
end.
15 Bmp - формат===============Вообщем то к OpenGL это никакого отношения не имеет, но загрузку текстур все-такизачастую приходится производить из него, так что полезно представлять что это такое.Описание самое простейшее, многое выкинуто, но для общего понимания и загрузкитекстур из bmp-файлов - этого будет достаточно.В начале каждого bmp-файла идет служебная информация - общая информация о файле TBitmapFileHeader и потом общая информация о bmp-изображении - TBitmapInfoHeader.Определения типов из windows.pas (комментарии мои)

Очень сильно помогло для вывода текста. Спасибо.

Отправить комментарий

Проверка
Антиспам проверка
Image CAPTCHA
...