воскресенье, 4 августа 2013 г.

Lazarus World. Создание окна при помощи библиотеки GLUT. Куб на OpenGL


Внимание! Данный пример основан на следующих статьях и примерах из сети Интернет:

1) Статья с сайта LinuxFocus.org — Программирование GLUT: окна и анимация, автор Miguel Angel Sepulveda.
2) Пример куба с сайта с примерами по OpenGL.
3) И статья в wiki на сайте freepascal.org - OpenGL Tutorial

Ну и конечно же, для создания проекта использовалась среда Lazarus 1.0.8 и дистрибутив Fedora 19 Linux.


В данном посте, на примере, показывается использование OpenGL в Lazarus.

Для начала нам необходимо инициализировать OpenGL. Создадим новый проект Lazarus. Выбираем пункт меню File > New, откроется окно выбора нового шаблона. Нам нужен шаблон, который находится в разделе Project > Program и нажимаем кнопку Ok, чтобы подтвердить выбор (Смотрите рисунок 1).

Рисунок 1. Окно выбора нового шаблона проекта


Сохраним проект под именем ogl_p1.lpr. Выбираем пункт меню File > Save As и сохраняем в домашнюю директорию пользователя, в каталог по следующему пути ~/Projects/lazarus/ogl_p1/, где ~ (знак тильда) это домашний каталог пользователя.

Теперь в редакторе исходного кода убираем весь код кроме следующего:

program ogl_p1;

begin

end.

Добавим в наш исходный код секцию uses, в которой мы перечислим модули необходимые нам для работы с OpenGL. Первый модуль который мы должны добавить называется gl, это основной модуль OpenGL. Второй модуль называется glut, этот модуль позволяет создавать OpenGL окно. Таким образом, у нас вышла строчка:

uses gl, glut;

Ниже секции uses, определим переменные, константы и процедуры необходимые нам для создания проекта.

Секция var:

var
Cmd: array of PChar;
CmdCount: Integer;
ScreenWidth, ScreenHeight: Integer;

Здесь можно видеть переменную Cmd для хранения имен параметров командной строки, переменную CmdCount для хранения количества параметров командной строки, и две переменные ScreenWidth, ScreenHeight для хранения размеров экрана по ширине и высоте, соответственно.

Секция const:

const
AppWidth = 400;
AppHeight = 400;
Константы AppWidth и AppHeight содержат размер окна OpenGL.

Процедура DrawGLScene:

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

procedure DrawGLScene; cdecl;
begin
glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);

glBegin(GL_QUADS);
glNormal3f( 0.0, 0.0, 1.0);
glVertex3f( 0.5, 0.5, 0.5); glVertex3f(-0.5, 0.5, 0.5);
glVertex3f(-0.5,-0.5, 0.5); glVertex3f( 0.5,-0.5, 0.5);

glNormal3f( 0.0, 0.0,-1.0);
glVertex3f(-0.5,-0.5,-0.5); glVertex3f(-0.5, 0.5,-0.5);
glVertex3f( 0.5, 0.5,-0.5); glVertex3f( 0.5,-0.5,-0.5);

glNormal3f( 0.0, 1.0, 0.0);
glVertex3f( 0.5, 0.5, 0.5); glVertex3f( 0.5, 0.5,-0.5);
glVertex3f(-0.5, 0.5,-0.5); glVertex3f(-0.5, 0.5, 0.5);

glNormal3f( 0.0,-1.0, 0.0);
glVertex3f(-0.5,-0.5,-0.5); glVertex3f( 0.5,-0.5,-0.5);
glVertex3f( 0.5,-0.5, 0.5); glVertex3f(-0.5,-0.5, 0.5);

glNormal3f( 1.0, 0.0, 0.0);
glVertex3f( 0.5, 0.5, 0.5); glVertex3f( 0.5,-0.5, 0.5);
glVertex3f( 0.5,-0.5,-0.5); glVertex3f( 0.5, 0.5,-0.5);

glNormal3f(-1.0, 0.0, 0.0);
glVertex3f(-0.5,-0.5,-0.5); glVertex3f(-0.5,-0.5, 0.5);
glVertex3f(-0.5, 0.5, 0.5); glVertex3f(-0.5, 0.5,-0.5);
glEnd();

glutSwapBuffers;
end;

Процедура ReSizeGLScene:

Данная процедура вызывается каждый раз когда изменяются размеры окна. В данной процедуре мы перестраиваем сцену под измененный размер окна.

procedure ReSizeGLScene(Width, Height: Integer); cdecl;
begin
glViewport(0, 0, Width, Height);
end;

Процедура GLKeyboard:

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

procedure GLKeyboard(Key: Byte; X, Y: Longint); cdecl;
begin
if Key = 27 then
Halt(0);
end;

Процедура InitializeGL:
В данном проекте используется для начальной инициализации сцены OpenGL. В данном случае здесь устанавливается точка обзора сцены, подключается световой источник.

procedure InitializeGL;
begin
glMatrixMode(GL_PROJECTION);
glFrustum(-0.5, 0.5, -0.5, 0.5, 1.0, 3.0);

glMatrixMode(GL_MODELVIEW);
glTranslatef(0.0, 0.0, -2.0);

glRotatef(30.0, 1.0, 0.0, 0.0);
glRotatef(30.0, 0.0, 1.0, 0.0);

glEnable(GL_DEPTH_TEST);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
end;

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

Сначала мы присвоим переменной CmdCount значение 1, оно говорит о том что программа будет иметь один параметр командной строки. Далее мы устанавливаем длину массива Cmd на хранения одной строки SetLength(Cmd, CmdCount), это строка является параметром, который содержит имя программы. Заносим в массив Cmd единственный параметр имя программы Cmd[CmdCount-1] := Pchar(ParamStr(CmdCount-1)):

