Delphi下OpenGL2d绘图(06)-画图(多窗口、多视图、多个DC)

一、前言

在学习OpenGL的过程中,发现很多函数都是全局的。前面几章中都是在一个窗口DC中画图,那么要在多个窗口画图,需要怎么处理呢?网上方法有多种,这里采用其中一种,利用wglMakeCurrent函数来切换不同窗口,以达到多窗口同时喧染的目的。

二、准备

每个窗口与OpenGL绑定时,都通过以下几个过程进行:

1.获取窗口句柄Handle/HWND(在TWinControl继承下来的类中,都可以通过TWinControl.Handle获得,MFC的窗口可以通过CWnd::GetSafeHwnd()获得)

2.通过句柄获取设备场景HDC(通过API GetDC()获取)

3.通过设备场景HDC获取OpenGL的HGLRC(通过OpenGL的wglCreateContext()获得)

当然,在程序销毁时记得释放相应的HGLRC与窗口DC。通过以上的对应关系,可以把这些信息存储在数组中。以四个窗口为例,我建了这样几个数组:

    FDC: array[0..3] of HDC;
    FHRC: array[0..3] of HGLRC;
    FHwnd: array[0..3] of THandle;

三、初始化

本例以多个TPanel为例代替多个窗口,以上三个数组进行初始化。新建了一个inidc()的方法,在窗口的OnCreate时调用,目的是初始化数组变量的值

procedure TForm1.FormCreate(Sender: TObject);
begin
  Fbmpindex := 0;
  // 对多个窗口进行初始化
  inidc(0, Pnl1.Handle);
  inidc(1, Pnl2.Handle);
  inidc(2, Pnl3.Handle);
  inidc(3, Pnl4.Handle);
end;

下面的inidc的代码

procedure TForm1.inidc(i: Integer; hform: THandle);
var
 pfd:TPIXELFORMATDESCRIPTOR;
  pixelFormat: Integer;
begin
  With pfd do
  begin
    nSize := sizeof(TPIXELFORMATDESCRIPTOR); // size
    nVersion := 1; // version
    dwFlags := PFD_SUPPORT_OPENGL or PFD_DRAW_TO_WINDOW or PFD_DOUBLEBUFFER; // support double-buffering
    iPixelType := PFD_TYPE_RGBA; // color type
    cColorBits := 24; // preferred color depth
    cRedBits := 0;
    cRedShift := 0; // color bits (ignored)
    cGreenBits := 0;
    cGreenShift := 0;
    cBlueBits := 0;
    cBlueShift := 0;
    cAlphaBits := 0;
    cAlphaShift := 0; // no alpha buffer
    cAccumBits := 0;
    cAccumRedBits := 0; // no accumulation buffer,
    cAccumGreenBits := 0; // accum bits (ignored)
    cAccumBlueBits := 0;
    cAccumAlphaBits := 0;
    cDepthBits := 16; // depth buffer
    cStencilBits := 0; // no stencil buffer
    cAuxBuffers := 0; // no auxiliary buffers
    iLayerType := PFD_MAIN_PLANE; // main layer
    bReserved := 0;
    dwLayerMask := 0;
    dwVisibleMask := 0;
    dwDamageMask := 0;
  end;
  FDC[i] := GetDC(hform);
  FHwnd[i] := hform;
  pixelFormat := ChoosePixelFormat(FDC[i], @pfd);
  if pixelFormat = 0 then
    Exit;
  if not SetPixelFormat(FDC[i], pixelFormat, @pfd) then
    Exit;
  FHRC[i] := wglCreateContext(FDC[i]);
  wglMakeCurrent(FDC[i], FHRC[i]);

  // 设置背景色为 黑色 参数为 RGBA
  glClearColor(0, 0, 0, 0);
end;

四、绘制

这里修改一下前面几章中的Draw函数,用于支持多窗口的绘制,代码如下:

procedure TForm1.Draw(i: Integer);
var
  Bmp: TBitmap;
  texture: GLuint;
  l, t, w, h: Integer;
  rc: TRect;
