Browse Source

V0.7.13
1、创建完成了动态库

Apple 1 week ago
parent
commit
6060fbad2a

+ 1 - 0
CMakeLists.txt

@@ -196,6 +196,7 @@ file(GLOB GLOBAL_SRC
 # add_subdirectory(${CMAKE_SOURCE_DIR}/demo/xlsx)
 # add_subdirectory(${CMAKE_SOURCE_DIR}/demo/DesignerPattern)
 # add_subdirectory(${CMAKE_SOURCE_DIR}/demo/ViewModel)
+add_subdirectory(${CMAKE_SOURCE_DIR}/demo/OpenGLWidget)
 add_subdirectory(${CMAKE_SOURCE_DIR}/demo/VideoPlayerGL)
 
 

+ 109 - 0
demo/OpenGLWidget/CMakeLists.txt

@@ -0,0 +1,109 @@
+cmake_minimum_required(VERSION 3.10)
+
+set(libName OpenGLWidget)
+
+
+
+#包含源文件c
+file(GLOB LOCAL_SRC
+    ${CMAKE_CURRENT_SOURCE_DIR}/*.qrc
+    ${CMAKE_CURRENT_SOURCE_DIR}/*.rc
+    ${CMAKE_CURRENT_SOURCE_DIR}/*.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/*.ui
+    ${CMAKE_CURRENT_SOURCE_DIR}/GLWidget/*.cpp
+    ${CMAKE_CURRENT_SOURCE_DIR}/GLShader/*.cpp
+
+    # ${CMAKE_SOURCE_DIR}/External/module/Logs/*.cpp
+    # ${CMAKE_SOURCE_DIR}/External/module/ThreadPool/*.cpp
+    
+)
+
+
+# 生成可执行程序
+
+add_library(${libName} SHARED
+    # WIN32
+    ${GLOBAL_SRC}
+    ${LOCAL_SRC} 
+)
+
+# set_target_properties(${this_exe} PROPERTIES
+    
+# )
+
+
+#添加头文件
+target_include_directories(${libName} PRIVATE
+
+    ${CMAKE_CURRENT_SOURCE_DIR}
+
+    ${CMAKE_SOURCE_DIR}/External/common
+    ${CMAKE_SOURCE_DIR}/External/module
+    # ${CMAKE_SOURCE_DIR}/External/module/ThreadPool
+    # ${CMAKE_SOURCE_DIR}/External/module/RingQueue
+
+    ${CMAKE_CURRENT_SOURCE_DIR}/GLWidget
+    ${CMAKE_CURRENT_SOURCE_DIR}/GLShader
+    
+    # ${CURL_INCLUDE_DIR}
+    # ${FFMPEG_INCLUDE_DIR}
+    ${spdlog_INCLUDE_DIR}
+)
+
+
+target_link_libraries(${libName} PRIVATE
+    Qt${QT_VERSION_MAJOR}::Widgets
+    Qt${QT_VERSION_MAJOR}::Core
+
+)
+
+if(QT_VERSION_MAJOR EQUAL 5)
+    target_link_libraries(${libName} PRIVATE
+        Qt5::OpenGL
+    )
+elseif(QT_VERSION_MAJOR EQUAL 6)
+    target_link_libraries(${libName} PRIVATE
+        Qt6::OpenGLWidgets
+    )
+endif(QT_VERSION_MAJOR EQUAL 5)
+
+if(CMAKE_SYSTEM_NAME MATCHES "Windows")
+    target_link_libraries(${libName} PRIVATE 
+        # ${CURL_LIBRARY}
+        # ${FFMPEG_LIBRARY}
+        ${spdlog_LIBRARY}
+        opengl32
+    )
+elseif(CMAKE_SYSTEM_NAME MATCHES "Linux")
+    target_link_libraries(${libName} PRIVATE 
+        ${spdlog_LIBRARY}
+        GL
+    )
+endif()
+
+# if(CMAKE_CXX_COMPILER_VERSION LESS 9.0)
+#     target_link_libraries(${this_exe} PRIVATE
+#         stdc++fs
+#     )
+# endif()
+
+
+
+# target_link_libraries(${this_exe} PRIVATE
+#     GL
+#     GUL
+# )
+# message(STATUS "CURL_LIBRARY: ${CURL_LIBRARY}")
+
+
+# if(CMAKE_CXX_COMPILER_ID MATCHES MSVC)
+#     target_link_libraries(${this_exe} PRIVATE
+#         # debug spdlogd.lib
+#         # optimized spdlog.lib
+#     )
+# elseif(CMAKE_CXX_COMPILER_ID MATCHES GNU)
+#     target_link_libraries(${this_exe} PRIVATE
+#         # debug 
+#         # optimized ${SM_DLL}
+#     )
+# endif()

+ 294 - 0
demo/OpenGLWidget/GLShader/ShaderBase.cpp

@@ -0,0 +1,294 @@
+#include "ShaderBase.h"
+
+#include <QString>
+#include <QImage>
+#include <QFile>
+
+#include <QOpenGLWidget>
+#include <QOpenGLFunctions_3_3_Core>
+#include <QTextStream>
+
+#include "spdlog/spdlog.h"
+
+
+ShaderBase::ShaderBase()
+{
+}
+
+ShaderBase::~ShaderBase()
+{
+    clearTexture();
+    
+    if(m_shaderProgramObj != nullptr) {
+        delete m_shaderProgramObj;
+        m_shaderProgramObj = nullptr;
+    }
+}
+
+
+/* 初始化Shader,第一个是定点着色器,第二个是片段着色器 */
+bool ShaderBase::loadShaderCode(const QString &vertexShaderFile, const QString &fragmentShaderFile)
+{
+    if(vertexShaderFile.isEmpty() || fragmentShaderFile.isEmpty()) 
+    {
+        SPDLOG_ERROR("顶点着色器或片段着色器文件为空");
+        return false;
+    }
+    /* 打开文件 */
+    QFile vertexFile(vertexShaderFile);
+    if (!vertexFile.open(QIODevice::ReadOnly)) 
+    {
+        SPDLOG_ERROR("Failed to open vertex shader file: {}", vertexShaderFile.toStdString());
+        return false;
+    }
+    m_vertexShaderCode = vertexFile.readAll();
+    vertexFile.close();
+
+    if (m_vertexShaderCode.isEmpty()) 
+    {
+        SPDLOG_ERROR("Vertex shader file is empty: {}", vertexShaderFile.toStdString());
+        return false;
+    }
+    /* 打开文件 */
+    QFile fragmentFile(fragmentShaderFile);
+    if (!fragmentFile.open(QIODevice::ReadOnly)) 
+    {
+        SPDLOG_ERROR("Failed to open fragment shader file: {}", fragmentShaderFile.toStdString());
+        return false;
+    }
+    m_fragmentShaderCode = fragmentFile.readAll();
+    fragmentFile.close();
+    if (m_fragmentShaderCode.isEmpty()) 
+    {
+        SPDLOG_ERROR("Fragment shader file is empty: {}", fragmentShaderFile.toStdString());
+        return false;
+    }
+
+    return true;
+}
+
+
+/* 编译着色器程序 */
+bool ShaderBase::compileShader()
+{
+    if(m_vertexShaderCode.isEmpty() || m_fragmentShaderCode.isEmpty()) {
+        SPDLOG_ERROR("顶点着色器或片段着色器文件为空");
+        return false;
+    }
+    /* 编译顶点着色器 */
+    QOpenGLShader* vertexShader = new QOpenGLShader(QOpenGLShader::Vertex);
+    if(!vertexShader->compileSourceCode(m_vertexShaderCode))
+    {
+        SPDLOG_ERROR("编译顶点着色器错误: {}", vertexShader->log().toStdString());
+        return false;
+    }
+    /* 编译片段着色器 */
+    QOpenGLShader* fragmentShader = new QOpenGLShader(QOpenGLShader::Fragment);
+    if(!fragmentShader->compileSourceCode(m_fragmentShaderCode))
+    {
+        SPDLOG_ERROR("编译片段着色器错误: {}", fragmentShader->log().toStdString());
+        return false;
+    }
+
+    /* 创建着色器程序对象 */
+    m_shaderProgramObj = new QOpenGLShaderProgram();
+    /* 添加顶点着色器和片段着色器 */
+    m_shaderProgramObj->addShader(vertexShader);
+    m_shaderProgramObj->addShader(fragmentShader);
+    /* 链接着色器程序 */
+    if (!m_shaderProgramObj->link()) {
+        SPDLOG_ERROR("Failed to link shader program: {}", m_shaderProgramObj->log().toStdString());
+        return false;
+    }
+    /* 检查链接错误 */
+    if (m_shaderProgramObj->log().contains("ERROR")) {
+        SPDLOG_ERROR("Shader program link error: {}", m_shaderProgramObj->log().toStdString());
+        return false;
+    }
+    /* 删除着色器对象 */
+    delete vertexShader;
+    vertexShader = nullptr;
+    delete fragmentShader;
+    fragmentShader = nullptr;
+
+    return true;
+}
+
+/**
+ * @brief 创建纹理,可以显式的指定纹理单元编号,返回纹理单元编号,创建失败则返回的是
+ * 
+ * @param uniformName 
+ * @param textureUnit 如果不指定或者小于0,则会自动分配纹理单元编号
+ * @return int -1,创建失败,>0,创建成功
+ */
+int ShaderBase::createTexture(const QString uniformName, int textureUnit)
+{
+    GLint maxTextureUnits = 0;
+    glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &maxTextureUnits);
+    if(textureUnit > maxTextureUnits) 
+    {
+        SPDLOG_ERROR("纹理单元编号:{}已超过支持的最大单元数目:{}", textureUnit, maxTextureUnits);
+        return -1;
+    }
+    /* 制定了单元编号,先查重 */
+    int texUnit = textureUnit;
+    if(texUnit >= 0)
+    {
+        for(auto it = m_mapTexture.begin(); it != m_mapTexture.end(); ++it) 
+        {
+            if(it.key() == texUnit) 
+            {
+                if(it->first == uniformName) 
+                {
+                    SPDLOG_WARN("纹理单元编号:{},名称:{} 已存在", texUnit, uniformName.toStdString());
+                    return texUnit;
+                } else 
+                {
+                    /* 删除该纹理单元 */
+                    SPDLOG_WARN("纹理单元编号:{},名称:{} 已存在,将被替换为名称:{}", texUnit, it->first.toStdString(), uniformName.toStdString());
+                    if(it->second != nullptr) 
+                    {
+                        it->second->destroy();
+                        delete it->second;
+                        it->second = nullptr;
+                    }
+                    m_mapTexture.erase(it); // 删除该纹理单元
+                    break; // 退出循环
+                }
+            }
+        }
+    }else 
+    {
+        /* 没有分配编号,手动分配 */
+        texUnit = 0;
+        for(int i = 0; i < m_mapTexture.size(); i++)
+        {
+            if(!m_mapTexture.contains(i))
+            {
+                texUnit = i;
+                break;
+            }
+        }
+    }
+
+    QOpenGLTexture* texture = new QOpenGLTexture(QOpenGLTexture::Target2D);
+    /* 设置纹理参数 */
+    texture->setWrapMode(QOpenGLTexture::Repeat); // S轴环绕方式
+    texture->setMinificationFilter(QOpenGLTexture::LinearMipMapLinear); // 纹理缩小过滤方式
+    texture->setMagnificationFilter(QOpenGLTexture::Linear); // 纹理放大过滤方式
+    
+
+    printGLerror("ShaderBase::createTextureFile");
+    /* 将纹理存储到数组中 */
+    m_mapTexture.insert(texUnit, QPair<QString, QOpenGLTexture*>(uniformName, texture));
+
+    return texUnit;
+}
+
+// /* 初始化纹理,直接传入图片 */
+// bool ShaderBase::createTexture(const QImage &image, const QString uniformName)
+// {
+//     if(image.isNull()) {
+//         SPDLOG_WARN("Texture Image is null");
+//         return false;
+//     }
+//     QOpenGLTexture* texture = new QOpenGLTexture(QOpenGLTexture::Target2D);
+//     texture->setSize(image.width(), image.height(), 1); // 设置纹理大小
+//     texture->setFormat(QOpenGLTexture::RGBA8_UNorm); // 设置纹理格式
+//     texture->allocateStorage(); // 分配纹理存储空间
+//     texture->setData(QOpenGLTexture::RGBA, QOpenGLTexture::UInt8, image.convertToFormat(QImage::Format_RGBA8888).bits()); // 设置纹理数据
+//     /* 设置纹理参数 */
+//     texture->setWrapMode(QOpenGLTexture::Repeat); // S轴环绕方式
+//     texture->setMinificationFilter(QOpenGLTexture::LinearMipMapLinear); // 纹理缩小过滤方式
+//     texture->setMagnificationFilter(QOpenGLTexture::Linear); // 纹理放大过滤方式
+    
+    
+//     texture->generateMipMaps(); // 生成多级渐远纹理
+
+//     printGLerror("ShaderBase::createTextureImage");
+//     /* 将纹理存储到数组中 */
+//     m_listTexture.push_back(QPair<QString, QOpenGLTexture*>(uniformName, texture));
+
+//     return true;
+// }
+
+/* 清空纹理 */
+void ShaderBase::clearTexture()
+{
+    for(auto& it : m_mapTexture) 
+    {
+        if(it.second != nullptr) 
+        {
+            it.second->destroy();
+            delete it.second;
+            it.second = nullptr;
+        }
+    }
+    m_mapTexture.clear();
+}
+
+/* 使用着色器 */
+void ShaderBase::useShader()
+{
+    if (m_shaderProgramObj == nullptr) {
+        SPDLOG_ERROR("Shader program object is null");
+        return;
+    }
+    /* 使用着色器程序 */
+    m_shaderProgramObj->bind();
+    /* 使用纹理 */
+    if(m_mapTexture.size() > 0) 
+    {
+        for (auto it = m_mapTexture.begin(); it != m_mapTexture.end(); ++it) 
+        {
+            it->second->bind(it.key());
+            /* 绑定纹理 */
+            int location = m_shaderProgramObj->uniformLocation(it->first);
+            if (location < 0) {
+                SPDLOG_ERROR("Failed to get uniform location for texture: {}", it->first.toStdString());
+                continue;
+            }
+            /* 设置纹理单元 */
+            m_shaderProgramObj->setUniformValue(location, it.key()); 
+        }
+    }
+}
+
+/* 打印OpenGL错误 */
+void ShaderBase::printGLerror(const std::string functionName)
+{
+    GLenum error = glGetError();
+    if (error == GL_NO_ERROR) {
+        return;
+    }
+
+    /* 打印出字符串 */
+    std::string errorString;
+    switch (error) 
+    {
+        case GL_INVALID_ENUM:
+            errorString = "GL_INVALID_ENUM";
+            break;
+        case GL_INVALID_VALUE:
+            errorString = "GL_INVALID_VALUE";
+            break;
+        case GL_INVALID_OPERATION:
+            errorString = "GL_INVALID_OPERATION";
+            break;
+        case GL_STACK_OVERFLOW:
+            SPDLOG_ERROR("GL_STACK_OVERFLOW");
+            break;
+        case GL_STACK_UNDERFLOW:
+            SPDLOG_ERROR("GL_STACK_UNDERFLOW");
+            break;
+        case GL_OUT_OF_MEMORY:
+            SPDLOG_ERROR("GL_OUT_OF_MEMORY");
+            break;
+        default:
+            SPDLOG_ERROR("Unknown OpenGL error: 0x{:X}", error);
+            break;
+    }
+    SPDLOG_ERROR("OpenGL error in {}: 0x{:X}, {}", functionName, error, errorString);
+    
+}
+

+ 55 - 0
demo/OpenGLWidget/GLShader/ShaderBase.h

@@ -0,0 +1,55 @@
+#ifndef SHADERBASE_H
+#define SHADERBASE_H
+
+#include "GL/gl.h"
+#include <QList>
+#include <QOpenGLTexture>
+#include <QOpenGLShader>
+
+class QString;
+class QImage;
+
+
+
+class ShaderBase
+{
+
+public:
+    ShaderBase();
+    virtual ~ShaderBase();
+
+    /* 初始化形状 */
+    virtual GLuint initShape() = 0;
+    /* 初始化纹理对象 */
+    virtual bool initTextures() = 0;
+    /* 绘制图形 */
+    virtual void drawShape() = 0;
+
+    /* 初始化Shader,第一个是定点着色器,第二个是片段着色器 */
+    virtual bool loadShaderCode(const QString &vertexShaderFile, const QString &fragmentShaderFile);
+    /* 编译着色器程序 */
+    virtual bool compileShader();
+    /* 创建纹理,可以显式的指定纹理单元编号,返回纹理单元编号,创建失败则返回的是-1 */
+    virtual int createTexture(const QString uniformName, int textureUnit = -1);
+    /* 清空纹理 */
+    virtual void clearTexture();
+
+    /* 使用着色器 */
+    virtual void useShader();
+    
+
+protected:
+    /* 打印OpenGL错误 */
+    void printGLerror(const std::string functionName);
+
+protected:
+    QByteArray m_vertexShaderCode;                          /* 顶点着色器文件 */
+    QByteArray m_fragmentShaderCode;                        /* 片段着色器文件 */
+    QOpenGLShaderProgram* m_shaderProgramObj = nullptr;     /* 着色器程序对象 */
+    
+    // QList<QPair<QString, QOpenGLTexture*>> m_listTexture;   /* uniform和纹理的映射 */
+    QMap<int, QPair<QString, QOpenGLTexture*>> m_mapTexture; /* uniform和纹理的映射,int是第几个,与 GL_TEXTURE0 相对应 */
+};
+
+
+#endif // SHADERBASE_H

+ 154 - 0
demo/OpenGLWidget/GLShader/ShaderRect.cpp

@@ -0,0 +1,154 @@
+#include "ShaderRect.h"
+
+#include <QOpenGLWidget>
+#include <QOpenGLFunctions_3_3_Core>
+#include <GL/gl.h>
+
+#include "spdlog/spdlog.h"
+
+ShaderRect::ShaderRect()
+{
+
+}
+
+ShaderRect::~ShaderRect()
+{
+    QOpenGLFunctions_3_3_Core *gl = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_3_3_Core>();
+    if (m_VAO != 0) {
+        if (gl) {
+            gl->glDeleteVertexArrays(1, &m_VAO);
+            gl->glDeleteBuffers(1, &m_VBO);
+            gl->glDeleteBuffers(1, &m_EBO);
+        }
+    }
+
+}
+
+/* 初始化形状 */
+GLuint ShaderRect::initShape()
+{
+    const int vertexCount = 4;    // 顶点数量
+    const int vertexSize = 8;     // 顶点大小
+    /* 矩形位置,铺满屏幕 */
+    float vertices [vertexCount * vertexSize] {
+        /* ----- 位置 -----|-------- 颜色 ----------|----- 纹理坐标 ------ */
+        -1.0f, -1.0f, 0.0f,     1.0f, 1.0f, 0.0f,   0.0f, 0.0f,     // 左下
+        1.0f, -1.0f, 0.0f,      0.0f, 0.0f, 1.0f,   1.0f, 0.0f,     // 右下
+        1.0f,  1.0f, 0.0f,      1.0f, 0.0f, 0.0f,   1.0f, 1.0f,     // 右上
+        -1.0f, 1.0f, 0.0f,      0.0f, 1.0f, 0.0f,   0.0f, 1.0f      // 右上
+    };
+    const int indexCount = 6; // 索引数量
+    /* 顶点顺序 */
+    uint32_t indices [indexCount] {
+        0, 1, 2, // 第一个三角形
+        2, 3, 0  // 第二个三角形
+    };
+
+    QOpenGLFunctions_3_3_Core *gl = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_3_3_Core>();
+    if (!gl) {
+        SPDLOG_ERROR("Failed to get OpenGL functions");
+        return 0;
+    }
+    /* -------------------------------------------------------------------------------------
+     * 顶点数组对象
+     * ------------------------------------------------------------------------------------ */
+    gl->glGenVertexArrays(1, &m_VAO); // 生成一个VAO,返回的ID存储在VAO1中
+    gl->glBindVertexArray(m_VAO); // 绑定VAO
+
+    /* -------------------------------------------------------------------------------------
+     * 创建顶点数组缓冲区
+     * ------------------------------------------------------------------------------------ */
+    gl->glGenBuffers(1, &m_VBO);
+    gl->glBindBuffer(GL_ARRAY_BUFFER, m_VBO); // 绑定VBO
+    gl->glBufferData(GL_ARRAY_BUFFER, vertexCount * vertexSize * sizeof(float), vertices, GL_STATIC_DRAW);
+
+    /* -------------------------------------------------------------------------------------
+     * 创建EBO
+     * ------------------------------------------------------------------------------------ */
+    gl->glGenBuffers(1, &m_EBO);
+    gl->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_EBO);
+    gl->glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexCount * sizeof(uint32_t), indices, GL_STATIC_DRAW); // 绑定EBO
+
+
+    /* -------------------------------------------------------------------------------------
+     * 链接顶点属性
+     * ------------------------------------------------------------------------------------ */
+    // 设置顶点属性指针,告诉OpenGL如何解析顶点数据
+    gl->glVertexAttribPointer(
+                    0,                  /* 顶点属性位置,0表示第一个属性 */
+                    3,                  /* 每个顶点属性的大小,这里是3,表示x、y、z坐标 */
+                    GL_FLOAT, GL_FALSE, /* 数据类型和是否标准化 */
+                    vertexSize * sizeof(float), /* 步长,表示每个顶点属性之间的间隔 */
+                    (void*)0            /* 偏移量,表示该属性(顶点坐标)从第0个字节开始 */
+                ); 
+    /* 启用顶点属性 */
+    gl->glEnableVertexAttribArray(0);
+ 
+    // 设置颜色位置,最后一个参数表示从第3个字节开始,倒数第二个参数是两个数据之间起始位置间隔8个字节
+    gl->glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, vertexSize * sizeof(float), (void*)(3*sizeof(float))); 
+    gl->glEnableVertexAttribArray(1);
+ 
+    /* 设置纹理位置 */
+    gl->glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, vertexSize * sizeof(float), (void*)(6*sizeof(float))); // 纹理坐标位置
+    gl->glEnableVertexAttribArray(2); // 启用纹理坐标属性
+
+    return m_VAO;
+}
+
+/* 绘制图形 */
+void ShaderRect::drawShape()
+{
+    QOpenGLFunctions_3_3_Core *gl = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_3_3_Core>();
+    /* 需要在使用时手动绑定VAO,绘制图形 */
+    gl->glBindVertexArray(m_VAO); // 绑定VAO
+
+    gl->glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); // 绘制四边形
+
+    gl->glBindVertexArray(0); // 解绑VAO
+}
+
+/* 初始化纹理对象 */
+bool ShaderRect::initTextures()
+{
+    /* 创建一个纹理对象 */
+    auto unit = createTexture(m_textureRGBAName);
+    if(unit < 0)
+    {
+        SPDLOG_ERROR("RGBA着色器创建纹理失败!");
+        return false;
+    }
+
+    return true;
+}
+
+/* 刷新一帧 */
+bool ShaderRect::refreshFrameRGBA(const QImage& image, int textureUnit)
+{
+    if(image.isNull()) {
+        SPDLOG_WARN("Texture Image is null");
+        return false;
+    }
+    QOpenGLTexture* texture = m_mapTexture.find(textureUnit)->second;
+    if(texture == nullptr)
+    {
+        SPDLOG_ERROR("错误的纹理编号:{}", textureUnit);
+        return false;
+    }
+    if(m_lastSize != image.size())
+    {
+        texture->destroy();   // 释放OpenGL资源
+        texture->create();    // 重新创建OpenGL资源
+        texture->setSize(image.width(), image.height(), 1); // 设置纹理大小
+        texture->setFormat(QOpenGLTexture::RGBA8_UNorm); // 设置纹理格式
+        texture->allocateStorage(); // 分配纹理存储空间
+    }
+    m_lastSize = image.size();
+    texture->setData(QOpenGLTexture::RGBA, QOpenGLTexture::UInt8, image.bits()); // 设置纹理数据
+
+    texture->generateMipMaps(); // 生成多级渐远纹理
+
+    printGLerror("ShaderRect::refreshFrame");
+
+    return true;
+}
+

