PlayerGLWidget2.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. #include "PlayerGLWidget2.h"
  2. #include "spdlog.h"
  3. #include <QFile>
  4. #include <QTextStream>
  5. #include <cstdint>
  6. #include <cstring>
  7. #include <gl/gl.h>
  8. #include <qobject.h>
  9. #include <qopenglext.h>
  10. #include <string.h>
  11. #include <string>
  12. PlayerGLWidget2::PlayerGLWidget2(QWidget *parent) : QOpenGLWidget(parent)
  13. {
  14. m_vertexCount = 4; // 顶点数量
  15. m_vertexSize = 8; // 顶点大小
  16. // m_vertices = new float[m_vertexCount * m_vertexSize] {
  17. // /* ----- 位置 -----|-------- 颜色 ----------|----- 纹理坐标 ------ */
  18. // -0.5f, -0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, // 左下
  19. // 0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, // 右下
  20. // 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // 右上
  21. // -0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f // 右上
  22. // };
  23. m_vertices = new float[m_vertexCount * m_vertexSize] {
  24. /* ----- 位置 -----|-------- 颜色 ----------|----- 纹理坐标 ------ */
  25. -1.0f, -1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 0.0f, // 左下
  26. 1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, // 右下
  27. 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // 右上
  28. -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f // 右上
  29. };
  30. m_indexCount = 6; // 索引数量
  31. m_indices = new uint32_t[m_indexCount] {
  32. 0, 1, 2, // 第一个三角形
  33. 2, 3, 0 // 第二个三角形
  34. };
  35. /* 打开着色器代码 */
  36. QString vertexShaderFile = ":/shader/vertexShader.glsl";
  37. if (!loadShader(vertexShaderFile, &m_vertexShaderCode)) {
  38. return;
  39. }
  40. // SPDLOG_INFO("顶点着色器代码: \n{}", m_vertexShaderCode);
  41. QString fragmentShaderFile = ":/shader/fragmentShader.glsl";
  42. if (!loadShader(fragmentShaderFile, &m_fragmentShaderCode)) {
  43. return;
  44. }
  45. // SPDLOG_INFO("片段着色器代码: \n{}", m_fragmentShaderCode);
  46. /* 加载问了图片 */
  47. QString imageFile = ":/Image/1.jpg";
  48. if (!loadImage(imageFile, m_imageTexture)) {
  49. return;
  50. }
  51. }
  52. PlayerGLWidget2::~PlayerGLWidget2()
  53. {
  54. if(m_vertices != nullptr)
  55. {
  56. delete[] m_vertices;
  57. m_vertices = nullptr;
  58. }
  59. if(m_indices != nullptr)
  60. {
  61. delete[] m_indices;
  62. m_indices = nullptr;
  63. }
  64. if(m_vertexShaderCode != nullptr)
  65. {
  66. delete[] m_vertexShaderCode;
  67. m_vertexShaderCode = nullptr;
  68. }
  69. if(m_fragmentShaderCode != nullptr)
  70. {
  71. delete[] m_fragmentShaderCode;
  72. m_fragmentShaderCode = nullptr;
  73. }
  74. }
  75. void PlayerGLWidget2::initializeGL()
  76. {
  77. /* 初始化OpenGL函数 */
  78. initializeOpenGLFunctions();
  79. /* -------------------------------------------------------------------------------------
  80. * 顶点数组对象
  81. * ------------------------------------------------------------------------------------ */
  82. glGenVertexArrays(1, &m_VAO1); // 生成一个VAO,返回的ID存储在VAO1中
  83. glBindVertexArray(m_VAO1); // 绑定VAO
  84. /* -------------------------------------------------------------------------------------
  85. * 创建顶点数组缓冲区
  86. * ------------------------------------------------------------------------------------ */
  87. glGenBuffers(1, &m_VBO1);
  88. glBindBuffer(GL_ARRAY_BUFFER, m_VBO1); // 绑定VBO
  89. glBufferData(GL_ARRAY_BUFFER, m_vertexCount * m_vertexSize * sizeof(float), m_vertices, GL_STATIC_DRAW);
  90. /* -------------------------------------------------------------------------------------
  91. * 创建EBO
  92. * ------------------------------------------------------------------------------------ */
  93. glGenBuffers(1, &m_EBO1);
  94. glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_EBO1);
  95. glBufferData(GL_ELEMENT_ARRAY_BUFFER, m_indexCount * sizeof(uint32_t), m_indices, GL_STATIC_DRAW); // 绑定EBO
  96. /* -------------------------------------------------------------------------------------
  97. * 链接顶点属性
  98. * ------------------------------------------------------------------------------------ */
  99. // 设置顶点属性指针,告诉OpenGL如何解析顶点数据
  100. glVertexAttribPointer(
  101. 0, /* 顶点属性位置,0表示第一个属性 */
  102. 3, /* 每个顶点属性的大小,这里是3,表示x、y、z坐标 */
  103. GL_FLOAT, GL_FALSE, /* 数据类型和是否标准化 */
  104. m_vertexSize * sizeof(float), /* 步长,表示每个顶点属性之间的间隔 */
  105. (void*)0 /* 偏移量,表示该属性(顶点坐标)从第0个字节开始 */
  106. );
  107. /* 启用顶点属性 */
  108. glEnableVertexAttribArray(0);
  109. // 设置颜色位置,最后一个参数表示从第3个字节开始,倒数第二个参数是两个数据之间起始位置间隔8个字节
  110. glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, m_vertexSize * sizeof(float), (void*)(3*sizeof(float)));
  111. glEnableVertexAttribArray(1);
  112. /* 设置纹理位置 */
  113. glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, m_vertexSize * sizeof(float), (void*)(6*sizeof(float))); // 纹理坐标位置
  114. glEnableVertexAttribArray(2); // 启用纹理坐标属性
  115. /* -------------------------------------------------------------------------------------
  116. * 纹理对象
  117. * ------------------------------------------------------------------------------------ */
  118. glGenTextures(1, &m_textureID); // 生成纹理对象
  119. glBindTexture(GL_TEXTURE_2D, m_textureID); // 绑定纹理对象
  120. /* 设置当前绑定的纹理对象的环绕、过滤方式 */
  121. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); // S轴环绕方式
  122. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); // T轴环绕方式
  123. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); // 纹理缩小过滤方式
  124. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // 纹理放大过滤方式
  125. /* 纹理数据,最后一个参数是纹理数据的指针,0表示数据在当前上下文中 */
  126. /* 纹理数据,最后一个参数是纹理数据的指针 */
  127. glTexImage2D(
  128. GL_TEXTURE_2D,
  129. 0, // Mipmap 级别
  130. GL_RGBA, // 纹理内部格式
  131. m_imageTexture.width(), // 纹理宽度
  132. m_imageTexture.height(), // 纹理高度
  133. 0, // 边框(必须为 0)
  134. GL_RGBA, // 数据格式(与 QImage 格式匹配)
  135. GL_UNSIGNED_BYTE, // 数据类型
  136. m_imageTexture.bits() // 数据指针
  137. );
  138. glGenerateMipmap(GL_TEXTURE_2D); // 生成多级渐远纹理
  139. /* -------------------------------------------------------------------------------------
  140. * 着色器程序对象
  141. * ------------------------------------------------------------------------------------ */
  142. /* 编译顶点着色器 */
  143. GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
  144. /* 着色器代码 */
  145. glShaderSource(vertexShader, 1, &m_vertexShaderCode, nullptr);
  146. glCompileShader(vertexShader); // 编译着色器
  147. /* 检查编译错误 */
  148. GLint success;
  149. GLchar infoLog[512];
  150. glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
  151. if(success == GL_FALSE)
  152. {
  153. glGetShaderInfoLog(vertexShader, sizeof(infoLog), nullptr, infoLog);
  154. SPDLOG_ERROR("顶点着色器编译错误: {}", infoLog);
  155. }
  156. /* 编译片段着色器 */
  157. GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
  158. /* 加载着色器代码 */
  159. glShaderSource(fragmentShader, 1, &m_fragmentShaderCode, nullptr);
  160. glCompileShader(fragmentShader); // 编译着色器
  161. /* 检查编译错误 */
  162. success = 0;
  163. memset(infoLog, 0, sizeof(infoLog)); // 清空infoLog
  164. glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
  165. if(success == GL_FALSE)
  166. {
  167. glGetShaderInfoLog(fragmentShader, sizeof(infoLog), nullptr, infoLog);
  168. SPDLOG_ERROR("片段着色器编译错误: {}", infoLog);
  169. }
  170. /* 创建一个着色器程序对象 */
  171. m_shaderProgram = glCreateProgram();
  172. /* 将顶点着色器和片段着色器附加到着色器程序对象上 */
  173. glAttachShader(m_shaderProgram, vertexShader);
  174. glAttachShader(m_shaderProgram, fragmentShader);
  175. /* 链接着色器程序 */
  176. glLinkProgram(m_shaderProgram);
  177. /* 检查链接错误 */
  178. success = 0;
  179. memset(infoLog, 0, sizeof(infoLog)); // 清空infoLog
  180. glGetProgramiv(m_shaderProgram, GL_LINK_STATUS, &success);
  181. if(success == GL_FALSE)
  182. {
  183. glGetProgramInfoLog(m_shaderProgram, sizeof(infoLog), nullptr, infoLog);
  184. SPDLOG_ERROR("着色器链接错误: {}", infoLog);
  185. }
  186. /* 删除着色器对象 */
  187. glDeleteShader(vertexShader);
  188. glDeleteShader(fragmentShader);
  189. /* 解绑VAO */
  190. // glBindVertexArray(0); // 解绑VAO
  191. /* 解绑VBO */
  192. glBindBuffer(GL_ARRAY_BUFFER, 0); // 解绑VBO
  193. /* 解绑EBO */
  194. // glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); // 解绑EBO
  195. /* 解绑纹理对象 */
  196. // glBindTexture(GL_TEXTURE_2D, 0); // 解绑纹理对象
  197. /* 解绑着色器程序对象 */
  198. // glUseProgram(0); // 解绑着色器程序对象
  199. }
  200. void PlayerGLWidget2::resizeGL(int w, int h)
  201. {
  202. glViewport(0, 0, w, h); // 设置视口大小
  203. }
  204. void PlayerGLWidget2::paintGL()
  205. {
  206. glClearColor(0.1f, 0.3f, 0.3f, 1.0f);
  207. glClear(GL_COLOR_BUFFER_BIT);
  208. /* 激活着色器程序对象 */
  209. glUseProgram(m_shaderProgram);
  210. glBindTexture(GL_TEXTURE_2D, m_textureID); // 绑定纹理对象
  211. /* 绑定VAO,绘制图形 */
  212. glBindVertexArray(m_VAO1); // 绑定VAO
  213. glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); // 绘制四边形
  214. glBindVertexArray(0); // 解绑VAO
  215. }
  216. /**
  217. * @brief 打开GLSL文件,读取着色器代码
  218. *
  219. * @param fileName
  220. * @param shaderCode 取出的着色器代码,函数内部会分配内存,需要在使用完后释放
  221. * @return true
  222. * @return false
  223. */
  224. bool PlayerGLWidget2::loadShader(const QString &fileName, char** shaderCode)
  225. {
  226. if(*shaderCode != nullptr) {
  227. delete[] *shaderCode;
  228. *shaderCode = nullptr;
  229. }
  230. /* 打开文件 */
  231. QFile file(fileName);
  232. if (!file.open(QIODevice::ReadOnly)) {
  233. SPDLOG_ERROR("Failed to open shader file: {}", fileName.toStdString());
  234. return false;
  235. }
  236. QByteArray ba = file.readAll();
  237. file.close();
  238. // SPDLOG_DEBUG("Shader file content: \n{}", ba.toStdString());
  239. if (ba.isEmpty()) {
  240. SPDLOG_ERROR("Shader file is empty: {}", fileName.toStdString());
  241. return false;
  242. }
  243. /* 计算字符串长度 */
  244. int len = ba.length() + 1; // +1是为了'\0'结尾
  245. /* 分配内存 */
  246. *shaderCode = new char[len];
  247. /* 复制字符串 */
  248. strcpy_s(*shaderCode, len, ba.toStdString().c_str());
  249. return true;
  250. }
  251. /* 加载图片 */
  252. bool PlayerGLWidget2::loadImage(const QString &fileName, QImage &imageTexture)
  253. {
  254. imageTexture.load(fileName);
  255. if (imageTexture.isNull()) {
  256. SPDLOG_ERROR("Failed to load image: {}", fileName.toStdString());
  257. return false;
  258. }
  259. /* 翻转图片,OpenGL的坐标系和Qt的坐标系是相反的,所以需要翻转图片 */
  260. // imageTexture = imageTexture.mirrored(false, true);
  261. // if (imageTexture.isNull()) {
  262. // SPDLOG_ERROR("Failed to flip image: {}", fileName.toStdString());
  263. // return false;
  264. // }
  265. /* 将图片转换为RGBA格式 */
  266. imageTexture = imageTexture.convertToFormat(QImage::Format_RGBA8888);
  267. if (imageTexture.isNull()) {
  268. SPDLOG_ERROR("Failed to convert image to RGBA format: {}", fileName.toStdString());
  269. return false;
  270. }
  271. return true;
  272. }