CmdCount := 1;
SetLength(Cmd, CmdCount);
Cmd[CmdCount-1] := PChar(ParamStr(CmdCount-1));

Проведем инициализацию GLUT.

glutInit(@CmdCount, @Cmd);

Выбор режима, двойной буфер, RGB палитра и буфер глубины

glutInitDisplayMode(GLUT_DOUBLE or GLUT_RGB or GLUT_DEPTH);

Задаем размер окна OpenGL и позицию окна на экране.
glutInitWindowSize(AppWidth, AppHeight);

ScreenWidth := glutGet(GLUT_SCREEN_WIDTH);
ScreenHeight := glutGet(GLUT_SCREEN_HEIGHT);

glutInitWindowPosition((ScreenWidth - AppWidth) div 2,
(ScreenHeight - AppHeight) div 2);

Создаем окно с заголовком ogl_p1:

glutCreateWindow('ogl_p1');

Инициализация сцены:

InitializeGL;

Регистрация вызываемых процедур:
glutDisplayFunc(@DrawGLScene);
glutReshapeFunc(@ReSizeGLScene);
glutKeyboardFunc(@GLKeyboard);

Запуск механизма обработки событий:
glutMainLoop;

На рисунке 2 показан результат работы программы.

Рисунок 2. Результат запуска приложения


Ниже показан весь код проекта:

program ogl_p1;

uses gl, glut;

var
  Cmd: array of PChar;
  CmdCount: Integer;
  ScreenWidth, ScreenHeight: Integer;

const
  AppWidth = 400;
  AppHeight = 400;

procedure DrawGLScene; cdecl;
begin
     glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);

     glBegin(GL_QUADS);
     glNormal3f( 0.0, 0.0, 1.0);
     glVertex3f( 0.5, 0.5, 0.5); glVertex3f(-0.5, 0.5, 0.5);
     glVertex3f(-0.5,-0.5, 0.5); glVertex3f( 0.5,-0.5, 0.5);

     glNormal3f( 0.0, 0.0,-1.0);
     glVertex3f(-0.5,-0.5,-0.5); glVertex3f(-0.5, 0.5,-0.5);
     glVertex3f( 0.5, 0.5,-0.5); glVertex3f( 0.5,-0.5,-0.5);

     glNormal3f( 0.0, 1.0, 0.0);
     glVertex3f( 0.5, 0.5, 0.5); glVertex3f( 0.5, 0.5,-0.5);
     glVertex3f(-0.5, 0.5,-0.5); glVertex3f(-0.5, 0.5, 0.5);

     glNormal3f( 0.0,-1.0, 0.0);
     glVertex3f(-0.5,-0.5,-0.5); glVertex3f( 0.5,-0.5,-0.5);
     glVertex3f( 0.5,-0.5, 0.5); glVertex3f(-0.5,-0.5, 0.5);

     glNormal3f( 1.0, 0.0, 0.0);
     glVertex3f( 0.5, 0.5, 0.5); glVertex3f( 0.5,-0.5, 0.5);
     glVertex3f( 0.5,-0.5,-0.5); glVertex3f( 0.5, 0.5,-0.5);

     glNormal3f(-1.0, 0.0, 0.0);
     glVertex3f(-0.5,-0.5,-0.5); glVertex3f(-0.5,-0.5, 0.5);
     glVertex3f(-0.5, 0.5, 0.5); glVertex3f(-0.5, 0.5,-0.5);
     glEnd();

     glutSwapBuffers;
end;

procedure ReSizeGLScene(Width, Height: Integer); cdecl;
begin
  glViewport(0, 0, Width, Height);
end;

procedure GLKeyboard(Key: Byte; X, Y: Longint); cdecl;
begin
  if Key = 27 then
    Halt(0);
end;

procedure InitializeGL;
begin
  glMatrixMode(GL_PROJECTION);
  glFrustum(-0.5, 0.5, -0.5, 0.5, 1.0, 3.0);

  glMatrixMode(GL_MODELVIEW);
  glTranslatef(0.0, 0.0, -2.0);

  glRotatef(30.0, 1.0, 0.0, 0.0);
  glRotatef(30.0, 0.0, 1.0, 0.0);

  glEnable(GL_DEPTH_TEST);
  glEnable(GL_LIGHTING);
  glEnable(GL_LIGHT0);
end;

begin

CmdCount := 1;
SetLength(Cmd, CmdCount);
Cmd[CmdCount-1] := PChar(ParamStr(CmdCount-1));

glutInit(@CmdCount, @Cmd); 
glutInitDisplayMode(GLUT_DOUBLE or GLUT_RGB or GLUT_DEPTH); 
 
glutInitWindowSize(AppWidth, AppHeight);

ScreenWidth := glutGet(GLUT_SCREEN_WIDTH);
ScreenHeight := glutGet(GLUT_SCREEN_HEIGHT);

glutInitWindowPosition((ScreenWidth - AppWidth) div 2,
   (ScreenHeight - AppHeight) div 2);

glutCreateWindow('ogl_p1');

InitializeGL;

glutDisplayFunc(@DrawGLScene);
glutReshapeFunc(@ReSizeGLScene);
glutKeyboardFunc(@GLKeyboard);

glutMainLoop;

end.



syntax highlighted by Code2HTML, v. 0.9.1

2 комментария:

  1. для инициации достаточно написать
    glutInit(@argc,argv); вместо glutInit(@CmdCount, @Cmd);
    поэтому первые три строки в теле программы
    (после Begin) не нужны

    ОтветитьУдалить
    Ответы
    1. Спасибо за комментарий. Да, действительно, можно обойтись одной строчкой инициализации библиотеки GLUT.

      Удалить