1 /**************************************************************************** 2 ** 3 ** Copyright (C) 2016 The Qt Company Ltd. 4 ** Contact: https://www.qt.io/licensing/ 5 ** 6 ** This file is part of the demonstration applications of the Qt Toolkit. 7 ** 8 ** $QT_BEGIN_LICENSE:BSD$ 9 ** Commercial License Usage 10 ** Licensees holding valid commercial Qt licenses may use this file in 11 ** accordance with the commercial license agreement provided with the 12 ** Software or, alternatively, in accordance with the terms contained in 13 ** a written agreement between you and The Qt Company. For licensing terms 14 ** and conditions see https://www.qt.io/terms-conditions. For further 15 ** information use the contact form at https://www.qt.io/contact-us. 16 ** 17 ** BSD License Usage 18 ** Alternatively, you may use this file under the terms of the BSD license 19 ** as follows: 20 ** 21 ** "Redistribution and use in source and binary forms, with or without 22 ** modification, are permitted provided that the following conditions are 23 ** met: 24 ** * Redistributions of source code must retain the above copyright 25 ** notice, this list of conditions and the following disclaimer. 26 ** * Redistributions in binary form must reproduce the above copyright 27 ** notice, this list of conditions and the following disclaimer in 28 ** the documentation and/or other materials provided with the 29 ** distribution. 30 ** * Neither the name of The Qt Company Ltd nor the names of its 31 ** contributors may be used to endorse or promote products derived 32 ** from this software without specific prior written permission. 33 ** 34 ** 35 ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 36 ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 37 ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 38 ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 39 ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 40 ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 41 ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 42 ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 43 ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 44 ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 45 ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." 46 ** 47 ** $QT_END_LICENSE$ 48 ** 49 ****************************************************************************/ 50 51 #ifndef GLBUFFERS_H 52 #define GLBUFFERS_H 53 54 //#include <GL/glew.h> 55 #include "glextensions.h" 56 57 #include <QtWidgets> 58 #include <QtOpenGL> 59 60 #define BUFFER_OFFSET(i) ((char*)0 + (i)) 61 #define SIZE_OF_MEMBER(cls, member) sizeof(static_cast<cls *>(nullptr)->member) 62 63 #define GLBUFFERS_ASSERT_OPENGL(prefix, assertion, returnStatement) \ 64 if (m_failed || !(assertion)) { \ 65 if (!m_failed) qCritical(prefix ": The necessary OpenGL functions are not available."); \ 66 m_failed = true; \ 67 returnStatement; \ 68 } 69 70 void qgluPerspective(GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar); 71 72 QT_BEGIN_NAMESPACE 73 class QMatrix4x4; 74 QT_END_NAMESPACE 75 76 class GLTexture 77 { 78 public: 79 GLTexture(); 80 virtual ~GLTexture(); 81 virtual void bind() = 0; 82 virtual void unbind() = 0; failed()83 virtual bool failed() const {return m_failed;} 84 protected: 85 GLuint m_texture = 0; 86 bool m_failed = false; 87 }; 88 89 class GLFrameBufferObject 90 { 91 public: 92 friend class GLRenderTargetCube; 93 // friend class GLRenderTarget2D; 94 95 GLFrameBufferObject(int width, int height); 96 virtual ~GLFrameBufferObject(); 97 bool isComplete(); failed()98 virtual bool failed() const {return m_failed;} 99 protected: 100 void setAsRenderTarget(bool state = true); 101 GLuint m_fbo = 0; 102 GLuint m_depthBuffer = 0; 103 int m_width, m_height; 104 bool m_failed = false; 105 }; 106 107 class GLTexture2D : public GLTexture 108 { 109 public: 110 GLTexture2D(int width, int height); 111 explicit GLTexture2D(const QString &fileName, int width = 0, int height = 0); 112 void load(int width, int height, QRgb *data); 113 void bind() override; 114 void unbind() override; 115 }; 116 117 class GLTexture3D : public GLTexture 118 { 119 public: 120 GLTexture3D(int width, int height, int depth); 121 // TODO: Implement function below 122 //GLTexture3D(const QString& fileName, int width = 0, int height = 0); 123 void load(int width, int height, int depth, QRgb *data); 124 void bind() override; 125 void unbind() override; 126 }; 127 128 class GLTextureCube : public GLTexture 129 { 130 public: 131 GLTextureCube(int size); 132 explicit GLTextureCube(const QStringList &fileNames, int size = 0); 133 void load(int size, int face, QRgb *data); 134 void bind() override; 135 void unbind() override; 136 }; 137 138 // TODO: Define and implement class below 139 //class GLRenderTarget2D : public GLTexture2D 140 141 class GLRenderTargetCube : public GLTextureCube 142 { 143 public: 144 GLRenderTargetCube(int size); 145 // begin rendering to one of the cube's faces. 0 <= face < 6 146 void begin(int face); 147 // end rendering 148 void end(); failed()149 bool failed() const override { return m_failed || m_fbo.failed(); } 150 151 static void getViewMatrix(QMatrix4x4& mat, int face); 152 static void getProjectionMatrix(QMatrix4x4& mat, float nearZ, float farZ); 153 private: 154 GLFrameBufferObject m_fbo; 155 }; 156 157 struct VertexDescription 158 { 159 enum 160 { 161 Null = 0, // Terminates a VertexDescription array 162 Position, 163 TexCoord, 164 Normal, 165 Color, 166 }; 167 int field; // Position, TexCoord, Normal, Color 168 int type; // GL_FLOAT, GL_UNSIGNED_BYTE 169 int count; // number of elements 170 int offset; // field's offset into vertex struct 171 int index; // 0 (unused at the moment) 172 }; 173 174 // Implementation of interleaved buffers. 175 // 'T' is a struct which must include a null-terminated static array 176 // 'VertexDescription* description'. 177 // Example: 178 /* 179 struct Vertex 180 { 181 GLfloat position[3]; 182 GLfloat texCoord[2]; 183 GLfloat normal[3]; 184 GLbyte color[4]; 185 static VertexDescription description[]; 186 }; 187 188 VertexDescription Vertex::description[] = { 189 {VertexDescription::Position, GL_FLOAT, SIZE_OF_MEMBER(Vertex, position) / sizeof(GLfloat), offsetof(Vertex, position), 0}, 190 {VertexDescription::TexCoord, GL_FLOAT, SIZE_OF_MEMBER(Vertex, texCoord) / sizeof(GLfloat), offsetof(Vertex, texCoord), 0}, 191 {VertexDescription::Normal, GL_FLOAT, SIZE_OF_MEMBER(Vertex, normal) / sizeof(GLfloat), offsetof(Vertex, normal), 0}, 192 {VertexDescription::Color, GL_BYTE, SIZE_OF_MEMBER(Vertex, color) / sizeof(GLbyte), offsetof(Vertex, color), 0}, 193 {VertexDescription::Null, 0, 0, 0, 0}, 194 }; 195 */ 196 template<class T> 197 class GLVertexBuffer 198 { 199 public: 200 GLVertexBuffer(int length, const T *data = nullptr, int mode = GL_STATIC_DRAW) 201 { 202 GLBUFFERS_ASSERT_OPENGL("GLVertexBuffer::GLVertexBuffer", glGenBuffers && glBindBuffer && glBufferData, return) 203 204 glGenBuffers(1, &m_buffer); 205 glBindBuffer(GL_ARRAY_BUFFER, m_buffer); 206 glBufferData(GL_ARRAY_BUFFER, (m_length = length) * sizeof(T), data, mode); 207 } 208 ~GLVertexBuffer()209 ~GLVertexBuffer() 210 { 211 GLBUFFERS_ASSERT_OPENGL("GLVertexBuffer::~GLVertexBuffer", glDeleteBuffers, return) 212 213 glDeleteBuffers(1, &m_buffer); 214 } 215 bind()216 void bind() 217 { 218 GLBUFFERS_ASSERT_OPENGL("GLVertexBuffer::bind", glBindBuffer, return) 219 220 glBindBuffer(GL_ARRAY_BUFFER, m_buffer); 221 for (VertexDescription *desc = T::description; desc->field != VertexDescription::Null; ++desc) { 222 switch (desc->field) { 223 case VertexDescription::Position: 224 glVertexPointer(desc->count, desc->type, sizeof(T), BUFFER_OFFSET(desc->offset)); 225 glEnableClientState(GL_VERTEX_ARRAY); 226 break; 227 case VertexDescription::TexCoord: 228 glTexCoordPointer(desc->count, desc->type, sizeof(T), BUFFER_OFFSET(desc->offset)); 229 glEnableClientState(GL_TEXTURE_COORD_ARRAY); 230 break; 231 case VertexDescription::Normal: 232 glNormalPointer(desc->type, sizeof(T), BUFFER_OFFSET(desc->offset)); 233 glEnableClientState(GL_NORMAL_ARRAY); 234 break; 235 case VertexDescription::Color: 236 glColorPointer(desc->count, desc->type, sizeof(T), BUFFER_OFFSET(desc->offset)); 237 glEnableClientState(GL_COLOR_ARRAY); 238 break; 239 default: 240 break; 241 } 242 } 243 } 244 unbind()245 void unbind() 246 { 247 GLBUFFERS_ASSERT_OPENGL("GLVertexBuffer::unbind", glBindBuffer, return) 248 249 glBindBuffer(GL_ARRAY_BUFFER, 0); 250 for (VertexDescription *desc = T::description; desc->field != VertexDescription::Null; ++desc) { 251 switch (desc->field) { 252 case VertexDescription::Position: 253 glDisableClientState(GL_VERTEX_ARRAY); 254 break; 255 case VertexDescription::TexCoord: 256 glDisableClientState(GL_TEXTURE_COORD_ARRAY); 257 break; 258 case VertexDescription::Normal: 259 glDisableClientState(GL_NORMAL_ARRAY); 260 break; 261 case VertexDescription::Color: 262 glDisableClientState(GL_COLOR_ARRAY); 263 break; 264 default: 265 break; 266 } 267 } 268 } 269 length()270 int length() const {return m_length;} 271 lock()272 T *lock() 273 { 274 GLBUFFERS_ASSERT_OPENGL("GLVertexBuffer::lock", glBindBuffer && glMapBuffer, return nullptr) 275 276 glBindBuffer(GL_ARRAY_BUFFER, m_buffer); 277 //glBufferData(GL_ARRAY_BUFFER, m_length, NULL, m_mode); 278 GLvoid* buffer = glMapBuffer(GL_ARRAY_BUFFER, GL_READ_WRITE); 279 m_failed = (buffer == nullptr); 280 return reinterpret_cast<T *>(buffer); 281 } 282 unlock()283 void unlock() 284 { 285 GLBUFFERS_ASSERT_OPENGL("GLVertexBuffer::unlock", glBindBuffer && glUnmapBuffer, return) 286 287 glBindBuffer(GL_ARRAY_BUFFER, m_buffer); 288 glUnmapBuffer(GL_ARRAY_BUFFER); 289 } 290 failed()291 bool failed() 292 { 293 return m_failed; 294 } 295 296 private: 297 int m_length = 0; 298 int m_mode = 0; 299 GLuint m_buffer = 0; 300 bool m_failed = false; 301 }; 302 303 template<class T> 304 class GLIndexBuffer 305 { 306 public: 307 GLIndexBuffer(int length, const T *data = nullptr, int mode = GL_STATIC_DRAW) 308 : m_length(0) 309 , m_mode(mode) 310 , m_buffer(0) 311 , m_failed(false) 312 { 313 GLBUFFERS_ASSERT_OPENGL("GLIndexBuffer::GLIndexBuffer", glGenBuffers && glBindBuffer && glBufferData, return) 314 315 glGenBuffers(1, &m_buffer); 316 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_buffer); 317 glBufferData(GL_ELEMENT_ARRAY_BUFFER, (m_length = length) * sizeof(T), data, mode); 318 } 319 ~GLIndexBuffer()320 ~GLIndexBuffer() 321 { 322 GLBUFFERS_ASSERT_OPENGL("GLIndexBuffer::~GLIndexBuffer", glDeleteBuffers, return) 323 324 glDeleteBuffers(1, &m_buffer); 325 } 326 bind()327 void bind() 328 { 329 GLBUFFERS_ASSERT_OPENGL("GLIndexBuffer::bind", glBindBuffer, return) 330 331 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_buffer); 332 } 333 unbind()334 void unbind() 335 { 336 GLBUFFERS_ASSERT_OPENGL("GLIndexBuffer::unbind", glBindBuffer, return) 337 338 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 339 } 340 length()341 int length() const {return m_length;} 342 lock()343 T *lock() 344 { 345 GLBUFFERS_ASSERT_OPENGL("GLIndexBuffer::lock", glBindBuffer && glMapBuffer, return nullptr) 346 347 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_buffer); 348 GLvoid* buffer = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_READ_WRITE); 349 m_failed = (buffer == nullptr); 350 return reinterpret_cast<T *>(buffer); 351 } 352 unlock()353 void unlock() 354 { 355 GLBUFFERS_ASSERT_OPENGL("GLIndexBuffer::unlock", glBindBuffer && glUnmapBuffer, return) 356 357 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_buffer); 358 glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER); 359 } 360 failed()361 bool failed() 362 { 363 return m_failed; 364 } 365 366 private: 367 int m_length, m_mode; 368 GLuint m_buffer; 369 bool m_failed; 370 }; 371 372 #endif 373