суббота, 30 ноября 2013 г.

Lazarus World. Используем GLX расширение для связи OpenGL с X Window System


Для создания окна будем использовать библиотеку xlib. Запустите Lazarus и создайте новый проект, для этого выберите пункт меню File>New>Program и нажмите кнопку OK (Смотрите рисунок 1). Назовите его ogl_p3.lpr и сохраните проект в домашней директории пользователя /home/[имя пользователя]/Projects/lazarus/ogl_p3/.

Рисунок 1. Создание нового проекта

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

Если посмотреть в редактор кода среды Lazarus, то можно увидеть уже введенный стартовый код проекта. Удалим лишнее и оставим только то, что нам пригодится в дальнейшем:

program ogl_p3;
uses
begin
end.

Теперь в секции uses подключим необходимые модули:

1) для работы с функциями связывающие opengl с x window system (glx)
2) для работы с функциями создания окна x window system (x, xutil, xlib)
3) для работы с функциями OpenGL (gl, glu)

Таким образом секция uses у нас примит вид:

uses glx, x, xutil, xlib, gl, glu;

Выше секции uses укажите режим синтаксиса совместимый с delphi

{$MODE delphi}

После секции uses создадим секцию глобальных переменных var, в данной секции определим следующие переменные:

var
  dpy: PDisplay;
  visinfo: PXVisualInfo;
  Attr: Array[0..10] of integer =
   (GLX_DEPTH_SIZE, 16,
    GLX_RGBA,
    GLX_RED_SIZE, 1,
    GLX_GREEN_SIZE, 1,
    GLX_BLUE_SIZE, 1,
    GLX_DOUBLEBUFFER,
    none);
  cm: TColormap;
  winAttr: TXSetWindowAttributes;
  win :TWindow;
  glXCont: GLXContext;

1) Указатель на структуру Display с именем dpy, которая определена в xlib и содержит информацию о соединении с X-сервером.
2) Указатель на структуру XvisualInfo c именем visinfo, которая определена в xlib и содержит информацию о визуальных характеристиках поддерживаемых экраном X-сервера.
3) Attr, массив атрибутов визуальных характеристик, которые мы запрашиваем у X-сервера.
4) cm хранит информацию о новой цветовой палитре окна, тип Tcolormap.
5) Структура TXSetWindowAttributes с именем winAttr, хранит все необходимые атрибуты для создания нового окна.
6) Идентификатор, с именем win, созданного окна типа Twindow.
7) Переменная хранящая информацию о созданном контексте рендеринга OpenGL.

Для начала нам нужно определится, что мы будем рисовать с помощью функций OpenGL. В книге Эдварда Эйнджела «Интерактивная компьютерная графика. Вводный курс на базе OpenGL» 2-е издание 2001г. написан си код алгоритма построения треугольника Серпинского. Так что попробуем его нарисовать.

Далее определим новый тип:

type
  point2 = array[1..2] of GLfloat;

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

Далее определи секцию var, где определим одну точку (начальная точка, откуда идут все расчеты) и массив из трех точек (вершины большого треугольника):

var
  p: point2 = (0.0, 0.0);
  vertices: array[1..3] of point2 = 
     ((0.0, 0.0), (250.0, 500.0), (500.0, 0.0));

Ниже напишем код процедуры перерисовки окна:

procedure redraw();
var
  j,k: integer;
begin
  Randomize;

  glClear(GL_COLOR_BUFFER_BIT);

  for k:=1 to 250000 do
  begin
    j := Random(3) + 1;

    p[1] := (p[1] + vertices[j][1]) / 2;

    p[2] := (p[2] + vertices[j][2]) / 2;

    glBegin(GL_POINTS);
      glVertex2fv(@p);
    glEnd;
end;

    glXSwapBuffers(dpy, win);
end;

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


procedure initgl();
begin
  glClearColor(1.0, 1.0, 1.0, 0.0);
  glColor3f(1.0, 0.0, 0.0);

  glMatrixMode(GL_PROJECTION);

  glLoadIdentity();

  gluOrtho2D(0.0, 500.0, 0.0, 500.0);

  glMatrixMode(GL_MODELVIEW);

end;

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

procedure resize(width, height: integer);
begin
  glViewport(0, 0, width, height);
end;

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

procedure loop();
var
  event: TXEvent;