+ 38 - 0
demo/OpenGLWidget/GLShader/ShaderRect.h

@@ -0,0 +1,38 @@
+#ifndef SHADERRECT_H
+#define SHADERRECT_H
+
+#include "ShaderBase.h"
+
+/**
+ * @brief 显示矩形RGBA图片
+ * 
+ */
+
+
+class ShaderRect : public ShaderBase
+{
+public:
+    ShaderRect();
+    ~ShaderRect();
+
+    /* 初始化形状 */
+    GLuint initShape() override;
+    /* 初始化纹理对象 */
+    bool initTextures() override;
+    /* 绘制图形 */
+    void drawShape() override;
+
+    /* 刷新一帧 */
+    bool refreshFrameRGBA(const QImage& image, int textureUnit = 0);
+
+private:
+    GLuint m_VAO = 0;              // 顶点数组对象的ID
+    GLuint m_VBO = 0;              // 顶点缓冲对象的ID
+    GLuint m_EBO = 0;              // 索引缓冲对象的ID
+    QSize m_lastSize;               /* 上一张图片的大小 */
+
+    const QString m_textureRGBAName = "textureRGBA"; // RGBA纹理名称
+};
+
+
+#endif // SHADERRECT_H

+ 282 - 0
demo/OpenGLWidget/GLShader/ShaderYUV420.cpp

