Browse Source

V0.7.6
1、OpenGL可以使用纹理显示出一个图片了

apple 1 month ago
parent
commit
7fb0db5f73

+ 1 - 1
External

@@ -1 +1 @@
-Subproject commit ec11806d69fafc7584de4382161bce67bacfefaa
+Subproject commit c1b5f5afdeff0d5346843c0b586eeaf21988892b

BIN
demo/VideoPlayerGL/1.jpg


+ 0 - 1
demo/VideoPlayerGL/CMakeLists.txt

@@ -12,7 +12,6 @@ file(GLOB LOCAL_SRC
     ${CMAKE_CURRENT_SOURCE_DIR}/*.ui
     ${CMAKE_CURRENT_SOURCE_DIR}/GLWidget/*.cpp
 
-
     ${CMAKE_SOURCE_DIR}/External/module/Logs/*.cpp
     ${CMAKE_SOURCE_DIR}/External/module/ThreadPool/*.cpp
     

+ 48 - 31
demo/VideoPlayerGL/GLWidget/PlayerGLWidget.cpp

@@ -2,7 +2,8 @@
 #include "spdlog/spdlog.h"
 #include <gl/gl.h>
 #include <qopenglext.h>
-
+#include <QVariant>
+#include <QDateTime>
 
 
 
@@ -28,16 +29,15 @@ void PlayerGLWidget::initializeGL()
      * 顶点数组对象
      * ------------------------------------------------------------------------------------ */
     /* 生成一个VAO,返回的ID存储在VAO1中 */
-    glGenVertexArrays(1, &VAO1);
-    glBindVertexArray(VAO1);
+    glGenVertexArrays(1, &m_VAO1);
+    glBindVertexArray(m_VAO1);
 
 
     /* 创建一个三角形坐标数组,这里的z坐标都是0,表示平面2维 */
     float vertices[] = {
-        0.5f, 0.5f, 0.0f,   // 右上角
-        0.5f, -0.5f, 0.0f,  // 右下角
-        -0.5f, -0.5f, 0.0f, // 左下角
-        -0.5f, 0.5f, 0.0f   // 左上角
+        0.5f, -0.5f, 0.0f,  1.0f, 0.0f, 0.0f,   // 右下
+        -0.5f, -0.5f, 0.0f,  0.0f, 1.0f, 0.0f,   // 左下
+        0.0f,  0.5f, 0.0f,  0.0f, 0.0f, 1.0f    // 顶部
     };
 
     /* -------------------------------------------------------------------------------------
@@ -45,10 +45,10 @@ void PlayerGLWidget::initializeGL()
      * (GLuint就是unsigned int) 
      * ------------------------------------------------------------------------------------ */
     /* 生成一个VBO,返回的ID存储在VBO1中 */
-    glGenBuffers(1, &VBO1);
+    glGenBuffers(1, &m_VBO1);
     /* OpenGL有很多缓冲对象类型,顶点缓冲对象的缓冲类型是GL_ARRAY_BUFFER
      * 绑定VBO1到GL_ARRAY_BUFFER上,表示VBO1是一个顶点缓冲对象 */
-    glBindBuffer(GL_ARRAY_BUFFER, VBO1);
+    glBindBuffer(GL_ARRAY_BUFFER, m_VBO1);
     /* 将顶点数据复制到缓冲区的内存中 */
     glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
 
@@ -60,9 +60,9 @@ void PlayerGLWidget::initializeGL()
         1, 2, 3  // 第二个三角形
     };
     /* 创建一个EBO,返回的ID存储在EBO1中 */
-    glGenBuffers(1, &EBO1);
+    glGenBuffers(1, &m_EBO1);
     /* 绑定缓冲区 */
-    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO1);
+    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_EBO1);
     glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
 
     
@@ -80,10 +80,13 @@ void PlayerGLWidget::initializeGL()
      * 6、第六个参数是偏移量,这里是0,表示从缓冲区的开头开始读取数据。
      * 7、最后一个参数是启用顶点属性指针,告诉OpenGL我们要使用这个顶点属性。
      */
