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