当前位置:网站首页>GDI 及OPENGL的区别
GDI 及OPENGL的区别
2020-11-09 01:10:00 【shzwork】
GDI+的介绍:
GDI+是Windows XP的一个子系统,它主要负责在显示屏幕和打印设备输出有关信息。
它是一组通过C++类实现的应用程序编程接口。
GDI+对以前的Windows版本中GDI进行了优化,并添加了许多新的功能。作为图形设备接口的GDI+使得应用程序开发人员在输出屏幕和打印机信息的时候无需考虑具体显示设备的细节,他们只需调用GDI+库输出的类的一些方法即可完成图形操作。
GDI+的使用方法:
在使用GDI+的cpp文件中包含GdiPlus.h文件,并引用命名空间,代码如下:
#include <GdiPlus.h>
using namespace Gdiplus;
在项目属性中,链接器的输入选项中,添加附加依赖项:gdiplus.lib
GDI+进行初始化:
// GDI+ 资源初始化
ULONG_PTR uToken = 0;
GdiplusStartupInput gdiplusStartupInput;
GdiplusStartup(&uToKen,&gdiplusStartupInput,NULL);
反初始化代码:
//销毁GDI+资源
GdiplusShutdown(uToken);
GDI+颜色系统:
透明度合成运算:
透明度是像素之间的一种合成运算。计算公式:
输出颜色=前景色*Alpha/255+背景色*(255-Alpha)/255
比如:ARGB(100,0,0,0)
背景色rgb(255,255,255);
输出颜色(155,155,155);
Bitmap类的构造:
Bitmap(const WCHAR *filename);
// 通过图片的文件名来构造一个Bitmap对象
Bitmap(INT width,INT height,PixelFormat format=PixelFormat32bppARGB);
// 通过位图的宽度,高度,像素格式来构造一个空的Bitmap对象,其中format的默认值是PixelFormat32bppARGB,代表32位的颜色信息,颜色组成是A,R,G,B。像素格式还有很多,
比如PixelFormat24bppRGB代表24位的颜色信息,颜色组成为R,G,B,比如PixelFormat16bppRGB,代表16位的颜色信息,颜色组成为R,G,B其中R占5位,G占6位,B占5位。
Bitmap类的常用方法:
Bitmap* Clone(
[in, ref] const Rect &rect,
[in] PixelFormat format
);
Bitmap* Clone(
[in, ref] const RectF &rect,
[in] PixelFormat format
);
Bitmap* Clone(
[in] REAL x,
[in] REAL y,
[in] REAL width,
[in] REAL height,
[in] PixelFormat format
);
Bitmap* Clone(
[in] INT x,
[in] INT y,
[in] INT width,
[in] INT height,
[in] PixelFormat format
);
以上四个方法为Bitmap的拷贝方法,从源位图的指定区域拷贝出新的位图对象出来,并用format像素格式应用在新的Bitmap对象中。
UINT GetWidth(): 获取位图的宽度
UINT GetHeight():
GetPixel(INT x,INT y,Color *color);
// 获取指定位置的颜色
SetPixel(INT x,INT y,const Color &color);
常用的画刷:
1). SolidBrush: 单色画刷;
SolidBrush(const Color &color);
SolidBrush blueBrush(Color(255,0,0,255));
2). HatchBrush: 阴影画刷;
HatchBrush(
[in] HatchStyle hatchStyle,
[in, ref] const Color &foreColor,
[in, ref] const Color &backColor
);
hatchStyle:影线画刷的类型
3). TextureBrush: 纹理画刷
TextureBrush(
[in] Image *image,
[in] wrapMode wrapMode,
[in, ref] const RectF &dstRect
);
...
4). LinearGradientBrush: 线性渐变画刷
LinearGradientBrush(
[in, ref] const PointF &point1,
[in, ref] const PointF &point2,
[in, ref] const Color &color1,
[in, ref] const Color &color2
);
point1: 渐变的起点坐标;
point2: 渐变的终点坐标;
color1: 为起点的颜色
color2: 为终点的颜色
Pen创建画笔
Pen(const Color &color,REAL width=1.0f);
// color为画笔的颜色,width为画笔宽度
Pen(const Brush *brush,REAL width=1.0f);
Graphics绘制图片:
DrawImage:
Graphics::DrawImage(Image*,Point*,INT)
Graphics::DrawImage(Image*,INT,INT)
Graphics::DrawImage(Image*,Point&)
..
Graphics绘制文本:
Graphics::DrawString(WCHAR*,INT,Font*,RectF&,StringFormat*,Brush*)
Graphics::DrawString(WCHAR*,INT,Font*,PointF&,Brush*)
Graphics::DrawString(WCHAR*,INT,Font*,PointF&,StringFormat*,Brush*)
绘制文本示例代码:
{Gdiplus::Font myFont(L"Arial",10);SolidBrush brushA(Color(255,0,0,255));graphics.DrawString(L"示例文本",-1,&myFont,PointF(200,575),&brushA);
}
以下为带文本输出格式的字符串绘制代码:
{Gdiplus::Font myFont(L"Arial",16);RectF layout(0,0,500.0f,200.0f);//设置对齐方式(水平居中对齐)StringFormat format;format.SetAlignment(StringAlignmentCenter);SolidBrush brushB(Color(255,0,0,255));graphics.DrawString(L"示例文本",-1,&myFont,layout,&format,&brushB);}
MeasureString测量字符串:
Graphics::MeasureString(WCHAR*,INT,Font*,RectF&,RectF*)
Graphics::MeasureString(WCHAR*,INT,Font*,PointF&,StringFormat*,RectF*)
Graphics::MeasureString(WCHAR*,INT,Font*,RectF&,StringFormat*,RectF*,INT*,INT*)
Status MeasureString(
[in] const WCHAR *string,
[in] INT length,
[in] const Font *font,
[in, ref] const RectF &layoutRect,
[in] const StringFormat *stringFormat,
[out] RectF *boundingBox,
[out] INT *codepointsFitted,
[out] INT *linesFilled
) const;
Graphics::MeasureString(WCHAR*,INT,Font*,SizeF&,StringFormat*,SizeF*,INT*,INT*)
Status MeasureString(
[in] const WCHAR *string,
[in] INT length,
[in] const Font *font,
[in, ref] const SizeF &layoutRectSize,
[in] const StringFormat *stringFormat,
[out] SizeF *size,
[out] INT *codepointsFitted,
[out] INT *linesFilled
) const;
Graphics::MeasureString(WCHAR*,INT,Font*,PointF&,RectF*)
其中
string为要测量的字符串
length:要测量的字符串长度,-1表示测试以NULL结尾的string字符串
Font: 字符串输出采用的字体
layoutRect: 文本输出时,指定的矩形区域
layoutRectSize: 文本输出时,指定的尺寸
boundingBox为测量结果,表示容纳全部文本时,所需要的矩形区域。
size:测量结果,表示容纳全部文本时所需要的尺寸。
codepointsFitted: 测量结果,表示指定的区域中能够容纳的字符个数
linesFilled: 测量结果,表示指定的区域中,能够容纳的字符行数
origin: 文本输出起点
SetTrimming: 字符串去尾
SetTrimming(StringTrimming trimming);
StringTrimming枚举:
None
Character
Word
EllipsisCharacter
EllipsisWord
EllipsisPath
Graphics绘制直线:
Graphics::DrawLine(Pen*,Point&,Point&)
Graphics::DrawLine(Pen*,PointF&,PointF&)
Graphics::DrawLine(Pen*,REAL,REAL,REAL,REAL)
Graphics::DrawLine(Pen*,INT,INT,INT,INT)
Graphics::DrawLines(Pen*,Point*,INT)
Graphics::DrawLines(Pen*,PointF*,INT)
Graphics绘制矩形;
DrawRectangle()
Graphics绘制圆:
Graphics绘制饼:
DrawPie()
Graphics填充矩形:
FillRectangle()
FillPie()
GDI的设备描述表DC与GDI+的Graphics的作用与区别:
1).DC(设备描述表),是Windows使用的一个数据结构,用于存储具备设备能力和与如何在设备上重绘一些项目有关的属性信息。首先必须获得一个DC的句柄,如何在绘制图形时,把该句柄作为一个参数传递给GDI绘图函数。当然也可以把它传递给获得或设置DC有关属性的函数。
2). 利用GDI+函数,不必使用句柄或DC,可以简单地创建一个图形对象(Graphics),再调用它的方法,如myGraphicsObject.DrawLine(parameters).Graphics对象是GDI+的核心,正如DC是GDI的核心一样。它们在不同的环境下扮演同样的角色,发挥着类似的作用。不同之处: 前者使用基于句柄的编程方法,而后者使用面向对象的编程方法。
绘图对象的使用差别:
GDI:所有与绘图有关的绘图对象必须选入指定的设备描述表中(使用SelectObject函数),才能被指定的DC所使用。
GDI+:绘图前,把绘图对象作为参数传递给Graphics图形对象的方法调用即可。
GDI+新增的功能:
渐变的画刷:
基数样条函数
持久路径对象
变形和矩阵对象
可伸缩区域(Regions)
Alpha混合
多种图像格式支持(BMP,JPEG,PNG,GIF,TIFF)
GDI与GDI+混合编程
GDI+在GDI的设备环境DC上进行图形绘制:
Graphics gs(hDC)
GDI+就会把当前hDC作为默认的目标画布,之后调用Graphics中的任何函数都会被绘制到hDC上,当然每个函数的调用完成并不会立即反映在hDC中,只有当Graphics类析构时,才会把所有绘制的内容全部一次性拷贝到hDC中。
GDI在GDI+的绘图表面上绘图:
hDC=Graphic.GetHDC()
---------------------
本文主要解决两个问题:
1、OpenGL到底是什么鬼?
2、如何创建一个使用OpenGL的窗口?
1、OpenGL到底是什么鬼?
笔者也算是一个入门的C++程序员了,一下决心要学习OpenGL之后就直接上谷歌搜了OpenGL的官网(当然这是要翻越万里长城的),想下一个API就上手。然而在官网上溜了一大圈,楞是没找到一个下载API的地方,倒是在各种显卡厂商的官网上都转了一圈,灰头土脸。
在网上找了很多资料之后,终于明白了一点,这也是非常重要的一点,就是:OpenGL并不是一个API(API这个应该懂吧,搞编程的人都知道。什么?你说你不是搞编程的?那你看这篇文章,还不速速出门右转。)库,而是一组规范,这组规范是由Khronos Group来维护的。(别问我Khronos Group是什么鬼,对于只能写入门文字的笔者来说,这也是第一次看到。)
这组规范定义了一组函数,这组函数传入的是什么参数,传出的是什么结果。由于只是这样的一组规范,所以只要合乎规范,谁都能以不同的方式实现函数。这也就是在官网上找不到API库的原因了,通常这些API是由显卡厂商实现的。顺便说一句,如果装了VS,VS里自带有OpenGL的库(至少笔者的VS2013里有)。
状态机
OpenGL本身就是一个大状态机:有很多变量可以设置以便我们控制其操作。OpenGL的状态通常被称为上下文(context)。我们在操作OpenGL的时候就是通过改变其状态来改变其运行的上下文,这样OpenGL就能给我们想要的结果了。
2、如何创建一个使用OpenGL的窗口?
2.1 所需工具
GLFW库+VS2013+GLAD源码
扯扯这些东西都是干啥用的。
GLFW是一个开源的跨平台窗口库,它封装了与操作系统相关的创建窗口的过程,让我们的窗口创建只需要调用少量的函数就能实现。(妈妈再也不用担心我不会创建窗口了)
VS2013,额,凑个字数,你懂的
GLAD源码是用来封装调用OpenGL库中的函数的,让我们调用OpenGL函数的时候只需要用熟悉的函数调用方式,不需要创建一个函数指针,然后加载dll中的函数地址,然后再调用。说的有点抽象啊,举个例子就知道了。原本我们的代码要是这个样子:
-
typedef void (*GL_GENBUFFERS)(GLsizei, GLuint*);
-
GL_GENBUFFERS glGenBuffers = (GL_GENBUFFERS)wglGetProcAddress("glGenBuffers");
-
glGenBuffers(1, &buffer); //这里才是调用函数的位置,上面只是获取函数地址
有了GLAD源码之后,我们就只需要这样子就行了:
glGenBuffers(1,&buffer); //省去了获取函数地址的操作
2.2 环境打造:
第一步:下载GLFW
官网地址是:http://www.glfw.org/download.html(你需要翻墙才能访问)
选择下载源文件,
图片资源来源于网络
文件包名为glfw-3.2.1.zip
或者你也可以到我的百度网盘中去下载,链接:https://pan.baidu.com/s/1ceyucgFRYImnjmG-LmkuwA 密码:9smq
第二步:下载CMake,编译glfw的源码
GLFW的源码是需要通过CMake来编译的,所以我们要下载一个CMake来使用。放心,CMake的使用非常方便。
官网地址是:https://cmake.org/download/(也需要翻墙才能访问),下载最新版本3.9.3,windows 32位版本,
图片资源来源于网络
或者你也可以到我的百度网盘中去下载,链接:http://pan.baidu.com/s/1clPRIm 密码:ct24
安装完成后,打开CMake,对其进行如下设置
CMake的编译设置
将源文件的目录和要生成的编译工程文件的目录设置好,设置成相同的目录就可以了。我们将其设置成解压后的根目录。
点击左下角的Configure按钮,在弹出的窗口的选择编译器中选择“Visual Studio 12 2013”,如下图
编译器设置
点击“Finish”,在等待一段时间之后,出现如下界面
设置好编译器之后
什么都不用管,直接点击左下角的Generate按钮,非常快速的进度条之后,打开解压GLFW的目录,就能看到VS2013版本的GLFW工程了
生成好工程的状态
有些读者在编译的时候可能会出问题,笔者也不知道什么原因,在这里直接提供编译好的库供大家使用。
第三步:下载GLAD
官网地址:http://glad.dav1d.de/(继续翻),选择好需要的版本和模式
选择好要下载的版本
点击页面最下方右下角的GENERATE按钮,在随后弹出的页面中,点击glad.zip进行下载
下载zip
第四步:组装开发库目录
新建一个文件夹,取名为OpenGL,将GLFW目录中的include目录复制到OpenGL目录中去
在OpenGL文件夹下新建一个文件夹,取名为lib,将编译好的GLFW库复制到lib文件夹下,GLFW库的位置是:glfw-3.2.1\src,将里面的Debug和Release两个目录复制,拷贝到lib文件夹下。
复制glad解压文件夹中,include目录下的两个文件夹glad和KHR复制,拷贝到OpenGL目录下,include文件夹中
完成之后,我们的OpenGL文件夹下是这样子
OpenGL目录
include文件夹下是这样
include目录
lib文件夹下是这样
lib目录
第五步:创建项目,设置路径
用VS2013创建一个HelloWindow空项目工程,将glad文件夹下的glad.c文件拷贝到工程中,并将glad.c文件添加到项目中
打开项目的属性,选择VC++目录标签,设置包含目录和库目录到我们之前设置的路径下,如图
工程目录设置
注意debug是这样设置,Release的话将库目录指定到Release目录就可以了
Release目录设置
点击链接器,选择输入标签,在附加依赖项中加入opengl32.lib;glfw3.lib;两项,Debug和Release模式下名字是一样的
确定,这样我们的项目设置就完成了。
第六步:创建窗口
添加cpp文件,取名为main.cpp,在main函数中加入如下代码
主函数代码
其中framebuffer_size_callback和processInput是两个处理消息的函数
framebuffer_size_callback用于当窗口大小改变时,改变OpenGL视口的区域大小
processInput函数处理输入事件
两个函数的实现如下:
子函数代码
编译项目,运行就成功了
运行效果图
作者:闪电的蓝熊猫
链接:https://www.jianshu.com/p/d83a519ae2d0
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。
版权声明
本文为[shzwork]所创,转载请带上原文链接,感谢
https://my.oschina.net/u/4000302/blog/4708444
边栏推荐
- android开发中提示:requires permission android.permission write_settings解决方法
- The vowels in the inverted string of leetcode
- 六家公司CTO讲述曾经历的“宕机噩梦”
- 亚马逊的无服务器总线EventBridge支持事件溯源 - AWS
- 数据库设计:范式与反范式
- 非阻塞的无界线程安全队列 —— ConcurrentLinkedQueue
- Queue with two stacks
- A few lines of code can easily transfer traceid across systems, so you don't have to worry about losing the log!
- Fiddler无法正常抓取谷歌等浏览器的请求_解决方案
- Review of API knowledge
猜你喜欢
简单介绍c#通过代码开启或关闭防火墙示例
Using containers to store table data
LeetCode-15:三数之和
LeetCode-11:盛水最多的容器
Esockettimeout solution in request in nodejs
How to get started with rabbitmq
老大问我:“建表为啥还设置个自增 id ?用流水号当主键不正好么?”
First development of STC to stm32
Bifrost 之 文件队列(一)
Tips in Android Development: requires permission android.permission write_ Settings solution
随机推荐
分库分表的几种常见玩法及如何解决跨库查询等问题
Save code
使用递增计数器的线程同步工具 —— 信号量,它的原理是什么样子的?
Flink's datasource Trilogy 3: customization
23张图,带你入门推荐系统
Decorator (1)
服务网格仍然很难 - cncf
Dynamic relu: Microsoft's refreshing device may be the best relu improvement | ECCV 2020
VIM Introduction Manual, (vs Code)
What courses will AI programming learn?
一堆代码忘了缩进?快捷方式教你无忧无虑!
Exception capture and handling in C + +
How does FC game console work?
非阻塞的无界线程安全队列 —— ConcurrentLinkedQueue
App crashed inexplicably. At first, it thought it was the case of the name in the header. Finally, it was found that it was the fault of the container!
Introduction skills of big data software learning
The vowels in the inverted string of leetcode
API部分的知识点复习
大数据岗位基础要求有哪些?
云计算之路-出海记-小目标:Hello World from .NET 5.0 on AWS