QT5的QOpenGLWidget和QGLWidget有不同,将原有的继承自QGLWidget的改为QOpenGLWidget主要区别就是一些函数不能使用,要想使用opengl的一些函数需要继承QOpenGLFunctions,具体修改如下:
头文件:
#include <QOpenGLWidget>
#include <QOpenGLFunctions>
#include <QOpenGLTexture>
#include <QOpenGLShaderProgram>
typedef struct GLTexture_s {
GLuint id; // for glGenTextures
HFrame frame;
} GLTexture;
//qt opengl的封装类
//这个类主要做的是界面显示的操作,不要将业务相关(开始播放,暂停,停止等)的添加进来
//具体做法是再写一个纯业务类来处理,要处理业务时调用这个业务类的方法即可
class HGLWidget :public QOpenGLWidget,protected QOpenGLFunctions
{
Q_OBJECT
public:
HGLWidget(QWidget* parent = NULL);
void setVertices(double ratio);
void setVertices(QRect rc);
//画帧
void drawFrame(HFrame *pFrame);
//画纹理
void drawTexture(HRect rc, GLTexture *tex);
//画框
void drawRect(HRect rc, HColor clr, int line_width = 1, bool bFill = false);
//画文本
void drawText(QPoint lb, const char* text, int fontsize, QColor clr);
protected:
virtual void initializeGL();
virtual void resizeGL(int w, int h);
virtual void paintGL();
static void loadYUVShader();
//VAO(Vertex Array Object)顶点数组对象
void initVAO();
void initYUV();
//画yuv数据
void drawYUV(HFrame* pFrame);
protected:
static std::atomic_flag s_init_flag;
//无符号四字节整型,
static GLuint prog_yuv; // GLuint
static GLuint texUniformY;// GLuint
static GLuint texUniformU;//GLuint
static GLuint texUniformV;//GLuint
static QOpenGLShaderProgram m_ShaderProgram;
//编号,对应Y U V
GLuint tex_yuv[3];//GLuint
GLfloat vertices[8];//GLfloat
GLfloat textures[8];//GLfloat
// NOTE: QPainter used 3 VertexAttribArray
enum VER_ATTR{
VER_ATTR_VER = 3,
VER_ATTR_TEX,
};
};
源文件:
std::atomic_flag HGLWidget::s_init_flag = ATOMIC_FLAG_INIT;
GLuint HGLWidget::prog_yuv;
GLuint HGLWidget::texUniformY;
GLuint HGLWidget::texUniformU;
GLuint HGLWidget::texUniformV;
QOpenGLShaderProgram HGLWidget::m_ShaderProgram;
HGLWidget::HGLWidget(QWidget* parent)
:QOpenGLWidget(parent)
{
}
void HGLWidget::setVertices(double ratio)
{
double w = 1.0, h = 1.0;
if (ratio < 1.0) {
w = ratio;
}
else {
h = 1.0 / ratio;
}
GLfloat tmp[] = {
-w, -h,
w, -h,
-w, h,
w, h,
};
memcpy(vertices, tmp, sizeof(GLfloat)*8);
}
void HGLWidget::setVertices(QRect rc)
{
int wnd_w = width();
int wnd_h = height();
if (wnd_w <= 0 || wnd_h <= 0) {
return;
}
GLfloat left = (GLfloat)rc.left() * 2 / wnd_w - 1;
GLfloat right = (GLfloat)(rc.right()+1) * 2 / wnd_w - 1;
GLfloat top = 1 - (GLfloat)rc.top() * 2 / wnd_h;
GLfloat bottom = 1 - (GLfloat)(rc.bottom()+1) * 2 / wnd_h;
qDebug("l=%d r=%d t=%d b=%d", rc.left(), rc.right(), rc.top(), rc.bottom());
qDebug("l=%f r=%f t=%f b=%f", left, right, top, bottom);
GLfloat tmp[] = {
left, bottom,
right, bottom,
left, top,
right, top
};
memcpy(vertices, tmp, sizeof(GLfloat)*8);
}
//画帧
void HGLWidget::drawFrame(HFrame *pFrame)
{
if (pFrame->type == GL_I420 || pFrame->type == GL_YV12) {
drawYUV(pFrame);
}
else {
// glMatrixMode(GL_PROJECTION);
// glLoadIdentity();
// glRasterPos3f(-1.0f,1.0f,0);
// glPixelZoom(width()/(float)pFrame->w, -height()/(float)pFrame->h);
// glDrawPixels(pFrame->w, pFrame->h, pFrame->type, GL_UNSIGNED_BYTE, pFrame->buf.base);
}
}
//画纹理
void HGLWidget::drawTexture(HRect rc, GLTexture *tex)
{
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, tex->id);
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_TEXTURE_2D);
glDisable(GL_BLEND);
}
//画框
void HGLWidget::drawRect(HRect rc, HColor clr, int line_width, bool bFill)
{
}
//画文本
#include <QPainter>
void HGLWidget::drawText(QPoint lb, const char* text, int fontsize, QColor clr) {
QPainter painter(this);
QFont font = painter.font();
font.setPointSize(fontsize);
painter.setFont(font);
painter.setPen(clr);
painter.drawText(lb, text);
}
void HGLWidget::initializeGL()
{
initializeOpenGLFunctions();
glEnable(GL_DEPTH_TEST);
if (!s_init_flag.test_and_set()) {
// s_init_flag.clear();
loadYUVShader();
}
initVAO();
initYUV();
}
void HGLWidget::resizeGL(int w, int h)
{
//设置视口
glViewport(0,0,w,h);
}
void HGLWidget::paintGL()
{
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
}
void HGLWidget::loadYUVShader() {
//创建顶点着色器
QOpenGLShader VSHader(QOpenGLShader::Vertex);//, this
//顶点着色器源码
const char *vsrc = "attribute vec4 vertexIn; \
attribute vec2 textureIn; \
varying vec2 textureOut; \
void main(void) \
{ \
gl_Position = vertexIn; \
textureOut = textureIn; \
}";
//源码送入顶点着色器程序
bool bCompile = VSHader.compileSourceCode(vsrc);
if(!bCompile)
{
}
//创建片元着色器
QOpenGLShader FSHader(QOpenGLShader::Fragment);//,this
//片段着色器源码(windows下opengl es 需要加上float这句话)
const char *fsrc =
#if defined(WIN32)
"#ifdef GL_ES\n"
"precision mediump float;\n"
"#endif\n"
#else
#endif
"varying vec2 textureOut; \
uniform sampler2D tex_y; \
uniform sampler2D tex_u; \
uniform sampler2D tex_v; \
void main(void) \
{ \
vec3 yuv; \
vec3 rgb; \
yuv.x = texture2D(tex_y, textureOut).r; \
yuv.y = texture2D(tex_u, textureOut).r - 0.5; \
yuv.z = texture2D(tex_v, textureOut).r - 0.5; \
rgb = mat3( 1, 1, 1, \
0, -0.39465, 2.03211, \
1.13983, -0.58060, 0) * yuv; \
gl_FragColor = vec4(rgb, 1); \
}";
//源码送入片元着色器程序
bCompile = FSHader.compileSourceCode(fsrc);
if(!bCompile)
{
}
//创建一个新的程序
//创建着色器程序容器
//m_ShaderProgram = new QOpenGLShaderProgram;
//关联着色器
//将片段着色器添加到程序容器
m_ShaderProgram.addShader(&FSHader);
//将顶点着色器添加到程序容器
m_ShaderProgram.addShader(&VSHader);
//绑定attribute变量
//绑定属性vertexIn到指定位置ATTRIB_VERTEX,该属性在顶点着色源码其中有声明
m_ShaderProgram.bindAttributeLocation("vertexIn", VER_ATTR_VER);
//绑定属性textureIn到指定位置ATTRIB_TEXTURE,该属性在顶点着色源码其中有声明
m_ShaderProgram.bindAttributeLocation("textureIn", VER_ATTR_TEX);
//链接程序
//链接所有所有添入到的着色器程序
m_ShaderProgram.link();
//激活所有链接
m_ShaderProgram.bind();
//获取Uniform变量
//读取着色器中的数据变量tex_y, tex_u, tex_v的位置,这些变量的声明可以在
//片段着色器源码中可以看到
texUniformY =m_ShaderProgram.uniformLocation("tex_y");
texUniformU =m_ShaderProgram.uniformLocation("tex_u");
texUniformV =m_ShaderProgram.uniformLocation("tex_v");
qDebug("loadYUVShader ok");
}
//VAO(Vertex Array Object)顶点数组对象
void HGLWidget::initVAO()
{
setVertices(1.0);
GLfloat tmp[] = {
0.0f, 1.0f,
1.0f, 1.0f,
0.0f, 0.0f,
1.0f, 0.0f,
};
// reverse
/*
GLfloat tmp[] = {
0.0f, 0.0f,
1.0f, 0.0f,
0.0f, 1.0f,
1.0f, 1.0f,
};
*/
memcpy(textures, tmp, sizeof(GLfloat)*8);
glVertexAttribPointer(VER_ATTR_VER, 2, GL_FLOAT, GL_FALSE, 0, vertices);
glEnableVertexAttribArray(VER_ATTR_VER);
glVertexAttribPointer(VER_ATTR_TEX, 2, GL_FLOAT, GL_FALSE, 0, textures);
glEnableVertexAttribArray(VER_ATTR_TEX);
}
void HGLWidget::initYUV()
{
glGenTextures(3, tex_yuv);
for (int i = 0; i < 3; ++i) {
glBindTexture(GL_TEXTURE_2D, tex_yuv[i]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
}
//画yuv数据
void HGLWidget::drawYUV(HFrame* pFrame)
{
assert(pFrame->type == GL_I420 || pFrame->type == GL_YV12);
int w = pFrame->w;
int h = pFrame->h;
int y_size = w*h;
GLubyte* y = (GLubyte*)pFrame->buf.base;
GLubyte* u = y + y_size;
GLubyte* v = u + (y_size>>2);
if (pFrame->type == GL_YV12) {
GLubyte* tmp = u;
u = v;
v = tmp;
}
//使用Program
glUseProgram(prog_yuv);
m_ShaderProgram.bind();
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, tex_yuv[0]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, w, h, 0, GL_RED, GL_UNSIGNED_BYTE, y);
glUniform1i(texUniformY, 0);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, tex_yuv[1]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, w/2, h/2, 0, GL_RED, GL_UNSIGNED_BYTE, u);
glUniform1i(texUniformU, 1);
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, tex_yuv[2]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, w/2, h/2, 0, GL_RED, GL_UNSIGNED_BYTE, v);
glUniform1i(texUniformV, 2);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
//使用Program
glUseProgram(0);
}