begin
  while true do
  begin
   XNextEvent(dpy, @event);
   case event._type of
    Expose: redraw();
    ConfigureNotify: resize(event.xconfigure.width,
      event.xconfigure.height);
    KeyPress: halt(1);
   end;
  end;
end;

в данном случае обрабатываются событие перерисовки окна (Expose), событие изменения размеров окна (ConfigureNotify), события нажатия клавиши (KeyPress).

Ниже определим секцию var, в которой определены переменные необходимые для последующего кода проекта в главных операторных скобках (begin ... end.)

var
  errorBase, eventBase: integer;
  title: String;
  window_title_property: TXTextProperty;

1) Переменные с именами errorBase и eventBase нужны для хранения кода ошибок возвращаемые процедурой glXQueryExtension.
2) Переменная строка с именем title для хранения названия заголовка окна
3) Переменная window_title_property необходима для установки имени приложения

Ниже напишем код главных операторных скобок:

begin
  initGlx();

  dpy := XOpenDisplay( nil );

  if (dpy = nil) then
  writeLn('Error: Could not connect to X server');

  if not (glXQueryExtension(dpy, errorBase, eventBase)) then
  writeLn('Error: GLX extension not supported');

  visinfo := glXChooseVisual(dpy, DefaultScreen(dpy), Attr);
  if (visinfo = nil) then
  writeLn('Error: Could not find visual');

  cm := XCreateColormap(dpy, RootWindow(dpy, visinfo.screen),
  visinfo.visual, AllocNone);

  winAttr.colormap := cm;
  winAttr.border_pixel := 0;
  winAttr.background_pixel := 0;
  winAttr.event_mask := ExposureMask or
      ButtonPressMask or
      StructureNotifyMask or
      KeyPressMask;

  win := XCreateWindow(dpy, RootWindow(dpy, visinfo.screen),
  0, 0, 500, 500, 0, visinfo.depth, InputOutput, visinfo.visual,
  CWBorderPixel or CWColormap or CWEventMask, @winAttr);

  title := 'ogl_p3';
  XStringListToTextProperty(@title, 1, @window_title_property);
  XSetWMName(dpy, win, @window_title_property);

  glXCont := glXCreateContext(dpy, visinfo, none, true);
  if (glXCont = nil) then
  writeLn('Error: Could not create an OpenGL rendering context');

  glXMakeCurrent(dpy, win, glXCont);

  XMapWindow(dpy, win);

  initgl();

  loop();

end.


1) Функция initGlx производит инициализацию расширения GLX.
2) Функция XopenDisplay устанавливает соединение клиента с X-сервером.
3) Функция glXQueryExtension запрашивает у X-сервера поддерживает ли он GLX расширения.
4) Функция glXChooseVisual запрашивает у X-сервера возможные визуальные характеристики экрана.
5) Функция XcreateColormap создает новую цветовую палитру для нового окна
6) Далее мы задаем необходимые атрибуты создаваемого окна:

winAttr.colormap := cm;
winAttr.border_pixel := 0;
winAttr.background_pixel := 0;
winAttr.event_mask := ExposureMask or
   ButtonPressMask or
   StructureNotifyMask or
   KeyPressMask;

7) Функция XcreateWindow создает новое окно согласно заданным атрибутам и полученным характеристикам.
8) Следующими строчками кода мы устанавливаем заголовок окна:


 title := 'ogl_p3';
 XStringListToTextProperty(@title, 1, @window_title_property);
 XSetWMName(dpy, win, @window_title_property);

9) Функция glXCreateContext создает контекст OpenGL
10) Функция glXMakeCurrent привязывает созданный контекст OpenGL к созданному окну.
11) Функция XmapWindow делает окно видимым
12) Перед тем как передать управление обработчику событий окна, необходимо выполнить процедуру initgl инициализации обзора сцены.
13) Запускаем бесконечный цикл обработки событий окна.

Теперь давайте соберем проект. Результат работы программы представлен рисунком 2.
  
Рисунок 2. Треугольник Серпинского

Код полностью:
program ogl_p3;

{$MODE delphi}

uses glx, x, xutil, xlib, gl, glu;