begin
  // 重新设置显示区域
  wglMakeCurrent(FDC[i], FHRC[i]);
  // 重新计算并设置显示区域大小
  GetWindowRect(fhwnd[i], rc);
  w := rc.Right - rc.Left;
  h := rc.Bottom - rc.Top;
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity;
  glViewPort(0, 0, w, h);
  gluOrtho2D(0, w, h, 0);
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity;

  // 只是为了显示多个图片,不是必须的
  inc(Fbmpindex);
  Bmp := TBitmap.Create;
  Bmp.LoadFromFile(ExtractFilePath(ParamStr(0)) + IntToStr(Fbmpindex mod 3) + ‘.bmp‘);
  // 创建纹理区域
  glGenTextures(1, @texture);
  // 绑定纹理区域
  glBindTexture(GL_TEXTURE_2D, texture);
  // 使用位图创建图像纹理
  glTexImage2D(
    GL_TEXTURE_2D,            // 纹理是一个2D纹理 GL_TEXTURE_2D
    0,                        // 图像的详细程度 默认 0
    3,                        // 数据的成分数。因为图像是由红,绿,蓝三种组成 默认3
    Bmp.Width,                // 纹理的宽度
    Bmp.Height,               // 纹理的高度
    0,                        // 边框的值 默认 0
    GL_BGR_EXT,               // 数据格式 bmp使用 bgr
    GL_UNSIGNED_BYTE,         // 组成图像的数据是无符号字节类型的
    Bmp.ScanLine[Bmp.Height - 1] // DIB数据指针
  );
  // 下面两行是让opengl在放大原始的纹理大(GL_TEXTURE_MAG_FILTER)或缩小原始纹理(GL_TEXTURE_MIN_FILTER)时OpenGL采用的滤波方式。
  // GL_LINEAR 使用线性滤波,可以把图片处理处平滑,但需要更多的内存与CPU
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);  // 线形滤波
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);  // 线形滤波

  // 以下是绘图,利用一个四边形,绘制图片

  // 启用纹理映射
  if glIsEnabled(GL_TEXTURE_2D) = 0 then
    glEnable(GL_TEXTURE_2D);
  // 清空缓冲区
  glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);  

  l := 10;
  t := 10;
  w := 100 + (i * 50); // 放大为200*200的图片

  // 选择纹理 如果场景中使用多个纹理,不能在glBegin() 和 glEnd() 之间绑定纹理
  glBindTexture(GL_TEXTURE_2D, texture);
  glBegin(GL_QUADS);
  // glTexCoord2f 的第一个参数是X坐标。
  // 0.0是纹理的左侧。 0.5是纹理的中点, 1.0是纹理的右侧。
  // glTexCoord2f 的第二个参数是Y坐标。
  // 0.0是纹理的底部。 0.5是纹理的中点, 1.0是纹理的顶部。
  glTexCoord2f(0, 1);
  glVertex2f(l, t);
  glTexCoord2f(1, 1);
  glVertex2f(l + w, t);
  glTexCoord2f(1, 0);
  glVertex2f(l + w, t + w);
  glTexCoord2f(0, 0);
  glVertex2f(l, t + w);
  glEnd();

  Bmp.Free;
  SwapBuffers(FDC[i]);
end;

上面的画图片的代码,如果觉得看起来复杂,可以用以下简单点的代码:

procedure TForm1.DrawSimple(i: Integer);
var
  l, t, w, h: Integer;
  rc: TRect;
begin
  // 重新设置显示区域
  wglMakeCurrent(FDC[i], FHRC[i]);
  // 重新计算并设置显示区域大小
  GetWindowRect(fhwnd[i], rc);
  w := rc.Right - rc.Left;
  h := rc.Bottom - rc.Top;
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity;
  glViewPort(0, 0, w, h);
  gluOrtho2D(0, w, h, 0);
  glMatrixMode(GL_MODELVIEW);
  glLoadIdentity;

  // 清空缓冲区
  glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
  // 设置四边形的颜色
  glColor3f(1, 0.5, 0);

  // 绘制第一个多边形
  l := 10;
  t := 10;
  w := 64 + (i - 2) * 50;
  glBegin(GL_QUADS);
  glVertex2f(l, t);
  glVertex2f(l + w, t);
  glVertex2f(l + w, t + w);
  glVertex2f(l, t + w);
  glEnd();
  SwapBuffers(FDC[i]);
end;

为了方便演示,这里用一个定时器TTimer代替以前在窗口的OnPaint画图,定时器下的代码如下:

procedure TForm1.tmr1Timer(Sender: TObject);
begin
  Draw(0);
  Draw(1);
  DrawSimple(2);
  DrawSimple(3);
end;

五、释放

最后记得释放资源,Delphi中基本上申请的资源都要回收,new->delete/dispose、get->release、create->destroy,简单的说,创建(create)的要销毁(destroy),借(get)的要还(release)。

procedure TForm1.FormDestroy(Sender: TObject);
var
  i: Integer;
begin
  for i := 0 to 4 - 1 do
  begin
    wglMakeCurrent(FDC[i], FHRC[i]);
    wglDeleteContext(FHRC[i]);
    ReleaseDC(fhwnd[i], FDC[i]);
  end;
end;

效果如下:

源码下载:OpenGL_06.zip

2014-07-17 by lin

Delphi下OpenGL2d绘图(06)-画图(多窗口、多视图、多个DC)

时间: 2024-10-10 09:08:23

Delphi下OpenGL2d绘图(06)-画图(多窗口、多视图、多个DC)的相关文章

Delphi下OpenGL2d绘图(01)-初始化

一.前言: Delphi默认支持OpenGl,可以uses OpenGL单元进行引用,便可以使用OpenGL的函数.OpenGl是跨平台的,而且Windows很早就支持并集成在系统中,存在于system32中的opengl32.dll,不需要额外安装.虽然windows本身有d3d,但能力有限,还没去学习怎么用. 引用别人的话:OpenGL仅仅支持以下几种基本几何图形:点,线和多边形.没有表面或者更高级的图形(比如球状图形)能被作为基本图形元素绘制.但是它们能够用多边形完美的模仿出来.随意看看现

