频道栏目
首页 > 程序开发 > 软件开发 > Delphi > 正文
Delphi下OpenGL2d绘图(05)-画图片Bmp
2014-07-11 09:15:56      个评论      
收藏   我要投稿
一、前言

 

找了不少资料,要画图片要先处理一下,需要引用别的单元,Delphi中没带,需要另外下载Gl.pas。看网上说是自带的OpenGl单元封装的是1.0版的,有此函数未声明。网上可以找到Gl.pas单元。另外需要一个Glaux.pas单元与glaux.dll,据说是辅助库。在本文最后会提供下载。感谢所有作者提供的资料。

 

二、流程

 

  绘画图片需要以下几个流程。Window本身的绘图是以位图为基础的,png,jpg等,绘画时,可以转为bmp再画。

 

  1.加载bmp图片:auxDIBImageLoadA或其他函数

 

  2.转换为纹理:glGenTextures -> glBindTexture -> glTexImage2D, glTexParameteri用于设置相关参数

 

  3.绘制纹理:glBindTexture -> glBegin(GL_QUADS) -> glTexCoord2f -> glVertex2f -> glEnd

 

三、利用glDrawPixels函数绘图

 

glDrawPixels共有5个参数

width: 表图像的宽度

height: 表图像的高度

format:表图像的数据存储格式

atype: 未知 

pixels: DIB数据的指针

复制代码

procedure TForm1.Draw;

var

  Bmp: TBitmap;

begin

  Bmp := TBitmap.Create;

  Bmp.LoadFromFile(ExtractFilePath(ParamStr(0)) + '1.bmp');

  // 清空缓冲区

  glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);

  // TBitmap的图像数据在内存中是按行倒序连续存放的,通过TBitmap.ScanLine[TBitmap.Height-1]可以取得首地址即图像缓冲区地址

  // bmp图片的颜色是按b g r存储的,所以要选 GL_BGR_EXT做为参数

  glDrawPixels(Bmp.Width, Bmp.Height, GL_BGR_EXT, GL_UNSIGNED_BYTE, Bmp.ScanLine[Bmp.Height - 1]);

  SwapBuffers(FDC);

  Bmp.Free;

end;

复制代码

用以上方法绘制图片不需要启用纹理映射,可以通过glPixelZoom函数来缩放图片,显示位置在窗口的左下角。暂时不知道如何改变图像位置。

 

三、使用纹理绘图

 

我想按制图片的显示位置与放大缩小,怎么办?可以用以下方法。

 

1.按流程,我们先把图片加载到程序里,获取相关的图片信息。

 

将图片加载到纹理中,有几种方法,网上有人写了,建议参考学习:https://www.cnblogs.com/IamEasy_Man/archive/2009/12/14/1624062.html

 

delphi中加载一张位图是很简单的,可以通过以下方式加载:

 

1).通过辅助库的auxDIBImageLoadA函数加载图片,返回是一个PTAUX_RGBImageRec数据指针,DIB数据格式为RGB。我没找到办法在使用完释放内存的办法。

 

  // RGB数据的结构体

  TAUX_RGBImageRec = record

    sizeX, sizeY: GLint;

    data: pointer;

  end;

  PTAUX_RGBImageRec =  ^TAUX_RGBImageRec;

var

  p: PTAUX_RGBImageRec;

begin

  p := auxDIBImageLoadA(PAnsiChar(ExtractFilePath(ParamStr(0)) + '1.bmp'));

  // p 怎么释放? Dispose与Freemem都无法操作这个指针

end;

2).通过TBitmap.LoadFromFile加载图片。Delphi自带,从效率上对比,与auxDIBImageLoadA性能是一样的,但DIB数据格式为BGR,DIB指针为TBitmap.ScanLine[Bmp.Height - 1]

 

复制代码

var

  Bmp: TBitmap;

begin

  Bmp := TBitmap.Create;

  TBitmap.LoadFromFile(ExtractFilePath(ParamStr(0)) + '1.bmp');

  // do something

 

  // 用完释放

  Bmp.Free;

end;

复制代码

2.创建纹理,其中的glGenTextures与glBindTexture,在Gl.pas中。

 

复制代码

  // 创建纹理区域

  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);  // 线形滤波

复制代码

3.绘制纹理

 

绘制纹理之前,必须通知OpenGL开启纹理映射glEnable(GL_TEXTURE_2D)。开启后,非纹理的绘制将不起作用。用完记得关闭就可以了。

 

复制代码

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

  

  // 启用纹理映射

  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 := 200; // 放大为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();

复制代码

以上的绘制就结束了,以下是Draw中完整的代码,可以不引用辅助库Glaux.pas

 

复制代码

procedure TForm1.Draw;

var

  Bmp: TBitmap;

  texture: GLuint;

  l, t, w: Integer;

begin

  Bmp := TBitmap.Create;

  Bmp.LoadFromFile(ExtractFilePath(ParamStr(0)) + '1.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 := 200; // 放大为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);

end;

点击复制链接 与好友分享!回本站首页
相关TAG标签 图片
上一篇:Delphi用QJSON解析JSON格式的数据
下一篇:Delphi中BCD和Currency类型
相关文章
图文推荐

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站