var
  dpy: PDisplay;
  visinfo: PXVisualInfo;
  Attr: Array[0..10] of integer =
    (GLX_DEPTH_SIZE, 16,
     GLX_RGBA,
     GLX_RED_SIZE, 1,
     GLX_GREEN_SIZE, 1,
     GLX_BLUE_SIZE, 1,
     GLX_DOUBLEBUFFER,
     none);
  cm: TColormap;
  winAttr: TXSetWindowAttributes;
  win :TWindow;
  glXCont: GLXContext;

type
   point2 = array[1..2] of GLfloat;
var
   p: point2 = (0.0, 0.0);
   vertices: array[1..3] of point2 =  
           ((0.0, 0.0), (250.0, 500.0), (500.0, 0.0));

procedure redraw();
var
   j,k: integer;
begin
  Randomize;

  glClear(GL_COLOR_BUFFER_BIT);

  for k:=1 to 250000 do
  begin
       j := Random(3) + 1;

       p[1] := (p[1] + vertices[j][1]) / 2;

       p[2] := (p[2] + vertices[j][2]) / 2;

       glBegin(GL_POINTS);
        glVertex2fv(@p);
       glEnd;
  end;

  glXSwapBuffers(dpy, win);
end;

procedure initgl();
begin
  glClearColor(1.0, 1.0, 1.0, 0.0);
  glColor3f(1.0, 0.0, 0.0);

  glMatrixMode(GL_PROJECTION);

  glLoadIdentity();

  gluOrtho2D(0.0, 500.0, 0.0, 500.0);

  glMatrixMode(GL_MODELVIEW);

end;

procedure resize(width, height: integer);
begin
  glViewport(0, 0, width, height);
end;

procedure loop();
var
  event: TXEvent;
begin
  while true do
  begin
    XNextEvent(dpy, @event);
    case event._type of
         Expose: redraw();
         ConfigureNotify: resize(event.xconfigure.width,
                          event.xconfigure.height);
         KeyPress: halt(1);
    end;
  end;
end;

var
  errorBase, eventBase: integer;
  title: String;
  window_title_property: TXTextProperty;
begin
  initGlx();

  dpy := XOpenDisplay( nil );

  if (dpy = nil) then
  writeLn('Error: Could not connect to X server');

  if not (glXQueryExtension(dpy, errorBase, eventBase)) then
  writeLn('Error: GLX extension not supported');

  visinfo := glXChooseVisual(dpy, DefaultScreen(dpy), Attr);
  if (visinfo = nil) then
  writeLn('Error: Could not find visual');

  cm := XCreateColormap(dpy, RootWindow(dpy, visinfo.screen),
  visinfo.visual, AllocNone);

     winAttr.colormap := cm;
     winAttr.border_pixel := 0;
     winAttr.background_pixel := 0;
     winAttr.event_mask := ExposureMask or
                           ButtonPressMask or
                           StructureNotifyMask or
                           KeyPressMask;

  win := XCreateWindow(dpy, RootWindow(dpy, visinfo.screen),
  0, 0, 500, 500, 0, visinfo.depth, InputOutput, visinfo.visual,
  CWBorderPixel or CWColormap or CWEventMask, @winAttr);

  title := 'ogl_p3';
  XStringListToTextProperty(@title, 1, @window_title_property);
  XSetWMName(dpy, win, @window_title_property);

  glXCont := glXCreateContext(dpy, visinfo, none, true);
  if (glXCont = nil) then
  writeLn('Error: Could not create an OpenGL rendering context');

  glXMakeCurrent(dpy, win, glXCont);

  XMapWindow(dpy, win);

  initgl();

  loop();

end.


syntax highlighted by Code2HTML, v. 0.9.1

четверг, 29 августа 2013 г.

Lazarus World. Используем компонент TOpenGLControl при работе с OpenGL


Для создания проекта используется Lazarus 1.0.8 и Fedora 19 Linux.

Компонент TOpenGLControl, по — умолчанию, не установлен в среде Lazarus, поэтому нам с вами предстоит установить данный компонент. Выберите пункт меню Package > Install / Uninstall Packages, откроется окно установки новых пакетов в среду Lazarus (Смотрите рисунок 1).

Рисунок 1. Установка нового пакета
  
