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; |
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(); |
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(); |
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 | |
209 | ~GLVertexBuffer() |
210 | { |
211 | GLBUFFERS_ASSERT_OPENGL("GLVertexBuffer::~GLVertexBuffer" , glDeleteBuffers, return) |
212 | |
213 | glDeleteBuffers(1, &m_buffer); |
214 | } |
215 | |
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(size: desc->count, type: desc->type, stride: sizeof(T), BUFFER_OFFSET(desc->offset)); |
225 | glEnableClientState(GL_VERTEX_ARRAY); |
226 | break; |
227 | case VertexDescription::TexCoord: |
228 | glTexCoordPointer(size: desc->count, type: desc->type, stride: sizeof(T), BUFFER_OFFSET(desc->offset)); |
229 | glEnableClientState(GL_TEXTURE_COORD_ARRAY); |
230 | break; |
231 | case VertexDescription::Normal: |
232 | glNormalPointer(type: desc->type, stride: sizeof(T), BUFFER_OFFSET(desc->offset)); |
233 | glEnableClientState(GL_NORMAL_ARRAY); |
234 | break; |
235 | case VertexDescription::Color: |
236 | glColorPointer(size: desc->count, type: desc->type, stride: sizeof(T), BUFFER_OFFSET(desc->offset)); |
237 | glEnableClientState(GL_COLOR_ARRAY); |
238 | break; |
239 | default: |
240 | break; |
241 | } |
242 | } |
243 | } |
244 | |
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 | |
270 | int length() const {return m_length;} |
271 | |
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 | |
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 | |
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 | |
320 | ~GLIndexBuffer() |
321 | { |
322 | GLBUFFERS_ASSERT_OPENGL("GLIndexBuffer::~GLIndexBuffer" , glDeleteBuffers, return) |
323 | |
324 | glDeleteBuffers(1, &m_buffer); |
325 | } |
326 | |
327 | void bind() |
328 | { |
329 | GLBUFFERS_ASSERT_OPENGL("GLIndexBuffer::bind" , glBindBuffer, return) |
330 | |
331 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_buffer); |
332 | } |
333 | |
334 | void unbind() |
335 | { |
336 | GLBUFFERS_ASSERT_OPENGL("GLIndexBuffer::unbind" , glBindBuffer, return) |
337 | |
338 | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); |
339 | } |
340 | |
341 | int length() const {return m_length;} |
342 | |
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 | |
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 | |
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 | |