четверг, 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

Комментариев нет:

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