В окне установки новых пакетов, в списке неустановленных пакетов, необходимо найти пакет с именем lazopenglcontext 0.0.1, выбрать его и нажать кнопку Install selection. После этого необходимо нажать кнопку Save and Rebuild IDE, для пересборки Lazarus уже с компонентом TOpenGLControl. В окне подтверждения установки нового пакета, нажмите кнопку Continue.
Теперь, если посмотреть на ленту компонентов, то вы увидите новую секцию OpenGL c TOpenGLControl компонентом на ней.

Теперь создадим новый проект. Для это выберите пункт меню File > New, в окне создания нового проекта выберите раздел Project >Application и нажмите кнопку Ok. Сохраните проект в каталог /home/[имя пользователя]/Projects/lazarus/ogl_p2 и присвойте имя проекту ogl_p2.lpi, а модулю формы ogl_p2_unit1.pas, для этого выберите пункт меню File > Save As.

В инспекторе объектов нам необходимо присвоить имя форме, в поле Name напишем имя формы ogl_form1. Дальше нам необходимо вытащить на форму компонент TOpenGLControl. Имя компонента будет OpenGLControl1. Теперь нам необходимо для нашей формы написать код обработчика события OnCreate, для этого в (Object Inspector) инспекторе объекта выберите нашу форму с именем ogl_form1 и перейдите с вкладки (Properties) Свойства на вкладку (Events) Событий, найдите в списке событий, событие OnCreate и выберите кнопку с тремя точками напротив. Ваш обработчик должен выглядеть как показано ниже:

procedure Togl_form1.FormCreate(Sender: TObject);
begin

Application.OnIdle := @IdleFunc;

end;

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

Application.OnIdle := @IdleFunc;

В модуле формы ogl_p2_unit1.pas в секцию uses нам необходимо добавить OpenGL модуль с именем gl.

В глобальной секции переменных var в модуле формы ogl_p2_unit1.pas, после строчки:

var
ogl_form1: Togl_form1;

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

timer: single;
LastMsecs: integer;
и третья переменная, задает угол на который поворачивается объект каждый раз:

rrx: single;

Создадим обработчик формы для события изменения размеров формы. Для этого нам необходимо в (Object Inspector) инспекторе объектов перейти на вкладку событий формы и нажать на кнопку с тремя точками напротив события OnResize и в обработчике события написать следующий код:

procedure Togl_form1.FormResize(Sender: TObject);
begin
OpenGLControl1.SetBounds(0, 0, Width, Height);
end;

Строчкой OpenGLControl1.SetBounds(0, 0, Width, Height); мы устанавливаем границы компонента OpenGLControl1 при изменение размеров формы, т.е. компонент OpenGLControl1 будет растянут на всю форму.

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

procedure Togl_form1.IdleFunc(Sender: TObject; var Done: Boolean);
begin
OpenGLControl1.Invalidate;
end;

Если приложение ничего не делает, то область вывода OpenGL графики компонента OpenGLControl1 объявляется не действительной, тем самым заставляет перерисовать область вывода графики компонента OpenGLControl1, т.е. вызывается процедура — обработчик события OnPaint компонента OpenGLControl1.

В классе формы нам понадобится объявить процедуру IdleFunc.

Рассмотрим обработчик события OnPaint компонента OpenGLControl1. Для начала нужно создать данную процедуру — обработчик. В инспекторе объектов выберите компонент OpenGLControl1 и перейдите на вкладку событий. Найдите событие OnPaint и нажмите на кнопку с тремя кнопками напротив.

procedure Togl_form1.OpenGLControl1Paint(Sender: TObject);
var
CurTime: TDateTime;
MSecs: integer;
begin

CurTime:=Now;

MSecs:=round(CurTime*86400*1000) mod 1000;

if MSecs<0 then MSecs:=1000+MSecs;
timer:=msecs-LastMsecs;

if timer<0 then timer:=1000+timer;
LastMsecs:=MSecs;

glClearColor(0.0, 0.0, 0.0, 0.0);

glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);

glLoadIdentity ();
glFrustum (-1, 1, -1, 1, 4.5, 10);
glTranslatef(0.0, 0.0, -5.0);

rrx:=rrx-0.6*(timer/10);
glRotatef(rrx,0.0,1.0,0.0);

glBegin(GL_QUADS);

glColor3f( 1.0, 1.0, 0.0);

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

glEnd();

OpenGLControl1.SwapBuffers;
end;

