Delphi使用OpenGL2d绘图之画图片Bmp的方法
<p><strong>一、前言:</strong></p><p>对于Delphi来说,要画图片要先处理一下,需要引用别的单元,而Delphi中没带,需要另外下载Gl.pas。网上常见自带的OpenGl单元封装的是1.0版的,有此函数未声明。网上可以找到Gl.pas单元。另外需要一个Glaux.pas单元与glaux.dll,是辅助库。在本文最后会提供下载。</p>
<p><strong>二、实现流程:</strong></p>
<p>绘画图片需要以下几个流程。Window本身的绘图是以位图为基础的,png,jpg等,绘画时,可以转为bmp再画。</p>
<p>1.加载bmp图片:使用auxDIBImageLoadA或其他函数</p>
<p>2.转换为纹理:glGenTextures -> glBindTexture -> glTexImage2D, glTexParameteri用于设置相关参数</p>
<p>3.绘制纹理:glBindTexture -> glBegin(GL_QUADS) -> glTexCoord2f -> glVertex2f -> glEnd</p>
<p><strong>三、利用glDrawPixels函数绘图</strong></p>
<p>glDrawPixels共有如下5个参数:</p>
<p>width: 表图像的<span style="color: #0000ff">宽度<br />
</span>height: 表图像的<span style="color: #0000ff">高度<br />
</span>format:表图像的<span style="color: #0000ff">数据存储格式<br />
</span>atype: 未知 <br />
pixels: DIB<span style="color: #0000ff">数据的指针</span></p>
<p>示例代码如下:</p>
<div class="jb51code">
<pre class="brush:delphi;">
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可以取得首地址即图像缓冲区地址
// bmp图片的颜色是按b g r存储的,所以要选 GL_BGR_EXT做为参数
glDrawPixels(Bmp.Width, Bmp.Height, GL_BGR_EXT, GL_UNSIGNED_BYTE, Bmp.ScanLine);
SwapBuffers(FDC);
Bmp.Free;
end;
</pre>
</div>
<p>用以上方法绘制图片不需要启用纹理映射,可以通过glPixelZoom函数来缩放图片,显示位置在窗口的左下角(暂时不知道如何改变图像位置。)</p>
<p><strong>三、使用纹理绘图</strong></p>
<p>想要按制图片的显示位置与放大缩小,可以用以下方法。</p>
<p>1.按流程,我们先<strong>把图片加载到程序里,获取相关的图片信息</strong>。</p>
<p>将图片加载到纹理中,可参考本站:https://www.jb51.net/article/52125.htm</p>
<p>在delphi中加载一张位图是很简单的,可以通过以下方式加载:</p>
<p>(1)通过辅助库的auxDIBImageLoadA函数加载图片,返回是一个PTAUX_RGBImageRec数据指针,DIB数据格式为RGB。</p>
<div class="jb51code">
<pre class="brush:delphi;">
// 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;
</pre>
</div>
<p>(2)通过TBitmap.LoadFromFile加载图片。Delphi自带,从效率上对比,与auxDIBImageLoadA性能是一样的,但DIB数据格式为BGR,DIB指针为TBitmap.ScanLine</p>
<div class="jb51code">
<pre class="brush:delphi;">
var
Bmp: TBitmap;
begin
Bmp := TBitmap.Create;
TBitmap.LoadFromFile(ExtractFilePath(ParamStr(0)) + '1.bmp');
// do something
// 用完释放
Bmp.Free;
end;
</pre>
</div>
<p><strong>2.创建纹理</strong>,其中的glGenTextures与glBindTexture,在Gl.pas中。</p>
<div class="jb51code">
<pre class="brush:delphi;">
// 创建纹理区域
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 // 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); // 线形滤波
</pre>
</div>
<p><strong>3.绘制纹理</strong></p>
<p>绘制纹理之前,必须通知OpenGL开启纹理映射glEnable(GL_TEXTURE_2D)。开启后,非纹理的绘制将不起作用。用完记得关闭就可以了。</p>
<div class="jb51code">
<pre class="brush:delphi;">
// 以下是绘图,利用一个四边形,绘制图片
// 启用纹理映射
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();
</pre>
</div>
<p>以上的绘制就结束了,以下是Draw中完整的代码,可以不引用辅助库Glaux.pas</p>
<div class="jb51code">
<pre class="brush:delphi;">
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 // 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;
</pre>
</div>
<p>本实例完整代码可点此下载。</p>
<div class="art_xg">
<b>您可能感兴趣的文章:</b><ul><li>Delphi下OpenGL2d绘图之画四边形的方法</li><li>Delphi下OpenGL2d绘图之画线的方法</li><li>Delphi下OpenGL2d绘图之画点的方法</li><li>opengl实现任意两点间画圆柱体</li></ul>
</div>
</div>
<!--endmain-->
頁:
[1]