@@ -0,0 +1,282 @@
+#include "ShaderYUV420.h"
+
+
+#include <QOpenGLWidget>
+#include <QOpenGLFunctions_3_3_Core>
+
+#include "spdlog/spdlog.h"
+
+Image_YUV420::Image_YUV420(Image_YUV420&& other): width(other.width), height(other.height),
+          yData(std::move(other.yData)), uData(std::move(other.uData)), vData(std::move(other.vData))
+{}
+
+Image_YUV420::Image_YUV420(const Image_YUV420& other)
+        : width(other.width), height(other.height),
+          yData(other.yData), uData(other.uData), vData(other.vData)
+{}
+
+Image_YUV420& Image_YUV420::operator=(Image_YUV420&& other) 
+{
+    if (this != &other) {
+        width = other.width;
+        height = other.height;
+        yData = std::move(other.yData);
+        uData = std::move(other.uData);
+        vData = std::move(other.vData);
+    }
+    return *this;
+}
+Image_YUV420& Image_YUV420::operator=(const Image_YUV420& other) 
+{
+    if (this != &other) {
+        width = other.width;
+        height = other.height;
+        yData = other.yData;
+        uData = other.uData;
+        vData = other.vData;
+    }
+    return *this;
+}
+
+bool Image_YUV420::isValid() const 
+{
+    return width > 0 && height > 0 && !yData.isEmpty() && !uData.isEmpty() && !vData.isEmpty();
+}
+
+void Image_YUV420::clear()
+{
+    width = 0;
+    height = 0;
+    yData.clear();
+    uData.clear();
+    vData.clear();
+}
+
+
+ShaderYUV420::ShaderYUV420()
+{
+
+}
+ShaderYUV420::~ShaderYUV420()
+{
+    QOpenGLFunctions_3_3_Core *gl = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_3_3_Core>();
+    if (m_VAO != 0) {
+        if (gl) {
+            gl->glDeleteVertexArrays(1, &m_VAO);
+            gl->glDeleteBuffers(1, &m_VBO);
+            gl->glDeleteBuffers(1, &m_EBO);
+        }
+    }
+}
+
+/* 初始化形状 */
+GLuint ShaderYUV420::initShape()
+{
+    const int vertexCount = 4;    // 顶点数量
+    const int vertexSize = 8;     // 顶点大小
+    /* 矩形位置,铺满屏幕 */
+    float vertices [vertexCount * vertexSize] {
+        /* ----- 位置 -----|-------- 颜色 ----------|----- 纹理坐标 ------ */
+        -1.0f, -1.0f, 0.0f,     1.0f, 1.0f, 0.0f,   0.0f, 0.0f,     // 左下
+        1.0f, -1.0f, 0.0f,      0.0f, 0.0f, 1.0f,   1.0f, 0.0f,     // 右下
+        1.0f,  1.0f, 0.0f,      1.0f, 0.0f, 0.0f,   1.0f, 1.0f,     // 右上
+        -1.0f, 1.0f, 0.0f,      0.0f, 1.0f, 0.0f,   0.0f, 1.0f      // 右上
+    };
+    const int indexCount = 6; // 索引数量
+    /* 顶点顺序 */
+    uint32_t indices [indexCount] {
+        0, 1, 2, // 第一个三角形
+        2, 3, 0  // 第二个三角形
+    };
+
+    QOpenGLFunctions_3_3_Core *gl = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_3_3_Core>();
+    if (!gl) {
+        SPDLOG_ERROR("Failed to get OpenGL functions");
+        return 0;
+    }
+    /* -------------------------------------------------------------------------------------
+     * 顶点数组对象
+     * ------------------------------------------------------------------------------------ */
+    gl->glGenVertexArrays(1, &m_VAO); // 生成一个VAO,返回的ID存储在VAO1中
+    gl->glBindVertexArray(m_VAO); // 绑定VAO
+
+    /* -------------------------------------------------------------------------------------
+     * 创建顶点数组缓冲区
+     * ------------------------------------------------------------------------------------ */
+    gl->glGenBuffers(1, &m_VBO);
+    gl->glBindBuffer(GL_ARRAY_BUFFER, m_VBO); // 绑定VBO
+    gl->glBufferData(GL_ARRAY_BUFFER, vertexCount * vertexSize * sizeof(float), vertices, GL_STATIC_DRAW);
+
+    /* -------------------------------------------------------------------------------------
+     * 创建EBO
+     * ------------------------------------------------------------------------------------ */
+    gl->glGenBuffers(1, &m_EBO);
+    gl->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_EBO);
+    gl->glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexCount * sizeof(uint32_t), indices, GL_STATIC_DRAW); // 绑定EBO
+
+
+    /* -------------------------------------------------------------------------------------
+     * 链接顶点属性
+     * ------------------------------------------------------------------------------------ */
+    // 设置顶点属性指针,告诉OpenGL如何解析顶点数据
+    gl->glVertexAttribPointer(
+                    0,                  /* 顶点属性位置,0表示第一个属性 */
+                    3,                  /* 每个顶点属性的大小,这里是3,表示x、y、z坐标 */
+                    GL_FLOAT, GL_FALSE, /* 数据类型和是否标准化 */
+                    vertexSize * sizeof(float), /* 步长,表示每个顶点属性之间的间隔 */
+                    (void*)0            /* 偏移量,表示该属性(顶点坐标)从第0个字节开始 */
+                ); 
+    /* 启用顶点属性 */
+    gl->glEnableVertexAttribArray(0);
+ 
+    // 设置颜色位置,最后一个参数表示从第3个字节开始,倒数第二个参数是两个数据之间起始位置间隔8个字节
+    gl->glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, vertexSize * sizeof(float), (void*)(3*sizeof(float))); 
+    gl->glEnableVertexAttribArray(1);
+ 
+    /* 设置纹理位置 */
+    gl->glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, vertexSize * sizeof(float), (void*)(6*sizeof(float))); // 纹理坐标位置
+    gl->glEnableVertexAttribArray(2); // 启用纹理坐标属性
+
+    return m_VAO;
+}
+
+/* 初始化纹理对象 */
+bool ShaderYUV420::initTextures()
+{
+    int unit = 0;
+    unit = createTexture(m_textureYName, 0);
+    if(unit < 0) {
+        SPDLOG_ERROR("Failed to create Y texture");
+        return false;
+    }
+    unit = createTexture(m_textureUName, 1);
+    if(unit < 0) {
+        SPDLOG_ERROR("Failed to create U texture");
+        return false;
+    }
+    unit = createTexture(m_textureVName, 2);
+    if(unit < 0) {
+        SPDLOG_ERROR("Failed to create V texture");
+        return false;
+    }
+
+    return true;
+}
+
+/* 绘制图形 */
+void ShaderYUV420::drawShape()
+{
+    QOpenGLFunctions_3_3_Core *gl = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_3_3_Core>();
+    /* 需要在使用时手动绑定VAO,绘制图形 */
+    gl->glBindVertexArray(m_VAO); // 绑定VAO
+
+    gl->glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); // 绘制四边形
+
+    gl->glBindVertexArray(0); // 解绑VAO
+}
+
+/* 刷新一帧 */
+bool ShaderYUV420::refreshFrameYUV420(const Image_YUV420& yuvData)
+{
+    if (!yuvData.isValid()) {
+        SPDLOG_ERROR("Invalid YUV420 data");
+        return false;
+    }
+    QOpenGLTexture *textureY = m_mapTexture.find(0)->second;
+    QOpenGLTexture *textureU = m_mapTexture.find(1)->second;
+    QOpenGLTexture *textureV = m_mapTexture.find(2)->second;
+
+    if(textureY == nullptr || textureU == nullptr || textureV == nullptr) {
+        SPDLOG_ERROR("Failed to get YUV textures");
+        return false;
+    }
+
+    if(yuvData.width != m_lastYUVSize.width() || yuvData.height != m_lastYUVSize.height()) 
+    {
+        /* 如果YUV数据的大小发生变化,则需要重新创建纹理 */
+        textureY->destroy();
+        textureU->destroy();
+        textureV->destroy();
+        textureY->create();
+        textureU->create();
+        textureV->create();
+
+        textureY->setSize(yuvData.width, yuvData.height, 1); // 设置Y分量纹理大小
+        textureY->setFormat(QOpenGLTexture::R8_UNorm); // 设置Y分量纹理格式
+        textureY->allocateStorage(); // 分配Y分量纹理存储空间
+        
+        textureU->setSize(yuvData.width / 2, yuvData.height / 2, 1); // 设置U分量纹理大小
+        textureU->setFormat(QOpenGLTexture::R8_UNorm); // 设置U分量纹理格式
+        textureU->allocateStorage(); // 分配U分量纹理存储空间
+
+        textureV->setSize(yuvData.width / 2, yuvData.height / 2, 1); // 设置V分量纹理大小
+        textureV->setFormat(QOpenGLTexture::R8_UNorm); // 设置V分量纹理格式
+        textureV->allocateStorage(); // 分配V分量纹理存储空间
+
+        m_lastYUVSize = QSize(yuvData.width, yuvData.height);
+    }
+
+    /* 设置Y分量纹理 */
+    textureY->setData(QOpenGLTexture::Red, QOpenGLTexture::UInt8, yuvData.yData.constData());
+    textureY->generateMipMaps(); // 生成多级渐远纹理
+
+    /* 设置U分量纹理 */
+    textureU->setData(QOpenGLTexture::Red, QOpenGLTexture::UInt8, yuvData.uData.constData());
+    textureU->generateMipMaps(); // 生成多级渐远纹理
+
+    /* 设置V分量纹理 */
+    textureV->setData(QOpenGLTexture::Red, QOpenGLTexture::UInt8, yuvData.vData.constData());
+    textureV->generateMipMaps(); // 生成多级渐远纹理
+
+    printGLerror("ShaderYUV420::refreshFrameYUV420");
+
+    return true;
+}
+
+/* 刷新一帧 */
+bool ShaderYUV420::refreshFrameRGBA(const QImage& image, int textureUnit)
+{
+    m_yuvData.clear(); // 清空YUV数据
+    convertRGBAToYUV420(image, m_yuvData);
+    
+    refreshFrameYUV420(m_yuvData);
+    return true;
+}
+
+/* RGBA转换成YUV420 */
+bool ShaderYUV420::convertRGBAToYUV420(const QImage& image, Image_YUV420& yuvData)
+{
+    int width = image.width();
+    int height = image.height();
+    const int ySize = yuvData.width * yuvData.height;
+    const int uvSize = ySize / 4;
+
+    QImage image_rgb(width, height, QImage::Format_RGB888);
+
+    yuvData.width = width;
+    yuvData.height = height;
+
+    yuvData.yData.resize(ySize);
+    yuvData.uData.resize(uvSize);
+    yuvData.vData.resize(uvSize);
+
+    for (int y = 0; y < height; ++y) {
+        for (int x = 0; x < width; ++x) {
+            QColor color = image.pixelColor(x, y);
+            int r = color.red();
+            int g = color.green();
+            int b = color.blue();
+
+            int yIndex = y * width + x;
+            yuvData.yData[yIndex] = static_cast<unsigned char>((0.257 * r) + (0.504 * g) + (0.098 * b) + 16);
+
+            if (y % 2 == 0 && x % 2 == 0) {
+                int uvIndex = (y / 2) * (width / 2) + (x / 2);
+                yuvData.uData[uvIndex] = static_cast<unsigned char>((-0.148 * r) - (0.291 * g) + (0.439 * b) + 128);
+                yuvData.vData[uvIndex] = static_cast<unsigned char>((0.439 * r) - (0.368 * g) - (0.071 * b) + 128);
+            }
+        }
+    }
+
+    return true;
+}