-     glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
+    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
      /* 启用顶点属性指针 */
-     glEnableVertexAttribArray(0);
+    glEnableVertexAttribArray(0);
 
+     /* 设置颜色位置,最后一个参数表示从第3个字节开始,倒数第二个参数是两个数据之间起始位置间隔6个字节 */
+    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6*sizeof(float), (void*)(3*sizeof(float)));
+    glEnableVertexAttribArray(1);
 
     /* -------------------------------------------------------------------------------------
      * 顶点着色器
@@ -100,11 +103,13 @@ void PlayerGLWidget::initializeGL()
     const char* vertexShaderSource = R"(
         #version 330 core
         layout(location = 0) in vec3 aPos;
-        out vec4 vertexColor;
+        layout(location = 1) in vec3 aColor;
+        uniform float offset;
+        out vec3 vertexColor;       //向片段着色器传递颜色数据
         void main()
         {
-            gl_Position = vec4(aPos, 1.0);
-            vertexColor = vec4(0.5, 0, 0, 1.0);
+            gl_Position = vec4(aPos.x + offset, aPos.y, aPos.z, 1.0);
+            vertexColor = aColor;
         }
     )";
 
@@ -137,10 +142,10 @@ void PlayerGLWidget::initializeGL()
     const char* fragmentShaderSource = R"(
         #version 330 core
         out vec4 FragColor;
-        in vec4 vertexColor;
+        in vec3 vertexColor;
         void main()
         {
-            FragColor = vertexColor;
+            FragColor = vec4(vertexColor, 1.0);
         }
     )";
     /* 创建一个片段着色器对象 */
@@ -162,17 +167,17 @@ void PlayerGLWidget::initializeGL()
      * 着色器程序对象
      * ------------------------------------------------------------------------------------ */
     /* 创建一个着色器程序对象 */
-    shaderProgram = glCreateProgram();
+    m_shaderProgram = glCreateProgram();
     /* 将顶点着色器和片段着色器附加到着色器程序对象上 */
-    glAttachShader(shaderProgram, vertexShader);
-    glAttachShader(shaderProgram, fragmentShader);
+    glAttachShader(m_shaderProgram, vertexShader);
+    glAttachShader(m_shaderProgram, fragmentShader);
     /* 链接着色器程序对象 */
-    glLinkProgram(shaderProgram);
+    glLinkProgram(m_shaderProgram);
     /* 检查链接错误 */
-    glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
+    glGetProgramiv(m_shaderProgram, GL_LINK_STATUS, &success);
     if(!success)
     {
-        glGetProgramInfoLog(shaderProgram, 512, nullptr, infoLog);
+        glGetProgramInfoLog(m_shaderProgram, 512, nullptr, infoLog);
         SPDLOG_ERROR("着色器程序链接错误: {}", infoLog);
     }
     /* 删除着色器对象,因为它们已经链接到着色器程序对象上了 */
@@ -194,19 +199,31 @@ void PlayerGLWidget::paintGL()
     glClearColor(0.1f, 0.3f, 0.3f, 1.0f);
     glClear(GL_COLOR_BUFFER_BIT);
 
+    /* 激活色器程序对象 */
+    glUseProgram(m_shaderProgram);
+
+    /* 更新uniform数据 */
+    /* uniform变量是一个全局变量,它的值在着色器程序中是唯一的,不能被顶点着色器和片段着色器同时使用。
+     * uniform变量的值在每次绘制时都可以更新。 */
+    static float offset = 0;
+    offset += 0.01f;
+    if (offset > 1.0f) offset = 0.0f;
+    
+    int offsetUniform = glGetUniformLocation(m_shaderProgram, "offset");
+    glUniform1f(offsetUniform, offset);
+
+    /* 绑定VAO1到 GL_VERTEX_ARRAY 上,表示VAO1是一个顶点数组对象 */
+    glBindVertexArray(m_VAO1);
+
     /* 绘制三角形 */
     /* glDrawArrays函数的第一个参数是绘制模式,这里是GL_TRIANGLES,表示绘制三角形。
      * 第二个参数是起始索引,这里是0,表示从第一个顶点开始绘制。
      * 第三个参数是顶点数量,这里是3,表示绘制3个顶点。
      */
