用Delphi编写OpenGL导学——下[转帖] 

2006-12-06 15:36 发布

2680 0 0

 
不说废话了,让我们看看如何用Delphi编写OpenGL吧。
以前也有人写过Delphi如何编写OpenGL,不过都是根据OpenGL教科书将编程语言翻译成了Delphi而已,并没有体现出Delphi的方便高效。我的教学会让你见识到Delphi编写OpenGL的方便和高效的。
为了实现我的说法,你需要一个函数库。这是外国朋友写的,主要是为了方便Delphi编写OpenGL程序。以后你不用再使用Delphi自带的糟糕的Opengl函数库了。函数库叫 DOT,你可以去 delphi3d.net下载。或者下载本贴的附件。我修改了代码,增加了对累积缓存(Accumulations buffers)的支持。大家按需选择吧。


我讲讲如何使用吧。首先把下载得到的压缩包里所有的文件解压到某个目录里,比如 D:\DOT。然后,运行Delphi,选择Tools菜单下的Options,在Options里选择Library,然后点击Library path旁边的 ... 在打开的对话框里还是点击 ... 接着选择刚才解压的目录(如D:\DOT)然后点击确定,再点Add,这样你刚才的解压目录就加到了库搜索路径里。你还要在Browsing path里增加你的解压目录,过程和Library path一样,我就不重复了。
不过,上述设置以后,你还无法在你的程序里调用DOT函数库。你还需要在程序的 uses 里增加至少四个项目,如下:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, DotWindow, GL, GLu, GLext;
最后四个就是你要增加的项目了。
现在,准备工作一切就绪,我们可以进入OpenGL的世界了!

首先,有几个窗体属性需要设置。在窗体设计窗口,单击选择窗体,然后在Object Inspector面板里,找到BorderIcons项,展开,把除了biSystemMenu以外的项都改成False。再找到BorderStyle,把值改成bsSingle。再把Height改成480,Width改成640。好了,窗体设置到此结束,可以写代码了。
新项目的代码如下,我们一步步让它画出一个可以由用户控制的正方形吧。
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs;

type
  TForm1 = class(TForm)
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

end.


首先是uses里增加DotWindow, GL, GLu, GLext,变成
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, DotWindow, GL, GLu, GLext;
然后给窗体添加几个事件,增加几个变量和函数,最终代码如下
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, DotWindow, GL, GLu, GLext;