+ 62 - 0
demo/OpenGLWidget/GLShader/ShaderYUV420.h

@@ -0,0 +1,62 @@
+#ifndef _SHADERYUV4210_H_
+#define _SHADERYUV4210_H_
+
+#include "ShaderBase.h"
+
+struct Image_YUV420
+{
+    int width;          /* 宽度 */
+    int height;         /* 高度 */
+    QByteArray yData;   /* Y分量数据 */
+    QByteArray uData;   /* U分量数据 */
+    QByteArray vData;   /* V分量数据 */
+
+    Image_YUV420() : width(0), height(0) {}
+    Image_YUV420(Image_YUV420&& other);
+    Image_YUV420(const Image_YUV420& other);
+    Image_YUV420& operator=(Image_YUV420&& other);
+    Image_YUV420& operator=(const Image_YUV420& other);
+    bool isValid() const;
+    void clear();
+};
+
+
+class ShaderYUV420 : public ShaderBase
+{
+
+public:
+    ShaderYUV420();
+    ~ShaderYUV420() override;
+
+    /* 初始化形状 */
+    GLuint initShape() override;
+    /* 初始化纹理对象 */
+    bool initTextures() override;
+    /* 绘制图形 */
+    void drawShape() override;
+
+    /* 刷新一帧 */
+    bool refreshFrameYUV420(const Image_YUV420& yuvData);
+    /* 刷新一帧 */
+    bool refreshFrameRGBA(const QImage& image, int textureUnit = 0);
+
+private:
+    /* RGBA转换成YUV420 */
+    bool convertRGBAToYUV420(const QImage& image, Image_YUV420& yuvData);
+
+private:
+    GLuint m_VAO = 0;              // 顶点数组对象的ID
+    GLuint m_VBO = 0;              // 顶点缓冲对象的ID
+    GLuint m_EBO = 0;              // 索引缓冲对象的ID
+    QSize m_lastSize;               /* 上一张图片的大小 */
+
+    Image_YUV420 m_yuvData;         /* YUV420数据 */
+    QSize m_lastYUVSize;          /* 上一张YUV图片的大小 */
+
+    const QString m_textureYName = "textureY"; // Y分量纹理名称
+    const QString m_textureUName = "textureU"; // U分量纹理名称
+    const QString m_textureVName = "textureV"; // V分量纹理名称
+};
+
+#endif // _SHADERYUV4210_H_
+