-    //  glDrawArrays(GL_TRIANGLES, 0, 3);
+    glDrawArrays(GL_TRIANGLES, 0, 3);
 
-    /* 使用着色器程序对象 */
-    glUseProgram(shaderProgram);
-    /* 绑定VAO1到 GL_VERTEX_ARRAY 上,表示VAO1是一个顶点数组对象 */
-    glBindVertexArray(VAO1);
-    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
-    // glDrawArrays(GL_TRIANGLES, 0, 3);
+    
+    // glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
     /* 解绑VAO1 */
     glBindVertexArray(0);
     

+ 4 - 4
demo/VideoPlayerGL/GLWidget/PlayerGLWidget.h

@@ -32,10 +32,10 @@ protected:
 
 private:
 
-    GLuint VAO1 = 0; // 顶点数组对象的ID
-    GLuint VBO1 = 0; // 顶点缓冲对象的ID
-    GLuint EBO1 = 0; // 索引缓冲对象的ID
-    GLuint shaderProgram = 0; // 着色器程序对象的ID
+    GLuint m_VAO1 = 0; // 顶点数组对象的ID
+    GLuint m_VBO1 = 0; // 顶点缓冲对象的ID
+    GLuint m_EBO1 = 0; // 索引缓冲对象的ID
+    GLuint m_shaderProgram = 0; // 着色器程序对象的ID
 
 };
 

+ 310 - 0
demo/VideoPlayerGL/GLWidget/PlayerGLWidget2.cpp

