Qt中使用GLEW进行OpenGL开发

为什么要使用GLEW

因为工作需求绘制视频,原本使用的Qt(我使用的是5.9.8的版本)自带的QOpenGL进行视频绘制,但是在稳定行测试中经常会出现界面不更新的情况。找了很久也没有好的解决方案,后来干脆使用GLEW进行OpenGL的开发。
目前Qt的OpenGL多少会存在些问题或者不完善。

使用VS创建Qt项目

1.创建一个Widget窗口即可。

#include <QtWidgets/QWidget>
#include "ui_GLEW4QT.h"

class GLEW4QT : public QWidget
{
	Q_OBJECT

public:
	GLEW4QT(QWidget *parent = Q_NULLPTR);

private:
	Ui::GLEW4QTClass ui;
};

设置Widget

GLEW4QT::GLEW4QT(QWidget *parent)
	: QWidget(parent, Qt::MSWindowsOwnDC)
{
	setAttribute(Qt::WA_PaintOnScreen);
	setAttribute(Qt::WA_NoSystemBackground);
	setAutoFillBackground(true);

	ui.setupUi(this);
}

1.在构造函数中设置一个Qt::MSWindowsOwnDC( 在窗口上为窗口提供自己的显示上下文)。
2.设置属性Qt::WA_PaintOnScreen,设置该属性后需要重新实现paintEngine函数。
3.设置Qt::WA_NoSystemBackground属性。
4.设置自动填充背景

重新实现paintEngine

直接返回NULL即可

virtual QPaintEngine* paintEngine() const { return NULL; }

添加GLEW库到工程

GLEW下载地址: 传送门
引入头文件

#define GLEW_STATIC
#include <GL/glew.h>
#include <GL/wglew.h>

#ifdef GLEW_STATIC
//使用静态库
#pragma comment(lib, "glew32s.lib")
#else
//使用动态库
#pragma comment(lib, "glew32.lib")
#endif
#pragma comment(lib, "opengl32.lib")

注意:如果使用glew静态库则需要在#include <GL/glew.h>前定义GLEW_STATIC

设置OpenGL上下文

设置GL像素格式

创建静态函数设置

/*
 * 设置GL像素格式
 */
static bool SetupPixelFormat(HDC dc)
{
	//像素格式描述符,渲染的像素格式
	PIXELFORMATDESCRIPTOR pfd;
	ZeroMemory(&pfd, sizeof(PIXELFORMATDESCRIPTOR));
	pfd.nVersion = 1;
	pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
	pfd.cColorBits = 32;
	pfd.cDepthBits = 24;
	pfd.cStencilBits = 8;
	pfd.iPixelType = PFD_TYPE_RGBA;
	pfd.iLayerType = PFD_MAIN_PLANE;
	pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;

	int pixelformat = 0;
	if ((pixelformat = ChoosePixelFormat(dc, &pfd)) == 0)
		return false;

	if (SetPixelFormat(dc, pixelformat, &pfd) == FALSE)
		return false;
	return true;
}

检测支持OpenGL的力度

这里也创建一个静态函数检测

/*
 * 检测支持OpenGL的力度
 * @param major 主版本号
 * @param minor 次版本号
 * @return -1 不支持GL, -2 glinit初始化失败, 0 支持GL, 1 支持多重采样
 */
static int CheckSupportGLLevel(int *major, int *minor)
{
	static bool checked = false;
	static int _major = 0;
	static int _minor = 0;
	static int support = 0;
	if (checked)
	{
		if (major)
			*major = _major;
		if (minor)
			*minor = _minor;
		return support;
	}
	checked = true;
	HDC dc = nullptr;
	HGLRC rc = nullptr;
	QWidget w;
	HWND hwnd = (HWND)w.winId();
	dc = GetDC(hwnd);
	if (!SetupPixelFormat(dc))
	{
		support = -1;
		goto end;
	}

	rc = wglCreateContext(dc);
	wglMakeCurrent(dc, rc);
	if (glewInit() != GLEW_OK)
	{
		support = -2;
		goto end;
	}
	glGetIntegerv(GL_MAJOR_VERSION, &_major);
	glGetIntegerv(GL_MINOR_VERSION, &_minor);
	if (wglChoosePixelFormatARB)
		support = 1;
	if (major)
		*major = _major;
	if (minor)
		*minor = _minor;
end:

	if (rc)
		wglDeleteContext(rc);
	if (dc)
		ReleaseDC(hwnd, dc);
	rc = nullptr;
	wglMakeCurrent(nullptr, nullptr);
	ReleaseDC(hwnd, dc);

	return support;
}

创建GLRC

/*
 * 创建HGLRC
 * @param dc HDC
 * @param supportMSAA 是否支持msaa
 * @param msaaLevel msaa等级 // 8, 16, 32
 * @return NULL 为失败,否则返回HGLRC
 */