+ 149 - 0
demo/OpenGLWidget/GLWidget/PlayerGLWidget.cpp

@@ -0,0 +1,149 @@
+#include "PlayerGLWidget.h"
+#include "spdlog/spdlog.h"
+#include <qopenglext.h>
+#include <QVariant>
+
+
+
+PlayerGLWidget::PlayerGLWidget(QWidget *parent) : QOpenGLWidget(parent)
+{
+
+}
+
+PlayerGLWidget::~PlayerGLWidget()
+{
+    if(m_shaderRGBA != nullptr) {
+        delete m_shaderRGBA;
+        m_shaderRGBA = nullptr;
+    }
+
+}
+
+
+/* 显示RGBA图片 */
+void PlayerGLWidget::showOneRGBAImage(const QImage& image)
+{
+    if(image.format() == QImage::Format_RGBA8888)
+    {
+        m_shaderRGBA->refreshFrameRGBA(image);
+    } else 
+    {
+        QImage imageRGBA = image.convertToFormat(QImage::Format_RGBA8888);
+        m_shaderRGBA->refreshFrameRGBA(imageRGBA);
+    }
+
+    m_shaderCurr = m_shaderRGBA; // 设置当前着色器为显示RGBA图片的着色器
+    update(); // 更新界面,触发paintGL函数
+}
+
+/* 显示一张YUV420的图片 */
+void PlayerGLWidget::showOneYUV420Image(const Image_YUV420& yuvData)
+{
+    if(!yuvData.isValid()) {
+        SPDLOG_WARN("YUV420数据无效");
+        return;
+    }
+
+    m_shaderYUV420->refreshFrameYUV420(yuvData);
+    m_shaderCurr = m_shaderYUV420; // 设置当前着色器为显示YUV420图片的着色器
+    update(); // 更新界面,触发paintGL函数
+}
+
+void PlayerGLWidget::testShowYUV420Image(const QImage& image)
+{
+    m_shaderYUV420->refreshFrameRGBA(image);
+    m_shaderCurr = m_shaderYUV420; // 设置当前着色器为显示YUV420图片的着色器
+    update(); // 更新界面,触发paintGL函数
+}
+
+/* 初始化RGBA的Shader */
+void PlayerGLWidget::initShaderRGBA()
+{
+    if(m_shaderRGBA != nullptr) {
+        delete m_shaderRGBA; // 删除旧的着色器对象
+        m_shaderRGBA = nullptr;
+    }
+    m_shaderRGBA = new ShaderRect();
+
+    m_shaderRGBA->initShape(); // 初始化形状
+    /* 初始化RGBA着色器 */
+    QString vertexShaderFile = ":/shaderCode/vertexShaderRGBA.glsl";
+    QString fragmentShaderFile = ":/shaderCode/fragmentShaderRGBA.glsl";
+    if (!m_shaderRGBA->loadShaderCode(vertexShaderFile, fragmentShaderFile)) 
+    {
+        SPDLOG_ERROR("加载着色器代码失败");
+        return;
+    }
+    /* 编译着色器 */
+    m_shaderRGBA->compileShader();
+    /* 初始化纹理 */
+    m_shaderRGBA->initTextures();
+}
+
+/* 初始化YUV420的Shader */
+void PlayerGLWidget::initShaderYUV420()
+{
+    if(m_shaderYUV420 != nullptr) {
+        delete m_shaderYUV420; // 删除旧的着色器对象
+        m_shaderYUV420 = nullptr;
+    }
+    m_shaderYUV420 = new ShaderYUV420();
+
+    m_shaderYUV420->initShape(); // 初始化形状
+    /* 初始化RGBA着色器 */
+    QString vertexShaderFile = ":/shaderCode/vertexShaderYUV420.glsl";
+    QString fragmentShaderFile = ":/shaderCode/fragmentShaderYUV420.glsl";
+    if (!m_shaderYUV420->loadShaderCode(vertexShaderFile, fragmentShaderFile)) 
+    {
+        SPDLOG_ERROR("加载着色器代码失败");
+        return;
+    }
+    /* 编译着色器 */
+    m_shaderYUV420->compileShader();
+    /* 初始化纹理 */
+    m_shaderYUV420->initTextures();
+}
+
+
+void PlayerGLWidget::initializeGL()
+{
+    SPDLOG_DEBUG("编译着色器...");
+    /* 初始化OpenGL函数,OpenGL的函数是在运行时才确定函数指针的 */
+    initializeOpenGLFunctions();
+
+    /* 初始化显示RGBA图片的着色器 */
+    initShaderRGBA();
+    /* 初始化显示YUV420图片的着色器 */
+    initShaderYUV420();
+
+
+    SPDLOG_DEBUG("着色器编译完成");
+}
+
+void PlayerGLWidget::resizeGL(int w, int h)
+{
+    /* 设置视口 */
+    glViewport(0, 0, w, h);
+    /* 设置投影矩阵 */
+    // m_shaderObj->setProjectionMatrix(w, h);
+    // SPDLOG_INFO("resizeGL: width = {}, height = {}", w, h);
+}
+
+void PlayerGLWidget::paintGL()
+{
+    
+    /* glClearColor函数是一个状态设置函数,而glClear函数则是一个状态使用的函数,
+     * 它使用了当前的状态来获取应该清除为的颜色。 */
+    glClearColor(0.1f, 0.3f, 0.3f, 1.0f);
+    glClear(GL_COLOR_BUFFER_BIT);
+
+    if(m_shaderCurr == nullptr) 
+    {
+        // SPDLOG_WARN("当前着色器对象为空");
+        return;
+    }
+
+    m_shaderCurr->useShader(); // 使用着色器
+    m_shaderCurr->drawShape(); // 绘制图形
+    
+}