@@ -0,0 +1,310 @@
+#include "PlayerGLWidget2.h"
+#include "spdlog.h"
+#include <QFile>
+#include <QTextStream>
+#include <cstdint>
+#include <cstring>
+#include <gl/gl.h>
+#include <qobject.h>
+#include <qopenglext.h>
+#include <string.h>
+#include <string>
+
+
+
+PlayerGLWidget2::PlayerGLWidget2(QWidget *parent) : QOpenGLWidget(parent)
+{
+    m_vertexCount = 4; // 顶点数量
+    m_vertexSize = 8; // 顶点大小
+    // m_vertices = new float[m_vertexCount * m_vertexSize] {
+    //     /* ----- 位置 -----|-------- 颜色 ----------|----- 纹理坐标 ------ */
+    //     -0.5f, -0.5f, 0.0f,     1.0f, 1.0f, 0.0f,   0.0f, 0.0f,     // 左下
+    //     0.5f, -0.5f, 0.0f,      0.0f, 0.0f, 1.0f,   1.0f, 0.0f,     // 右下
+    //     0.5f,  0.5f, 0.0f,      1.0f, 0.0f, 0.0f,   1.0f, 1.0f,     // 右上
+    //     -0.5f, 0.5f, 0.0f,      0.0f, 1.0f, 0.0f,   0.0f, 1.0f      // 右上
+    // };
+
+    m_vertices = new float[m_vertexCount * m_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      // 右上
+    };
+
+    m_indexCount = 6; // 索引数量
+    m_indices = new uint32_t[m_indexCount] {
+        0, 1, 2, // 第一个三角形
+        2, 3, 0  // 第二个三角形
+    };
+
+
+    /* 打开着色器代码 */
+    QString vertexShaderFile = ":/shader/vertexShader.glsl";
+    if (!loadShader(vertexShaderFile, &m_vertexShaderCode)) {
+        return;
+    }
+    // SPDLOG_INFO("顶点着色器代码: \n{}", m_vertexShaderCode);
+
+    QString fragmentShaderFile = ":/shader/fragmentShader.glsl";
+    if (!loadShader(fragmentShaderFile, &m_fragmentShaderCode)) {
+        return;
+    }
+    // SPDLOG_INFO("片段着色器代码: \n{}", m_fragmentShaderCode);
+
+    /* 加载问了图片 */
+    QString imageFile = ":/Image/1.jpg";
+    if (!loadImage(imageFile, m_imageTexture)) {
+        return;
+    }
+
+}
+PlayerGLWidget2::~PlayerGLWidget2()
+{
+    if(m_vertices != nullptr)
+    {
+        delete[] m_vertices;
+        m_vertices = nullptr;
+    }
+    if(m_indices != nullptr)
+    {
+        delete[] m_indices;
+        m_indices = nullptr;
+    }
+    if(m_vertexShaderCode != nullptr)
+    {
+        delete[] m_vertexShaderCode;
+        m_vertexShaderCode = nullptr;
+    }
+    if(m_fragmentShaderCode != nullptr)
+    {
+        delete[] m_fragmentShaderCode;
+        m_fragmentShaderCode = nullptr;
+    }
+}
+
+void PlayerGLWidget2::initializeGL()
+{
+    /* 初始化OpenGL函数 */
+    initializeOpenGLFunctions();
+
+    /* -------------------------------------------------------------------------------------
+     * 顶点数组对象
+     * ------------------------------------------------------------------------------------ */
+    glGenVertexArrays(1, &m_VAO1); // 生成一个VAO,返回的ID存储在VAO1中
+    glBindVertexArray(m_VAO1); // 绑定VAO
+
+    /* -------------------------------------------------------------------------------------
+     * 创建顶点数组缓冲区
+     * ------------------------------------------------------------------------------------ */
+    glGenBuffers(1, &m_VBO1);
+    glBindBuffer(GL_ARRAY_BUFFER, m_VBO1); // 绑定VBO
+    glBufferData(GL_ARRAY_BUFFER, m_vertexCount * m_vertexSize * sizeof(float), m_vertices, GL_STATIC_DRAW);
+
+    /* -------------------------------------------------------------------------------------
+     * 创建EBO
+     * ------------------------------------------------------------------------------------ */
+    glGenBuffers(1, &m_EBO1);
+    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_EBO1);
+    glBufferData(GL_ELEMENT_ARRAY_BUFFER, m_indexCount * sizeof(uint32_t), m_indices, GL_STATIC_DRAW); // 绑定EBO
+
+
+    /* -------------------------------------------------------------------------------------
+     * 链接顶点属性
+     * ------------------------------------------------------------------------------------ */
+    // 设置顶点属性指针,告诉OpenGL如何解析顶点数据
+    glVertexAttribPointer(
+                    0,                  /* 顶点属性位置,0表示第一个属性 */
+                    3,                  /* 每个顶点属性的大小,这里是3,表示x、y、z坐标 */
+                    GL_FLOAT, GL_FALSE, /* 数据类型和是否标准化 */
+                    m_vertexSize * sizeof(float), /* 步长,表示每个顶点属性之间的间隔 */
+                    (void*)0            /* 偏移量,表示该属性(顶点坐标)从第0个字节开始 */
+                ); 
+    /* 启用顶点属性 */
+    glEnableVertexAttribArray(0);
+ 
+    // 设置颜色位置,最后一个参数表示从第3个字节开始,倒数第二个参数是两个数据之间起始位置间隔8个字节
+    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, m_vertexSize * sizeof(float), (void*)(3*sizeof(float))); 
+    glEnableVertexAttribArray(1);
+ 
+    /* 设置纹理位置 */
+    glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, m_vertexSize * sizeof(float), (void*)(6*sizeof(float))); // 纹理坐标位置
+    glEnableVertexAttribArray(2); // 启用纹理坐标属性
+
+    
+
+    /* -------------------------------------------------------------------------------------
+     * 纹理对象
+     * ------------------------------------------------------------------------------------ */
+    glGenTextures(1, &m_textureID); // 生成纹理对象
+    glBindTexture(GL_TEXTURE_2D, m_textureID); // 绑定纹理对象
+    /* 设置当前绑定的纹理对象的环绕、过滤方式 */
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); // S轴环绕方式
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); // T轴环绕方式
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); // 纹理缩小过滤方式
+    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // 纹理放大过滤方式
+
+    /* 纹理数据,最后一个参数是纹理数据的指针,0表示数据在当前上下文中 */
+    /* 纹理数据,最后一个参数是纹理数据的指针 */
+    glTexImage2D(
+        GL_TEXTURE_2D,
+        0,                          // Mipmap 级别
+        GL_RGBA,                    // 纹理内部格式
+        m_imageTexture.width(),     // 纹理宽度
+        m_imageTexture.height(),    // 纹理高度
+        0,                          // 边框(必须为 0)
+        GL_RGBA,                    // 数据格式(与 QImage 格式匹配)
+        GL_UNSIGNED_BYTE,           // 数据类型
+        m_imageTexture.bits()       // 数据指针
+    );
+    glGenerateMipmap(GL_TEXTURE_2D); // 生成多级渐远纹理
+
+
+    /* -------------------------------------------------------------------------------------
+     * 着色器程序对象
+     * ------------------------------------------------------------------------------------ */
+    /* 编译顶点着色器 */
+    GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
+    /* 着色器代码 */
+    glShaderSource(vertexShader, 1, &m_vertexShaderCode, nullptr);
+    glCompileShader(vertexShader); // 编译着色器
+    /* 检查编译错误 */
+    GLint success;
+    GLchar infoLog[512];
+    glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
+    if(success == GL_FALSE)
+    {
+        glGetShaderInfoLog(vertexShader, sizeof(infoLog), nullptr, infoLog);
+        SPDLOG_ERROR("顶点着色器编译错误: {}", infoLog);
+    }
+
+    /* 编译片段着色器 */
+    GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
+    /* 加载着色器代码 */
+    glShaderSource(fragmentShader, 1, &m_fragmentShaderCode, nullptr);
+    glCompileShader(fragmentShader); // 编译着色器
+    /* 检查编译错误 */
+    success = 0;
+    memset(infoLog, 0, sizeof(infoLog)); // 清空infoLog
+    glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
+    if(success == GL_FALSE)
+    {
+        glGetShaderInfoLog(fragmentShader, sizeof(infoLog), nullptr, infoLog);
+        SPDLOG_ERROR("片段着色器编译错误: {}", infoLog);
+    }
+
+    /* 创建一个着色器程序对象 */
+    m_shaderProgram = glCreateProgram();
+    /* 将顶点着色器和片段着色器附加到着色器程序对象上 */
+    glAttachShader(m_shaderProgram, vertexShader);
+    glAttachShader(m_shaderProgram, fragmentShader);
+    /* 链接着色器程序 */
+    glLinkProgram(m_shaderProgram);
+    /* 检查链接错误 */
+    success = 0;
+    memset(infoLog, 0, sizeof(infoLog)); // 清空infoLog
+    glGetProgramiv(m_shaderProgram, GL_LINK_STATUS, &success);
+    if(success == GL_FALSE)
+    {
+        glGetProgramInfoLog(m_shaderProgram, sizeof(infoLog), nullptr, infoLog);
+        SPDLOG_ERROR("着色器链接错误: {}", infoLog);
+    }
+    /* 删除着色器对象 */
+    glDeleteShader(vertexShader);
+    glDeleteShader(fragmentShader);
+    /* 解绑VAO */
+    // glBindVertexArray(0); // 解绑VAO
+    /* 解绑VBO */
+    glBindBuffer(GL_ARRAY_BUFFER, 0); // 解绑VBO
+    /* 解绑EBO */
+    // glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); // 解绑EBO
+    /* 解绑纹理对象 */
+    // glBindTexture(GL_TEXTURE_2D, 0); // 解绑纹理对象
+    /* 解绑着色器程序对象 */
+    // glUseProgram(0); // 解绑着色器程序对象
+}
+
+void PlayerGLWidget2::resizeGL(int w, int h)
+{
+    glViewport(0, 0, w, h); // 设置视口大小
+}
+
+void PlayerGLWidget2::paintGL()
+{
+    glClearColor(0.1f, 0.3f, 0.3f, 1.0f);
+    glClear(GL_COLOR_BUFFER_BIT);
+
+    /* 激活着色器程序对象 */
+    glUseProgram(m_shaderProgram);
+    glBindTexture(GL_TEXTURE_2D, m_textureID); // 绑定纹理对象
+    /* 绑定VAO,绘制图形 */
+    glBindVertexArray(m_VAO1); // 绑定VAO
+
+    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); // 绘制四边形
+
+    glBindVertexArray(0); // 解绑VAO
+
+}
+
+
+/**
+ * @brief 打开GLSL文件,读取着色器代码
+ * 
+ * @param fileName 
+ * @param shaderCode 取出的着色器代码,函数内部会分配内存,需要在使用完后释放
+ * @return true 
+ * @return false 
+ */
+bool PlayerGLWidget2::loadShader(const QString &fileName, char** shaderCode)
+{
+    if(*shaderCode != nullptr) {
+        delete[] *shaderCode;
+        *shaderCode = nullptr;
+    }
+    /* 打开文件 */
+    QFile file(fileName);
+    if (!file.open(QIODevice::ReadOnly)) {
+        SPDLOG_ERROR("Failed to open shader file: {}", fileName.toStdString());
+        return false;
+    }
+    QByteArray ba = file.readAll();
+    file.close();
+    // SPDLOG_DEBUG("Shader file content: \n{}", ba.toStdString());
+
+    if (ba.isEmpty()) {
+        SPDLOG_ERROR("Shader file is empty: {}", fileName.toStdString());
+        return false;
+    }
+    /* 计算字符串长度 */
+    int len = ba.length() + 1; // +1是为了'\0'结尾
+    /* 分配内存 */
+    *shaderCode = new char[len];
+    /* 复制字符串 */
+    strcpy_s(*shaderCode, len, ba.toStdString().c_str());
+
+    return true;
+}
+
+/* 加载图片 */
+bool PlayerGLWidget2::loadImage(const QString &fileName, QImage &imageTexture)
+{
+    imageTexture.load(fileName);
+    if (imageTexture.isNull()) {
+        SPDLOG_ERROR("Failed to load image: {}", fileName.toStdString());
+        return false;
+    }
+    /* 翻转图片,OpenGL的坐标系和Qt的坐标系是相反的,所以需要翻转图片 */
+    // imageTexture = imageTexture.mirrored(false, true);
+    // if (imageTexture.isNull()) {
+    //     SPDLOG_ERROR("Failed to flip image: {}", fileName.toStdString());
+    //     return false;
+    // }
+    /* 将图片转换为RGBA格式 */
+    imageTexture = imageTexture.convertToFormat(QImage::Format_RGBA8888);
+    if (imageTexture.isNull()) {
+        SPDLOG_ERROR("Failed to convert image to RGBA format: {}", fileName.toStdString());
+        return false;
+    }
+    
+    return true;
+}

