1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the demonstration applications of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
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 http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file. Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "glbuffers.h"
43 #include <QtGui/qmatrix4x4.h>
44
45
qgluPerspective(GLdouble fovy,GLdouble aspect,GLdouble zNear,GLdouble zFar)46 void qgluPerspective(GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar)
47 {
48 const GLdouble ymax = zNear * tan(fovy * M_PI / 360.0);
49 const GLdouble ymin = -ymax;
50 const GLdouble xmin = ymin * aspect;
51 const GLdouble xmax = ymax * aspect;
52 glFrustum(xmin, xmax, ymin, ymax, zNear, zFar);
53 }
54
55 //============================================================================//
56 // GLTexture //
57 //============================================================================//
58
GLTexture()59 GLTexture::GLTexture() : m_texture(0), m_failed(false)
60 {
61 glGenTextures(1, &m_texture);
62 }
63
~GLTexture()64 GLTexture::~GLTexture()
65 {
66 glDeleteTextures(1, &m_texture);
67 }
68
69 //============================================================================//
70 // GLTexture2D //
71 //============================================================================//
72
GLTexture2D(int width,int height)73 GLTexture2D::GLTexture2D(int width, int height)
74 {
75 glBindTexture(GL_TEXTURE_2D, m_texture);
76 glTexImage2D(GL_TEXTURE_2D, 0, 4, width, height, 0,
77 GL_BGRA, GL_UNSIGNED_BYTE, 0);
78
79 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
80 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
81 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
82 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
83 //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
84 //glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
85 glBindTexture(GL_TEXTURE_2D, 0);
86 }
87
88
GLTexture2D(const QString & fileName,int width,int height)89 GLTexture2D::GLTexture2D(const QString& fileName, int width, int height)
90 {
91 // TODO: Add error handling.
92 QImage image(fileName);
93
94 if (image.isNull()) {
95 m_failed = true;
96 return;
97 }
98
99 image = image.convertToFormat(QImage::Format_ARGB32);
100
101 //qDebug() << "Image size:" << image.width() << "x" << image.height();
102 if (width <= 0)
103 width = image.width();
104 if (height <= 0)
105 height = image.height();
106 if (width != image.width() || height != image.height())
107 image = image.scaled(width, height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
108
109 glBindTexture(GL_TEXTURE_2D, m_texture);
110
111 // Works on x86, so probably works on all little-endian systems.
112 // Does it work on big-endian systems?
113 glTexImage2D(GL_TEXTURE_2D, 0, 4, image.width(), image.height(), 0,
114 GL_BGRA, GL_UNSIGNED_BYTE, image.bits());
115
116 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
117 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
118 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
119 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
120 //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
121 //glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
122 glBindTexture(GL_TEXTURE_2D, 0);
123 }
124
load(int width,int height,QRgb * data)125 void GLTexture2D::load(int width, int height, QRgb *data)
126 {
127 glBindTexture(GL_TEXTURE_2D, m_texture);
128 glTexImage2D(GL_TEXTURE_2D, 0, 4, width, height, 0,
129 GL_BGRA, GL_UNSIGNED_BYTE, data);
130 glBindTexture(GL_TEXTURE_2D, 0);
131 }
132
bind()133 void GLTexture2D::bind()
134 {
135 glBindTexture(GL_TEXTURE_2D, m_texture);
136 glEnable(GL_TEXTURE_2D);
137 }
138
unbind()139 void GLTexture2D::unbind()
140 {
141 glBindTexture(GL_TEXTURE_2D, 0);
142 glDisable(GL_TEXTURE_2D);
143 }
144
145
146 //============================================================================//
147 // GLTexture3D //
148 //============================================================================//
149
GLTexture3D(int width,int height,int depth)150 GLTexture3D::GLTexture3D(int width, int height, int depth)
151 {
152 GLBUFFERS_ASSERT_OPENGL("GLTexture3D::GLTexture3D", glTexImage3D, return)
153
154 glBindTexture(GL_TEXTURE_3D, m_texture);
155 glTexImage3D(GL_TEXTURE_3D, 0, 4, width, height, depth, 0,
156 GL_BGRA, GL_UNSIGNED_BYTE, 0);
157
158 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_REPEAT);
159 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_REPEAT);
160 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_REPEAT);
161 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
162 glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
163 //glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
164 //glTexParameteri(GL_TEXTURE_3D, GL_GENERATE_MIPMAP, GL_TRUE);
165 glBindTexture(GL_TEXTURE_3D, 0);
166 }
167
load(int width,int height,int depth,QRgb * data)168 void GLTexture3D::load(int width, int height, int depth, QRgb *data)
169 {
170 GLBUFFERS_ASSERT_OPENGL("GLTexture3D::load", glTexImage3D, return)
171
172 glBindTexture(GL_TEXTURE_3D, m_texture);
173 glTexImage3D(GL_TEXTURE_3D, 0, 4, width, height, depth, 0,
174 GL_BGRA, GL_UNSIGNED_BYTE, data);
175 glBindTexture(GL_TEXTURE_3D, 0);
176 }
177
bind()178 void GLTexture3D::bind()
179 {
180 glBindTexture(GL_TEXTURE_3D, m_texture);
181 glEnable(GL_TEXTURE_3D);
182 }
183
unbind()184 void GLTexture3D::unbind()
185 {
186 glBindTexture(GL_TEXTURE_3D, 0);
187 glDisable(GL_TEXTURE_3D);
188 }
189
190 //============================================================================//
191 // GLTextureCube //
192 //============================================================================//
193
GLTextureCube(int size)194 GLTextureCube::GLTextureCube(int size)
195 {
196 glBindTexture(GL_TEXTURE_CUBE_MAP, m_texture);
197
198 for (int i = 0; i < 6; ++i)
199 glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, 4, size, size, 0,
200 GL_BGRA, GL_UNSIGNED_BYTE, 0);
201
202 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
203 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
204 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
205 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
206 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
207 //glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
208 //glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_GENERATE_MIPMAP, GL_TRUE);
209 glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
210 }
211
GLTextureCube(const QStringList & fileNames,int size)212 GLTextureCube::GLTextureCube(const QStringList& fileNames, int size)
213 {
214 // TODO: Add error handling.
215
216 glBindTexture(GL_TEXTURE_CUBE_MAP, m_texture);
217
218 int index = 0;
219 foreach (QString file, fileNames) {
220 QImage image(file);
221 if (image.isNull()) {
222 m_failed = true;
223 break;
224 }
225
226 image = image.convertToFormat(QImage::Format_ARGB32);
227
228 //qDebug() << "Image size:" << image.width() << "x" << image.height();
229 if (size <= 0)
230 size = image.width();
231 if (size != image.width() || size != image.height())
232 image = image.scaled(size, size, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
233
234 // Works on x86, so probably works on all little-endian systems.
235 // Does it work on big-endian systems?
236 glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + index, 0, 4, image.width(), image.height(), 0,
237 GL_BGRA, GL_UNSIGNED_BYTE, image.bits());
238
239 if (++index == 6)
240 break;
241 }
242
243 // Clear remaining faces.
244 while (index < 6) {
245 glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + index, 0, 4, size, size, 0,
246 GL_BGRA, GL_UNSIGNED_BYTE, 0);
247 ++index;
248 }
249
250 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
251 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
252 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
253 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
254 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
255 //glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
256 //glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_GENERATE_MIPMAP, GL_TRUE);
257 glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
258 }
259
load(int size,int face,QRgb * data)260 void GLTextureCube::load(int size, int face, QRgb *data)
261 {
262 glBindTexture(GL_TEXTURE_CUBE_MAP, m_texture);
263 glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, 0, 4, size, size, 0,
264 GL_BGRA, GL_UNSIGNED_BYTE, data);
265 glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
266 }
267
bind()268 void GLTextureCube::bind()
269 {
270 glBindTexture(GL_TEXTURE_CUBE_MAP, m_texture);
271 glEnable(GL_TEXTURE_CUBE_MAP);
272 }
273
unbind()274 void GLTextureCube::unbind()
275 {
276 glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
277 glDisable(GL_TEXTURE_CUBE_MAP);
278 }
279
280 //============================================================================//
281 // GLFrameBufferObject //
282 //============================================================================//
283
GLFrameBufferObject(int width,int height)284 GLFrameBufferObject::GLFrameBufferObject(int width, int height)
285 : m_fbo(0)
286 , m_depthBuffer(0)
287 , m_width(width)
288 , m_height(height)
289 , m_failed(false)
290 {
291 GLBUFFERS_ASSERT_OPENGL("GLFrameBufferObject::GLFrameBufferObject",
292 glGenFramebuffersEXT && glGenRenderbuffersEXT && glBindRenderbufferEXT && glRenderbufferStorageEXT, return)
293
294 // TODO: share depth buffers of same size
295 glGenFramebuffersEXT(1, &m_fbo);
296 //glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo);
297 glGenRenderbuffersEXT(1, &m_depthBuffer);
298 glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, m_depthBuffer);
299 glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, m_width, m_height);
300 //glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_depthBuffer);
301 //glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
302 }
303
~GLFrameBufferObject()304 GLFrameBufferObject::~GLFrameBufferObject()
305 {
306 GLBUFFERS_ASSERT_OPENGL("GLFrameBufferObject::~GLFrameBufferObject",
307 glDeleteFramebuffersEXT && glDeleteRenderbuffersEXT, return)
308
309 glDeleteFramebuffersEXT(1, &m_fbo);
310 glDeleteRenderbuffersEXT(1, &m_depthBuffer);
311 }
312
setAsRenderTarget(bool state)313 void GLFrameBufferObject::setAsRenderTarget(bool state)
314 {
315 GLBUFFERS_ASSERT_OPENGL("GLFrameBufferObject::setAsRenderTarget", glBindFramebufferEXT, return)
316
317 if (state) {
318 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, m_fbo);
319 glPushAttrib(GL_VIEWPORT_BIT);
320 glViewport(0, 0, m_width, m_height);
321 } else {
322 glPopAttrib();
323 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
324 }
325 }
326
isComplete()327 bool GLFrameBufferObject::isComplete()
328 {
329 GLBUFFERS_ASSERT_OPENGL("GLFrameBufferObject::isComplete", glCheckFramebufferStatusEXT, return false)
330
331 return GL_FRAMEBUFFER_COMPLETE_EXT == glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
332 }
333
334 //============================================================================//
335 // GLRenderTargetCube //
336 //============================================================================//
337
GLRenderTargetCube(int size)338 GLRenderTargetCube::GLRenderTargetCube(int size)
339 : GLTextureCube(size)
340 , m_fbo(size, size)
341 {
342 }
343
begin(int face)344 void GLRenderTargetCube::begin(int face)
345 {
346 GLBUFFERS_ASSERT_OPENGL("GLRenderTargetCube::begin",
347 glFramebufferTexture2DEXT && glFramebufferRenderbufferEXT, return)
348
349 m_fbo.setAsRenderTarget(true);
350 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
351 GL_TEXTURE_CUBE_MAP_POSITIVE_X + face, m_texture, 0);
352 glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, m_fbo.m_depthBuffer);
353 }
354
end()355 void GLRenderTargetCube::end()
356 {
357 m_fbo.setAsRenderTarget(false);
358 }
359
getViewMatrix(QMatrix4x4 & mat,int face)360 void GLRenderTargetCube::getViewMatrix(QMatrix4x4& mat, int face)
361 {
362 if (face < 0 || face >= 6) {
363 qWarning("GLRenderTargetCube::getViewMatrix: 'face' must be in the range [0, 6). (face == %d)", face);
364 return;
365 }
366
367 static int perm[6][3] = {
368 {2, 1, 0},
369 {2, 1, 0},
370 {0, 2, 1},
371 {0, 2, 1},
372 {0, 1, 2},
373 {0, 1, 2},
374 };
375
376 static float signs[6][3] = {
377 {-1.0f, -1.0f, -1.0f},
378 {+1.0f, -1.0f, +1.0f},
379 {+1.0f, +1.0f, -1.0f},
380 {+1.0f, -1.0f, +1.0f},
381 {+1.0f, -1.0f, -1.0f},
382 {-1.0f, -1.0f, +1.0f},
383 };
384
385 mat.fill(0.0f);
386 for (int i = 0; i < 3; ++i)
387 mat(i, perm[face][i]) = signs[face][i];
388 mat(3, 3) = 1.0f;
389 }
390
getProjectionMatrix(QMatrix4x4 & mat,float nearZ,float farZ)391 void GLRenderTargetCube::getProjectionMatrix(QMatrix4x4& mat, float nearZ, float farZ)
392 {
393 static const QMatrix4x4 reference(
394 1.0f, 0.0f, 0.0f, 0.0f,
395 0.0f, 1.0f, 0.0f, 0.0f,
396 0.0f, 0.0f, 0.0f, 0.0f,
397 0.0f, 0.0f, -1.0f, 0.0f);
398
399 mat = reference;
400 mat(2, 2) = (nearZ+farZ)/(nearZ-farZ);
401 mat(2, 3) = 2.0f*nearZ*farZ/(nearZ-farZ);
402 }
403