+ 54 - 0
demo/OpenGLWidget/GLWidget/PlayerGLWidget.h

@@ -0,0 +1,54 @@
+#ifndef PLAYEROPENGLWIDGET_H
+#define PLAYEROPENGLWIDGET_H
+
+
+#include <QOpenGLWidget>
+#include <QOpenGLFunctions_3_3_Core>
+#include <GL/gl.h>
+
+#include "ShaderRect.h"
+#include "ShaderYUV420.h"
+
+/**
+ * @brief 
+ * 
+ */
+
+
+class PlayerGLWidget : public QOpenGLWidget, protected QOpenGLFunctions_3_3_Core
+{
+    Q_OBJECT
+
+public:
+    explicit PlayerGLWidget(QWidget *parent = nullptr);
+    ~PlayerGLWidget();
+
+    /* 显示RGBA图片 */
+    void showOneRGBAImage(const QImage& image);
+    /* 显示一张YUV420的图片 */
+    void showOneYUV420Image(const Image_YUV420& yuvData);
+    
+    void testShowYUV420Image(const QImage& image);
+
+private:
+    /* 初始化RGBA的Shader */
+    void initShaderRGBA();
+    /* 初始化YUV420的Shader */
+    void initShaderYUV420();
+ 
+protected:
+    void initializeGL() override;
+    void resizeGL(int w, int h) override;
+    void paintGL() override;
+
+private:
+
+    // GLuint m_VAO1 = 0; // 顶点数组对象的ID
+    
+    ShaderBase* m_shaderCurr = nullptr;     /* 当前使用的着色器对象 */
+    ShaderRect* m_shaderRGBA = nullptr;     /* 显示RGBA图片的着色器对象 */
+    ShaderYUV420* m_shaderYUV420 = nullptr; /* 显示YUV420图片的着色器对象 */
+
+};
+
+#endif /* PLAYEROPENGLWIDGET_H */

