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