type
  TForm1 = class(TDotForm)    //注意这里,要把原来的TForm改成现在的TDotForm      
    procedure FormPaint(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
    bFullScreen : Bool;             //决定是否用全屏显示
    rX, rY      : GLuint;           //旋转角度

    procedure DrawScene;
    procedure LoadExtensions;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

程序首先创建窗体,产生OnCreate事件,这时调用FormCreate过程。在这个过程里,初始化OpenGL的一些参数
procedure TForm1.FormCreate(Sender: TObject);
begin
  bFullScreen := False;
  rX := 360;
  rY := 360;

  if bFullScreen then
  begin
    dotSetDisplayMode(800, 600, 32, 60);
    Self.BorderStyle := bsNone;
    Self.Height := 600;
    Self.Width  := 800;
    Self.WindowState := wsMaximized;
    Self.Context.DC  := GetDC(Self.Handle);
    ShowCursor(False);
  end;

  Self.Context.QuickPF(32, 0, 24, 0, 0);
  Self.Context.InitGL;
  LoadExtensions;

  glShadeModel(GL_SMOOTH);
  glEnable(GL_DEPTH_TEST);

  glClearColor(0, 0, 0, 0);

  glMatrixMode(GL_PROJECTION);
    gluPerspective(60.0, Self.ClientWidth / Self.ClientHeight, 1.0, 100.0);
  glMatrixMode(GL_MODELVIEW);


end;
书上能找到的内容我就不讲了,我只讲DOT特有的函数
dotSetDisplayMode
要用到四个参数,前两个设置屏幕的分辨率(比如640,480;1024,768),第三个设置颜色深度(8,16,32 还是选择32吧,省得麻烦),最后一个设置屏幕刷新率(60最保险)
Self.Context.QuickPF
用于设置像素格式的。函数默认设置了双缓存,共有五个参数(原版是四个)。分别设置 色彩缓存位数,透明缓存位数,深度缓存位数,模版缓存位数以及 累积缓存位数。
Self.Context.InitGL
利用刚才设置的像素格式,生成OpenGL的Context(还是不要乱翻译的好  );
注意:Self. 可以不用写,我写出来是为了防止混乱。
LoadExtensions
用于调用OpenGL的扩展功能。函数定义如下
procedure TForm1.LoadExtensions;
  procedure Load(const ext: String);
  begin
    if not glext_LoadExtension(ext) then
      raise Exception.Create('This demo requires ' + ext + '!');
  end;
begin

  {*****************************************************************************
    Load all required OpenGL extensions here, and throw an exception if any of
    them are not found.
   ****************************************************************************}

  Load('GL_ARB_multitexture');
  Load('GL_EXT_texture_filter_anisotropic');
end;
OpenGL的初始化完成了。

窗体显示任何东西,都会产生OnPaint事件,所以在FormPaint过程里添加OpenGL的绘图函数
procedure TForm1.FormPaint(Sender: TObject);
begin
  DrawScene;
end;
DrawScene 函数定义如下
procedure TForm1.DrawScene;
begin
  glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);

  glLoadIdentity;
  glTranslatef(0, 0, -3);
  glRotatef(rX, 1, 0, 0);
  glRotatef(rY, 0, 1, 0);
  glBegin(GL_QUADS);
    glColor3f(1, 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);
///////////////////////////////////////
    glColor3f(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);
//////////////////////////////////////
    glColor3f(0, 0, 1);
    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);
//////////////////////////////////////
    glColor3f(1, 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);
/////////////////////////////////////
    glColor3f(1, 0, 1);
    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);
////////////////////////////////////
    glColor3f(1, 1, 1);
    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;

  Self.Context.PageFlip;
end;
对了,别忘了在程序关闭时,会产生OnClose事件,所以要在FormClose过程里加一个函数调用
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  dotSetDisplayMode(0, 0, 0, 0);
end;
如果使用了全屏显示,调用dotSetDisplayMode(0, 0, 0, 0)可以恢复原来的屏幕设置。窗口模式调用此函数没有任何不良影响。

现在运行程序就能看见一个正方形了。但是还不能控制。这时就要用到FormKeyDown过程了。
procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  case Key of
    VK_UP:
    begin
      if rX = 0 then
        rX := 360;
      Dec(rX);
      DrawScene;
    end;
    VK_DOWN:
    begin
      if rX = 720 then
        rX := 360;
      Inc(rX);
      DrawScene;
    end;
    VK_LEFT:
    begin
      if rY = 0 then
        rY := 360;
      Dec(rY);
      DrawScene;
    end;
    VK_RIGHT:
    begin
      if rY = 720 then
        rY := 360;
      Inc(rY);
      DrawScene;
    end;
    VK_ESCAPE:
      Close;
  end;
end;

现在运行程序,就可以用键盘上的方向键控制正方体旋转了,而且只要按键盘的Esc键就能退出程序了。

怎么样,简单吗?
什么,不简单?!你按照OpenGL教材上的方法,或者用C/C++编写我这个程序以后再发表意见吧。

DOT让我们摆脱了繁琐的OpenGL初始化设置(当然不只如此,DOT更方便的功能需要你更深入的学习OpenGL才能体会到)。
Delphi让我们不用为创建、修改窗体,响应键盘消息等等基本Windows编程而费神。
两者的结合让我们可以轻松编写OpenGL程序了!

TA的作品 TA的主页
B Color Smilies

你可能喜欢

用Delphi编写OpenGL导学——下[转帖] 
联系
我们
快速回复 返回顶部 返回列表