+ 8 - 0
demo/OpenGLWidget/resShaderCode.qrc

@@ -0,0 +1,8 @@
+<RCC>
+    <qresource prefix="/">
+        <file>shaderCode/vertexShaderRGBA.glsl</file>
+        <file>shaderCode/fragmentShaderRGBA.glsl</file>
+        <file>shaderCode/vertexShaderYUV420.glsl</file>
+        <file>shaderCode/fragmentShaderYUV420.glsl</file>
+    </qresource>
+</RCC>

+ 16 - 0
demo/OpenGLWidget/shaderCode/fragmentShader.glsl

@@ -0,0 +1,16 @@
+#version 330 core
+
+in vec3 vertexColor;    //输入颜色数据
+in vec2 TexCoord;       //输入纹理坐标数据
+
+out vec4 FragColor;     //输出颜色数据
+
+uniform sampler2D ourTexture1; //纹理采样器
+uniform sampler2D ourTexture2; //纹理采样器
+
+void main()
+{
+    //FragColor = vec4(1,0,0,1);
+    //FragColor = texture(ourTexture1, TexCoord) * vec4(vertexColor, 1.0); // 乘以颜色
+    FragColor = mix(texture(ourTexture1, TexCoord), texture(ourTexture2, TexCoord), 0.2); // 混合两种纹理
+}

