Основы 1: Библиотека OpenGL



Автор:

ZasKok S.M.S.

Дата:

11 августа 2007

Файлы:

Заголовочный файл OpenGL для Delphi



DirectX, OpenGL и видеокарта.

Я думаю, многие из читателей играют в компьютерные игры с великолепной трехмерной графикой или хоть раз смотрели потрясающие графические демонстрационные программы (демки). Известно, что многие из них использую графические библиотеки, такие как OpenGL и DirectX. Но что собой представляют эти библиотеки?

Полагаю, вы не раз видели при установки DirectX богатый набор файлов (d3d9.dll, ddraw.dll, dinput.dll, dsound.dll, и др.). Они содержат в себе основные компоненты DirectX: Direct3D (3D), DirectDraw (2D), DirectInput (ввод/вывод), DirectSound (звук) и др., встраивающиеся в систему через COM-интерфейс. Библиотека OpenGL представляет собой всего один файл, opengl32.dll, расположенный в системной директории. Это уже обычная DLL с огромным набором низкоуровневых функций. Этот файл поставляется вместе с Windows.

Но как же тогда обновляются или совершенствуются возможности библиотеки, если файл не изменяется? DirectX, напротив, обновляется чуть ли не каждый месяц. Дело в том, что DirectX и OpenGL, в основном, не общаются с видеокартой напрямую, а используют в качестве надежного посредника ее драйвер. Вот, например, схема взаимодействия приложения и монитора компьютера с видеокартой ATI Radeon:

Схема вывода графических данных на монитор

Отсюда видно, что DirectX и OpenGL являются аппартно-независимыми, т.к. общаются с драйверами, которые у каждой видеокарты свои (и, естественно, являются аппартно-зависимыми). Однако, OpenGL не зависит также и от операционной системы (что нельзя сказать о DirectX) и содержится в Windows, Linux, MacOS и др.

Независимость и простой API интерфейс позволяют OpenGL стать интересным предметом изучения трехмерной графики для новичков и профессионалов. А система расширений OpenGL позволяет использовать эту библиотеку для создания сложнейших сцен с великолепной графикой. На основе OpenGL были написаны такие игры, как Quake 1,2,3,4 и Doom 3, а также почти все демки (для интересующихся: Scene.Org).

Подключение OpenGL

Итак, как было уже сказано, OpenGL в первую очередь представляет собой набор функций (API), которые можно использовать в своих программах. В этой и во всех следующих статьях будет использоваться язык программирования Delphi, который, как считает автор, наиболее легкий для понимания. Несмотря на это, к примерам на Delphi будут прилагаться примеры на С++ (с и без использования вспомогательной библиотеки GLUT), которые будут одинаково успешно компилироваться как на Windows, так и на Linux.

Автор нашел, по крайней мере, 3 способа подключения функций OpenGL к программе:

1. Во время компиляции программы. Этим способом в Delphi 7 функции просто объявлялись внешними, содержащимися в opengl32.dll.

Язык Delphi


procedure glBegin(mode: GLenum); stdcall;
  external 'opengl32.dll';

procedure glEnd; stdcall;
  external 'opengl32.dll';

procedure glVertex2f(x,y: GLfloat); stdcall;
  external 'opengl32.dll';



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

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

Язык Delphi


program Load;

uses
  Windows;

var
  glBegin: procedure(mode: GLEnum); stdcall;
  glEnd: procedure(); stdcall;
  glVertex2f: procedure(x, y: GLfloat); stdcall;
  //...

procedure LoadOpenGL;
var
  lib: HModule;
begin
  lib:=LoadLibrary('opengl32');

  glBegin:=GetProcAddress(lib,'glBegin');
  glEnd:=GetProcAddress(lib,'glEnd');
  glVertex2f:=GetProcAddress(lib,'glVertex2f');
  //...
end;

begin
  LoadOpenGL;
  //...
end.



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

Язык Delphi


glActiveTextureARB:=wglGetProcAddress('glActiveTextureARB');



3. Во время вызова функции. Это уже более хитрый способ - загрузка адреса функции при ее собственном вызове. Такой способ автор обнаружил в заголовочной файле для OpenGL 2.0, взятого с сайта OpenGL.Org.

Язык Delphi


program Load;

uses
  Windows;

var
  glBegin: procedure(mode: TGLenum); stdcall;
  glEnd: procedure(); stdcall;
  glVertex2f: procedure(x: TGLfloat; y: TGLfloat); stdcall;
  //...

procedure STUB_glBegin(mode: TGLenum); stdcall;
begin
  glBegin := wglGetProcAddress('glBegin');
  glBegin(mode);
end;

procedure STUB_glEnd; stdcall;
begin
  glEnd := wglGetProcAddress('glEnd');
  glEnd;
end;

procedure STUB_glVertex2f(x: TGLfloat; y: TGLfloat); stdcall;
begin
  glVertex2f := wglGetProcAddress('glVertex2f');
  glVertex2f(x,y);
end;

//...

procedure InitSTUBs;
begin
  glBegin:=STUB_glBegin;
  glEnd:=STUB_glEnd;
  glVertex2f:=STUB_glVertex2f;
end;

begin
  InitSTUBs;
  //...
end.



Таким образом адрес функции загружается тогда, когда она первый раз используется. Здесь можно сделать еще одну полезную вешь: если по каким-либо причинам адрес функции не загружен (может быть такая функция отсутствует), то в "STUB"-функции можно это учесть и не вызывать основную функцию. Этим можно обойти ошибку неверного доступа к памяти (access violation).

Язык Delphi


procedure STUB_glBegin(mode: TGLenum); stdcall;
var
  func: pointer;
begin
  func := wglGetProcAddress('glBegin');
  if Assigned(func) then
  begin
    glBegin:=func;
    glBegin(mode);
  end;
end;



Далее мы просто будем использовать заголовочный файл для OpenGL 2.0 - dglOpenGL.pas. Скачать его можно здесь.




Сайт создан в системе uCoz