1) Объявляем локальные переменные, которые будут использоваться в процедуре, секция var:
var
CurTime: TDateTime;
MSecs: integer;

2) Расчет времени используемое для вращение OpenGL объекта:

CurTime:=Now;

MSecs:=round(CurTime*86400*1000) mod 1000;

if MSecs<0 then MSecs:=1000+MSecs;
timer:=msecs-LastMsecs;

if timer<0 then timer:=1000+timer;
LastMsecs:=MSecs;

3) Инициализация сцены и настройка обзора сцены:

glClearColor(0.0, 0.0, 0.0, 0.0);

glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);

glLoadIdentity ();
glFrustum (-1, 1, -1, 1, 4.5, 10);
glTranslatef(0.0, 0.0, -5.0);

4) Вращаем объект на значение rrx с учетом времени.

rrx:=rrx-0.6*(timer/10);
glRotatef(rrx,0.0,1.0,0.0);

5) Формируем квадрат желтого цвета:

glBegin(GL_QUADS);

glColor3f( 1.0, 1.0, 0.0);

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

glEnd();

6) Отображаем содержимое буфера на экран:

OpenGLControl1.SwapBuffers;

И последнее, что нам осталось сделать, это написать обработчик события OnResize для компонента OpenGLControl1, в котором мы будем подгонять размер OpenGL сцены под размер компонента OpenGLControl1. Опять выбираем, в инспекторе объектов, компонент OpenGLControl1, переходим на вкладку события и находим событие OnResize. Нажимаем кнопку с тремя точками напротив этого события. Код обработчика показан ниже:

procedure Togl_form1.OpenGLControl1Resize(Sender: TObject);
begin
glViewport (0, 0, OpenGLControl1.Width, OpenGLControl1.Height);
end;

Теперь взглянем на снимок нашего приложения в действие (Смотрите рисунок 2).

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

Код программы:
unit ogl_p2_unit1;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, FileUtil, OpenGLContext, Forms, Controls
  Graphics, Dialogs, gl;

type

  { Togl_form1 }

  Togl_form1 = class(TForm)
    OpenGLControl1: TOpenGLControl;
    procedure FormCreate(Sender: TObject);
    procedure FormResize(Sender: TObject);
    procedure OpenGLControl1Paint(Sender: TObject);
    procedure OpenGLControl1Resize(Sender: TObject);
    procedure IdleFunc(Sender: TObject; var Done: Boolean);
  private
    { private declarations }
  public
    { public declarations }
  end;

var
  ogl_form1: Togl_form1;
  timer: single;
  LastMsecs: integer;
  rrx: single;

implementation

{$R *.lfm}

{ Togl_form1 }

procedure Togl_form1.OpenGLControl1Paint(Sender: TObject);
var
  CurTime: TDateTime;
  MSecs: integer;
begin

  CurTime:=Now;

  MSecs:=round(CurTime*86400*1000) mod 1000;

  if MSecs<0 then MSecs:=1000+MSecs;
        timer:=msecs-LastMsecs;

  if timer<0 then timer:=1000+timer;
        LastMsecs:=MSecs;

  glClearColor(0.0, 0.0, 0.0, 0.0);

  glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);

  glLoadIdentity ();
  glFrustum (-1, 1, -1, 1, 4.5, 10);
  glTranslatef(0.0, 0.0, -5.0);

  rrx:=rrx-0.6*(timer/10);

  glRotatef(rrx,0.0,1.0,0.0);

  glBegin(GL_QUADS);

  glColor3f( 1.0, 1.0, 0.0);

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

  glEnd();

  OpenGLControl1.SwapBuffers;
end;

procedure Togl_form1.OpenGLControl1Resize(Sender: TObject);
begin
 glViewport (0, 0, OpenGLControl1.Width, OpenGLControl1.Height);
end;

procedure Togl_form1.FormCreate(Sender: TObject);
begin
    Application.OnIdle := @IdleFunc;
end;

procedure Togl_form1.FormResize(Sender: TObject);
begin
     OpenGLControl1.SetBounds(0, 0, Width, Height);
end;

procedure Togl_form1.IdleFunc(Sender: TObject; var Done: Boolean);
begin
    OpenGLControl1.Invalidate;
end;

end.


syntax highlighted by Code2HTML, v. 0.9.1

воскресенье, 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