+ 63 - 0
demo/VideoPlayerGL/GLWidget/PlayerGLWidget2.h

@@ -0,0 +1,63 @@
+#ifndef PLAYEROPENGLWIDGET2_H
+#define PLAYEROPENGLWIDGET2_H
+
+
+#include <QOpenGLWidget>
+#include <QOpenGLFunctions_3_3_Core>
+#include <cstdint>
+#include <gl/gl.h>
+#include <qchar.h>
+
+
+/**
+ * @brief 
+ * 
+ */
+
+
+class PlayerGLWidget2 : public QOpenGLWidget, protected QOpenGLFunctions_3_3_Core
+{
+    Q_OBJECT
+
+public:
+    explicit PlayerGLWidget2(QWidget *parent = nullptr);
+    ~PlayerGLWidget2();
+
+
+
+ 
+protected:
+    void initializeGL() override;
+    void resizeGL(int w, int h) override;
+    void paintGL() override;
+
+private:
+    /* 打开GLSL文件,读取着色器代码 */
+    bool loadShader(const QString &fileName, char** shaderCode);
+    /* 加载图片 */
+    bool loadImage(const QString &fileName, QImage &imageTexture);
+
+private:
+
+    GLuint m_VAO1 = 0;              // 顶点数组对象的ID
+    GLuint m_VBO1 = 0;              // 顶点缓冲对象的ID
+    GLuint m_textureID;             // 纹理对象的ID
+    GLuint m_EBO1 = 0;              // 索引缓冲对象的ID
+    GLuint m_shaderProgram = 0;     // 着色器程序对象的ID
+
+    float* m_vertices = nullptr;    // 顶点数据
+    int m_vertexCount = 0;          // 顶点数量
+    int m_vertexSize = 0;           // 顶点大小
+
+    uint32_t* m_indices = nullptr;  // 索引数据(EBO数据)
+    int m_indexCount = 0;           // 索引数量
+
+    char* m_vertexShaderCode = nullptr;     // 顶点着色器代码
+    char* m_fragmentShaderCode = nullptr;   // 片段着色器代码
+
+    QImage m_imageTexture;          /* 纹理图片 */
+};
+
+
+
+#endif /* PLAYEROPENGLWIDGET2_H */