+ 14 - 0
demo/OpenGLWidget/shaderCode/fragmentShaderRGBA.glsl

@@ -0,0 +1,14 @@
+#version 330 core
+
+in vec3 vertexColor;    //输入颜色数据
+in vec2 TexCoord;       //输入纹理坐标数据
+
+out vec4 FragColor;     //输出颜色数据
+
+uniform sampler2D textureRGBA; //纹理采样器
+
+void main()
+{
+    //FragColor = vec4(1,0,0,1);
+    FragColor = texture(textureRGBA, TexCoord);
+}

+ 21 - 0
demo/OpenGLWidget/shaderCode/fragmentShaderYUV420.glsl

@@ -0,0 +1,21 @@
+#version 330 core
+
+in vec3 vertexColor;    //输入颜色数据
+in vec2 TexCoord;       //输入纹理坐标数据
+
+out vec4 FragColor;     //输出颜色数据
+
+uniform sampler2D textureY; //Y分量纹理采样器
+uniform sampler2D textureU; //U分量纹理采样器
+uniform sampler2D textureV;
+
+void main()
+{
+    float y = texture(textureY, TexCoord).r;
+    float u = texture(textureU, TexCoord).r - 0.5;
+    float v = texture(textureV, TexCoord).r - 0.5;
+    float r = y + 1.402 * v;
+    float g = y - 0.344 * u - 0.714 * v;
+    float b = y + 1.772 * u;
+    FragColor = vec4(r, g, b, 1.0);
+}

+ 15 - 0
demo/OpenGLWidget/shaderCode/vertexShader.glsl

@@ -0,0 +1,15 @@
+#version 330 core
+layout(location = 0) in vec3 aPos;
+layout(location = 1) in vec3 aColor;
+layout(location = 2) in vec2 aTexCoord; // 纹理坐标
+
+out vec3 vertexColor;       //向片段着色器传递颜色数据
+out vec2 TexCoord;          //向片段着色器传递纹理坐标数据
+
+void main()
+{
+    gl_Position = vec4(aPos, 1.0);
+    vertexColor = aColor;
+    /* 传递纹理数据,并将垂直坐标翻转 */
+    TexCoord = vec2(aTexCoord.x, 1.0 - aTexCoord.y);
+}

+ 15 - 0
demo/OpenGLWidget/shaderCode/vertexShaderRGBA.glsl

@@ -0,0 +1,15 @@
+#version 330 core
+layout(location = 0) in vec3 aPos;
+layout(location = 1) in vec3 aColor;
+layout(location = 2) in vec2 aTexCoord; // 纹理坐标
+
+out vec3 vertexColor;       //向片段着色器传递颜色数据
+out vec2 TexCoord;          //向片段着色器传递纹理坐标数据
+
+void main()
+{
+    gl_Position = vec4(aPos, 1.0);
+    vertexColor = aColor;
+    /* 传递纹理数据,并将垂直坐标翻转 */
+    TexCoord = vec2(aTexCoord.x, 1.0 - aTexCoord.y);
+}

+ 15 - 0
demo/OpenGLWidget/shaderCode/vertexShaderYUV420.glsl

@@ -0,0 +1,15 @@
+#version 330 core
+layout(location = 0) in vec3 aPos;
+layout(location = 1) in vec3 aColor;
+layout(location = 2) in vec2 aTexCoord; // 纹理坐标
+
+out vec3 vertexColor;       //向片段着色器传递颜色数据
+out vec2 TexCoord;          //向片段着色器传递纹理坐标数据
+
+void main()
+{
+    gl_Position = vec4(aPos, 1.0);
+    vertexColor = aColor;
+    /* 传递纹理数据,并将垂直坐标翻转 */
+    TexCoord = vec2(aTexCoord.x, 1.0 - aTexCoord.y);
+}