Delphi使用OpenGL2d绘图之画图片Bmp的方法
一、前言:
对于Delphi来说,要画图片要先处理一下,需要引用别的单元,而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数据的指针
示例代码如下:
procedureTForm1.Draw; var Bmp:TBitmap; begin Bmp:=TBitmap.Create; Bmp.LoadFromFile(ExtractFilePath(ParamStr(0))+'1.bmp'); //清空缓冲区 glClear(GL_COLOR_BUFFER_BITorGL_DEPTH_BUFFER_BIT); //TBitmap的图像数据在内存中是按行倒序连续存放的,通过TBitmap.ScanLine[TBitmap.Height-1]可以取得首地址即图像缓冲区地址 //bmp图片的颜色是按bgr存储的,所以要选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.nhooo.com/article/52125.htm
在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'); //dosomething //用完释放 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)。开启后,非纹理的绘制将不起作用。用完记得关闭就可以了。
//以下是绘图,利用一个四边形,绘制图片 //启用纹理映射 ifglIsEnabled(GL_TEXTURE_2D)=0then glEnable(GL_TEXTURE_2D); //清空缓冲区 glClear(GL_COLOR_BUFFER_BITorGL_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
procedureTForm1.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);//线形滤波 //以下是绘图,利用一个四边形,绘制图片 //启用纹理映射 ifglIsEnabled(GL_TEXTURE_2D)=0then glEnable(GL_TEXTURE_2D); //清空缓冲区 glClear(GL_COLOR_BUFFER_BITorGL_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;
本实例完整代码可点此下载。