Delphi下OpenGL2d绘图(04)-画四边形

一.前言 画四边形基本上与前几遍文字代码是相同.区别在于glBegin()的参数“GL_QUADS”.绘制的框架代码可以使用 Delphi下OpenGL2d绘图(01)-初始化 中的代码.修改的部份为 Draw 函数的内容. 二.画四边形 使用GL_QUADS:绘制由四个顶点组成的一组单独的四边形.顶点4n-3.4n-2.4n-1和4n定义了第n个四边形.总共绘制N/4个四边形.学画四边形是为了画位图做准备. 设置颜色: glColor3f(1, 0.5, 0); 可以设置四边形的颜色,参数为三

Delphi下OpenGL2d绘图(05)-画图片Bmp

一.前言 找了不少资料,要画图片要先处理一下,需要引用别的单元,Delphi中没带,需要另外下载Gl.pas.看网上说是自带的OpenGl单元封装的是1.0版的,有此函数未声明.网上可以找到Gl.pas单元.另外需要一个Glaux.pas单元与glaux.dll,据说是辅助库.在本文最后会提供下载.感谢所有作者提供的资料. 二.流程 绘画图片需要以下几个流程.Window本身的绘图是以位图为基础的,png,jpg等,绘画时,可以转为bmp再画. 1.加载bmp图片:auxDIBImageLoad

Delphi下OpenGL2d绘图(03)-画线

一.前言 画线与画点基本上代码是相同.区别在于glBegin()的参数.绘制的框架代码可以使用 Delphi下OpenGL2d绘图(01)-初始化 中的代码.修改的部份为 Draw 函数的内容. 二.画线 GL_LINES:把每一个顶点作为一个独立的线段,顶点2n-1和2n之间共定义了n条线段,总共绘制N/2条线段 GL_LINE_STRIP:绘制从第一个顶点到最后一个顶点依次相连的一组线段,第n和n+1个顶点定义了线段n,总共绘制n-1条线段 GL_LINE_LOOP:绘制从第一个顶点到最后一

Delphi下OpenGL2d绘图(02)-画点

一.前言 图形的绘制可以使用glBegin().glEnd()之间完成,绘制的框架代码可以使用 Delphi下OpenGL2d绘图(01)-初始化 中的代码.修改的部份为 Draw 函数的内容. 二.画点 使用glPointSize 函数指定栅格化点的直径.默认为1.0,只在GL_POINTS下起作用,关于消锯齿等功能以后再研究.使用glBegin(GL_POINTS)告诉OpenGL画点,参数GL_POINTS表示点,还有其他参数,如画线GL_LINES等,具体可以参考OpenGL单元的源码.

DELPHI下API简述(1800个API)

DELPHI下API简述 http://zero.cnbct.org/show.asp?id=144 auxGetDevCaps API 获取附属设备容量 auxGetNumDevs API 返回附属设备数量 auxGetVolume API 获取当前卷设置 auxOutMessage API 向输出设备发送消息 auxSetVolume API 设置附属设备卷 AbortDoc API 终止一项打印作业 AbortPath API 终止或取消DC中的一切路径 AbortPrinter API

DELPHI下的SOCK编程

本文是写给公司新来的程序员的,算是一点培训的教材.本文不会涉及太多的编程细节,只是简单讲解在DELPHI下进行Winsock编程最好了解的知识. 题外话:我认为学习编程就如同学习外语一样,最好的方式是你先学会如何去运用它,然后才是了解它的语言特性.语法之类的东西.不过很可惜,我们以前的外语教育使用了相反的过程.软件编程也是一样,在很多人的大学阶段,你更多的是学习那些理论知识,学习“语法”,这里,我丝毫没有贬低理论知识重要性的意思.理论知识和实践是相辅相成的,但一个恰当的学习方式,很多时候可以让学

Delphi下的RTTI函数大全

http://ljz9425.blog.163.com/blog/static/369148572008111635253858/ Delphi下的RTTI(下) 2008-12-16 15:52:53|  分类: Delphi |字号 订阅目 录===============================================================================⊙ GetTypeData 函数⊙ GetPropInfo 函数⊙ FindPropInfo

深入Delphi下的DLL编程

深入Delphi下的DLL编程 作者:岑心 引 言 相信有些计算机知识的朋友都应该听说过“DLL”.尤其是那些使用过windows操作系统的人,都应该有过多次重装系统的“悲惨”经历——无论再怎样小心,没有驱动损坏,没有病毒侵扰,仍然在使用(安装)了一段时间软件后,发现windows系统越来越庞大,操作越来越慢,还不时的出现曾经能使用的软件无法使用的情况,导致最终不得不重装系统.这种情况常常是由于dll文件的大量安装和冲突造成的.这一方面说明DLL的不足,另一方面也说明DLL的重要地位,以至我们无