14. Пример использования OpenGL в проекте Delphi

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

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  OpenGL, ExtCtrls, StdCtrls;

type
  TfrmGL = class(TForm)
    Timer1: TTimer;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure FormKeyDown(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    procedure Timer1Timer(Sender: TObject);

  private
    DC : HDC;
    hrc: HGLRC;
  protected
    procedure WMPaint(var Msg: TWMPaint); message WM_PAINT;
  end;

var
  frmGL: TfrmGL;

implementation

{$R *.DFM}

const
  POINT_COUNT = 3000;

var
  points: array [0..POINT_COUNT - 1] of TGLArrayf3;
  motion: array [0..POINT_COUNT - 1] of TGLArrayf3;

{Процедура формирования фонтана}
procedure UpdatePOINT(i: Word);
begin
  points[i][0] := points[i][0] + motion[i][0];
  points[i][1] := points[i][1] + motion[i][1];
  if points[i][1] < -0.9 then begin
    points[i][0] := 0.0;
    points[i][1] := -0.6;
    motion[i][0] := (Random - 0.5) / 20;
    motion[i][1] := Random / 7 + 0.02;
    end
  else motion[i][1] := motion[i][1] - 0.01;
end;

{Процедура перерисовки окна}
procedure TfrmGL.WMPaint(var Msg: TWMPaint);
var
  ps: TPaintStruct;
  i : GLUint;
begin
  glClear(GL_COLOR_BUFFER_BIT);
  glBegin(GL_POINTS);
    for i := 0 to POINT_COUNT - 1 do begin
      UpdatePOINT(i);
      glVertex3fv(@points[i]);
    end;
  glEnd;
  SwapBuffers(DC);
end;

{Процедура установки формата пикселя}
procedure SetDCPixelFormat(hdc: HDC);
var
  pfd         : TPixelFormatDescriptor;
  nPixelFormat: Integer;
begin
  FillChar(pfd, SizeOf(pfd), 0);
  pfd.dwFlags  := PFD_DRAW_TO_WINDOW or PFD_SUPPORT_OPENGL or PFD_DOUBLEBUFFER;
  nPixelFormat := ChoosePixelFormat(hdc, @pfd);
  SetPixelFormat(hdc, nPixelFormat, @pfd);
end;

{Процедура создания формы}
procedure TfrmGL.FormCreate(Sender: TObject);
begin
  DC := GetDC(Handle);
  SetDCPixelFormat(DC);
  hrc := wglCreateContext(DC);
  wglMakeCurrent(DC, hrc);
  glPointSize(1);
  glColor3f(0, 0.7, 0.9);
end;

{Процедура завершения работы приложения}
procedure TfrmGL.FormDestroy(Sender: TObject);
begin
  wglMakeCurrent(0, 0);
  wglDeleteContext(hrc);
  ReleaseDC(Handle, DC);
  DeleteDC(DC);
end;

{Процедура нажатия клавиши ESC}
procedure TfrmGL.FormKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  If Key = VK_ESCAPE then Close;
end;

{Процедура обработки событий таймера}
procedure TfrmGL.Timer1Timer(Sender: TObject);
begin
  InvalidateRect(Handle, nil, False);
end;

end.

В списке uses расположен необходимый для работы приложения модуль OpenGL.pas. Количество точек (капелек, из которых состоит фонтан) определяется константой POINT_COUNTИзучение программы начнем с процедуры создания формы FormCreate. Вывод изображения фонтана на поверхность формы начинается с команд:

DC := GetDC(Handle);
SetDCPixelFormat;
hrc := wglCreateContext(DC);
wglMakeCurrent(DC, hrc);

Первым аргументом функции, расположенной в последней строке, является ссылка на контекст устройства (величина DC типа HDC), на который будет осуществляться вывод. В нашем случае это окно формы (DC := GetDC(Handle)). Для получения контекста необходима величина hrc типа HGLRC (hrc := wglCreateContext(DC)). Затем строка glPointSize(1) задает размер точек (в нашем случае это один пиксель), а строка glColor3f(0, 0.7, 0.9) указывает их цвет.

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

FillChar(pfd, SizeOf(pfd), 0);
pfd.dwFlags := PFD_DRAW_TO_WINDOW or PFD_SUPPORT_OPENGL or PFD_DOUBLEBUFFER;

Иными словами, системе сообщается, что вывод будет осуществляться в окно (PFD_DRAW_TO_WINDOW), что библиотека OpenGL поддерживается (PFD_SUPPORT_OPENGL) и что будет использоваться двойная буферизация (PFD_DOUBLEBUFFER). Затем функция ChoosePixelFormat(hdc, @pfd) возвращает формат пикселя, который нужен в качестве аргумента функции SetPixelFormat(hdc, nPixelFormat, @pfd).

В процедуре WMPaint cтрока glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT) очищает экран и окрашивает его заданным цветом. Строка glBegin(GL_POINTS), как говорят, открывает командную скобку, а строка glEnd закрывает ее. Строки, расположенные между ними, задают область вывода на экран графических примитивов (в нашем случае точек, так как используется константа GL_POINTS). Причем создание формы фонтана происходит в специальной процедуре UpdatePOINT. Команда SwapBuffers(DC) используется в режиме двойной буферизации для вывода на экран содержимого заднего буфера.

Обработка событий таймера заключается в том, что двадцать раз в секунду перерисовывается окно программы (строка InvalidateRect(Handle, nil, False)).

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

Результат работы программы представлен в видеофрагменте.

Видео YouTube


 
ċ
Fountain.flv
(8632k)
Олег Данилов,
6 февр. 2012 г., 05:35
ċ
OpenGL.pas
(146k)
Олег Данилов,
6 февр. 2012 г., 04:52
ċ
Пример использования OpenGL.rar
(161k)
Олег Данилов,
7 февр. 2012 г., 23:34