+ 9 - 0
demo/VideoPlayerGL/res.qrc

@@ -0,0 +1,9 @@
+<RCC>
+    <qresource prefix="/Image">
+        <file>1.jpg</file>
+    </qresource>
+    <qresource prefix="/">
+        <file>shader/vertexShader.glsl</file>
+        <file>shader/fragmentShader.glsl</file>
+    </qresource>
+</RCC>

+ 0 - 18
demo/VideoPlayerGL/shader.glsl

@@ -1,18 +0,0 @@
-
-// 版本号可以是330, 410, 420, 430, 440, 450等,具体取决于你的OpenGL版本和需求
-#version version_number // GLSL版本号
-
-in type in_variable_name; //输入变量
-in type in_variable_name;
-
-out type out_variable_name; //输出变量
-
-uniform type uniform_name;  // uniform变量
-
-void main()
-{
-  // 处理输入并进行一些图形操作
-  ...
-  // 输出处理过的结果到输出变量
-  out_variable_name = weird_stuff_we_processed;
-}

+ 13 - 0
demo/VideoPlayerGL/shader/fragmentShader.glsl

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

+ 15 - 0
demo/VideoPlayerGL/shader/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);
+}

+ 8 - 1
demo/VideoPlayerGL/widget.cpp

@@ -12,7 +12,7 @@ Widget::Widget(QWidget *parent)
 {
     ui->setupUi(this);
 
-    m_playerGLWidget = new PlayerGLWidget(ui->widget_display);
+    m_playerGLWidget = new PlayerGLWidget2(ui->widget_display);
     m_playerGLWidget->setGeometry(0, 0, ui->widget_display->width(), ui->widget_display->height());
     m_playerGLWidget->setStyleSheet(R"(border-radius:10px;)");
 
@@ -21,6 +21,13 @@ Widget::Widget(QWidget *parent)
     QPalette palette = m_playerGLWidget->palette();
     palette.setColor(QPalette::Window, Qt::black); // 设置背景颜色为黑色
     this->setPalette(palette);
+
+    connect(&m_timer, &QTimer::timeout, this, [=]() {
+        // SPDLOG_DEBUG("刷新一帧");
+        m_playerGLWidget->update();
+    });
+    m_timer.setSingleShot(false);
+    m_timer.start(10); // 60 FPS
     
 }
 

+ 5 - 1
demo/VideoPlayerGL/widget.h

@@ -4,6 +4,8 @@
 #include <QWidget>
 #include <memory>
 #include "PlayerGLWidget.h"
+#include "PlayerGLWidget2.h"
+#include <QTimer>
 
 QT_BEGIN_NAMESPACE
 namespace Ui { class Widget; }
@@ -25,7 +27,9 @@ protected:
 private:
     Ui::Widget *ui;
 
-    PlayerGLWidget *m_playerGLWidget = nullptr;
+    PlayerGLWidget2 *m_playerGLWidget = nullptr;
+
+    QTimer m_timer;
 
 };
 #endif // WIDGET_H