static HGLRC CreateGLRC(HDC dc, bool supportMSAA, int msaaLevel)
{
	HGLRC rc;
	if (!supportMSAA)
	{
		if (!SetupPixelFormat(dc))
			return nullptr;
		rc = wglCreateContext(dc);
		return rc;
	}


	ZeroMemory(&rc, sizeof(HGLRC));
	GLint attribs[]{
		WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
		WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB,
		WGL_DOUBLE_BUFFER_ARB, GL_TRUE,
		WGL_RED_BITS_ARB, 8,
		WGL_GREEN_BITS_ARB, 8,
		WGL_BLUE_BITS_ARB, 8,
		WGL_ALPHA_BITS_ARB, 8,
		WGL_DEPTH_BITS_ARB, 24,
		WGL_STENCIL_BITS_ARB, 8,
		WGL_SAMPLE_BUFFERS_ARB, GL_TRUE,
		WGL_SAMPLES_ARB, msaaLevel,//8,16,32
		NULL,
		NULL
	};
	int pixelFormat[256] = { 0 };
	UINT formatNum = 0;
	int ret = wglChoosePixelFormatARB(dc, attribs, NULL, 256, pixelFormat, &formatNum);
	if (formatNum > 0)
	{
		PIXELFORMATDESCRIPTOR pfd;
		DescribePixelFormat(dc, pixelFormat[0], sizeof(PIXELFORMATDESCRIPTOR), &pfd);
		SetPixelFormat(dc, pixelFormat[0], &pfd);

		int contexAttributes[] = {
			WGL_CONTEXT_MAJOR_VERSION_ARB, 4,
			WGL_CONTEXT_MINOR_VERSION_ARB, 3,
			WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
			0
		};
		rc = wglCreateContextAttribsARB(dc, nullptr, contexAttributes);
	}
	return rc;
}

把当前窗口设置为OpenGL上下文

在构造函数中处理

GLEW4QT::GLEW4QT(QWidget *parent)
	: QWidget(parent, Qt::MSWindowsOwnDC)
{
	setAttribute(Qt::WA_PaintOnScreen);
	setAttribute(Qt::WA_NoSystemBackground);
	setAutoFillBackground(true);

	int major = 0, minor = 0;
	dc = GetDC((HWND)winId());
	bool supportMSAA = CheckSupportGLLevel(&major, &minor) == 1;
	rc = CreateGLRC(dc, supportMSAA, 16);
	qDebug() << "OpenGL Version:" << major << "." << minor;
	if (!wglMakeCurrent(dc, rc))
		throw;

	ui.setupUi(this);
}

也可以关闭垂直同步,让OpenGL火力全开

//是否开启垂直同步
wglSwapIntervalEXT(false);

在析构函数中要记得释放DC和RC

GLEW4QT::~GLEW4QT()
{
	wglMakeCurrent(nullptr, nullptr);
	if (rc)
		wglDeleteContext(rc);
	if (dc)
		ReleaseDC((HWND)winId(), dc);
}

绘制背景颜色

更新视口

重写resizeEvent,并更新OpenGL视口

void GLEW4QT::resizeEvent(QResizeEvent *event)
{
	glViewport(0, 0, event->size().width(), event->size().height());
}

绘制

void GLEW4QT::Renderer()
{
	glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	SwapBuffers(dc);
}

Renderer不要直接调用,我们把他放在event中调用

添加QtEvent

class QtEvent : public QEvent
{
public:
	enum Type
	{
		GL_Renderer = QEvent::User + 1,
	};
	QtEvent(Type type) : QEvent(QEvent::Type(type)) {};
};

调用绘制

bool GLEW4QT::event(QEvent *event)
{
	if (event->type() == QtEvent::GL_Renderer)
	{
		Renderer();
		return true;
	}
	return QWidget::event(event);
}

Post绘制事件

void GLEW4QT::GLUpdate()
{
	QApplication::postEvent(this, new QtEvent(QtEvent::GL_Renderer));
}

这样在需要重新绘制的地方调用GLUpdate即可

void GLEW4QT::resizeEvent(QResizeEvent *event)
{
	glViewport(0, 0, event->size().width(), event->size().height());
	GLUpdate();
}

绘制测试

通过改变颜色测试OGL环境
构造函数中添加定时器改变red值

	...
	QTimer *timer = new QTimer(this);
	connect(timer, &QTimer::timeout, [this] {
		red += 0.01f;
		if (red > 1.0f) red = 0.0f;
		GLUpdate();
	});
	timer->start(30);
	...

Renderer更新颜色值

	...
	glClearColor(red, 0.0f, 0.0f, 1.0f);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	...

测试效果
在这里插入图片描述

源码下载

如果您在测试的过程中某个环节出错了,请下载源码查看
源码链接: 传送门.

开启新征程

通过上面的一番操作就可以在Qt中使用原生的OpenGL了。

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

sttplay666

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值