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 Qt Data Visualization module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:GPL$ |
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 | ** GNU General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU |
19 | ** General Public License version 3 or (at your option) any later version |
20 | ** approved by the KDE Free Qt Foundation. The licenses are as published by |
21 | ** the Free Software Foundation and appearing in the file LICENSE.GPL3 |
22 | ** included in the packaging of this file. Please review the following |
23 | ** information to ensure the GNU General Public License requirements will |
24 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
25 | ** |
26 | ** $QT_END_LICENSE$ |
27 | ** |
28 | ****************************************************************************/ |
29 | |
30 | #include "texturehelper_p.h" |
31 | #include "utils_p.h" |
32 | |
33 | #include <QtGui/QImage> |
34 | #include <QtGui/QPainter> |
35 | #include <QtCore/QTime> |
36 | |
37 | QT_BEGIN_NAMESPACE_DATAVISUALIZATION |
38 | |
39 | // Defined in shaderhelper.cpp |
40 | extern void discardDebugMsgs(QtMsgType type, const QMessageLogContext &context, const QString &msg); |
41 | |
42 | TextureHelper::TextureHelper() |
43 | { |
44 | initializeOpenGLFunctions(); |
45 | #if !defined(QT_OPENGL_ES_2) |
46 | if (!Utils::isOpenGLES()) { |
47 | // Discard warnings about deprecated functions |
48 | QtMessageHandler handler = qInstallMessageHandler(discardDebugMsgs); |
49 | |
50 | m_openGlFunctions_2_1 = |
51 | QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_2_1>(); |
52 | if (m_openGlFunctions_2_1) |
53 | m_openGlFunctions_2_1->initializeOpenGLFunctions(); |
54 | |
55 | // Restore original message handler |
56 | qInstallMessageHandler(handler); |
57 | |
58 | if (!m_openGlFunctions_2_1) |
59 | qFatal(msg: "OpenGL version is too low, at least 2.1 is required" ); |
60 | } |
61 | #endif |
62 | } |
63 | |
64 | TextureHelper::~TextureHelper() |
65 | { |
66 | } |
67 | |
68 | GLuint TextureHelper::create2DTexture(const QImage &image, bool useTrilinearFiltering, |
69 | bool convert, bool smoothScale, bool clampY) |
70 | { |
71 | if (image.isNull()) |
72 | return 0; |
73 | |
74 | QImage texImage = image; |
75 | |
76 | if (Utils::isOpenGLES()) { |
77 | GLuint imageWidth = Utils::getNearestPowerOfTwo(value: image.width()); |
78 | GLuint imageHeight = Utils::getNearestPowerOfTwo(value: image.height()); |
79 | if (smoothScale) { |
80 | texImage = image.scaled(w: imageWidth, h: imageHeight, aspectMode: Qt::IgnoreAspectRatio, |
81 | mode: Qt::SmoothTransformation); |
82 | } else { |
83 | texImage = image.scaled(w: imageWidth, h: imageHeight, aspectMode: Qt::IgnoreAspectRatio); |
84 | } |
85 | } |
86 | |
87 | GLuint textureId; |
88 | glGenTextures(n: 1, textures: &textureId); |
89 | glBindTexture(GL_TEXTURE_2D, texture: textureId); |
90 | if (convert) |
91 | texImage = convertToGLFormat(srcImage: texImage); |
92 | glTexImage2D(GL_TEXTURE_2D, level: 0, GL_RGBA, width: texImage.width(), height: texImage.height(), |
93 | border: 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels: texImage.bits()); |
94 | if (smoothScale) |
95 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
96 | else |
97 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
98 | if (useTrilinearFiltering) { |
99 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); |
100 | glGenerateMipmap(GL_TEXTURE_2D); |
101 | } else { |
102 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
103 | } |
104 | if (clampY) |
105 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
106 | glBindTexture(GL_TEXTURE_2D, texture: 0); |
107 | |
108 | return textureId; |
109 | } |
110 | |
111 | GLuint TextureHelper::create3DTexture(const QVector<uchar> *data, int width, int height, int depth, |
112 | QImage::Format dataFormat) |
113 | { |
114 | if (Utils::isOpenGLES() || !width || !height || !depth) |
115 | return 0; |
116 | |
117 | GLuint textureId = 0; |
118 | #if defined(QT_OPENGL_ES_2) |
119 | Q_UNUSED(dataFormat) |
120 | Q_UNUSED(data) |
121 | #else |
122 | glEnable(GL_TEXTURE_3D); |
123 | |
124 | glGenTextures(n: 1, textures: &textureId); |
125 | glBindTexture(GL_TEXTURE_3D, texture: textureId); |
126 | glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
127 | glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
128 | glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); |
129 | glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
130 | glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
131 | |
132 | GLenum status = glGetError(); |
133 | // glGetError docs advise to call glGetError in loop to clear all error flags |
134 | while (status) |
135 | status = glGetError(); |
136 | |
137 | GLint internalFormat = 4; |
138 | GLint format = GL_BGRA; |
139 | if (dataFormat == QImage::Format_Indexed8) { |
140 | internalFormat = 1; |
141 | format = GL_RED; |
142 | // Align width to 32bits |
143 | width = width + width % 4; |
144 | } |
145 | m_openGlFunctions_2_1->glTexImage3D(GL_TEXTURE_3D, level: 0, internalformat: internalFormat, width, height, depth, border: 0, |
146 | format, GL_UNSIGNED_BYTE, pixels: data->constData()); |
147 | status = glGetError(); |
148 | if (status) |
149 | qWarning() << __FUNCTION__ << "3D texture creation failed:" << status; |
150 | |
151 | glBindTexture(GL_TEXTURE_3D, texture: 0); |
152 | glDisable(GL_TEXTURE_3D); |
153 | #endif |
154 | return textureId; |
155 | } |
156 | |
157 | GLuint TextureHelper::createCubeMapTexture(const QImage &image, bool useTrilinearFiltering) |
158 | { |
159 | if (image.isNull()) |
160 | return 0; |
161 | |
162 | GLuint textureId; |
163 | glGenTextures(n: 1, textures: &textureId); |
164 | glBindTexture(GL_TEXTURE_CUBE_MAP, texture: textureId); |
165 | QImage glTexture = convertToGLFormat(srcImage: image); |
166 | glTexImage2D(GL_TEXTURE_CUBE_MAP, level: 0, GL_RGBA, width: glTexture.width(), height: glTexture.height(), |
167 | border: 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels: glTexture.bits()); |
168 | glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
169 | if (useTrilinearFiltering) { |
170 | glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); |
171 | glGenerateMipmap(GL_TEXTURE_CUBE_MAP); |
172 | } else { |
173 | glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
174 | } |
175 | glBindTexture(GL_TEXTURE_2D, texture: 0); |
176 | return textureId; |
177 | } |
178 | |
179 | GLuint TextureHelper::createSelectionTexture(const QSize &size, GLuint &frameBuffer, |
180 | GLuint &depthBuffer) |
181 | { |
182 | GLuint textureid; |
183 | |
184 | // Create texture for the selection buffer |
185 | glGenTextures(n: 1, textures: &textureid); |
186 | glBindTexture(GL_TEXTURE_2D, texture: textureid); |
187 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
188 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
189 | glTexImage2D(GL_TEXTURE_2D, level: 0, GL_RGBA, width: size.width(), height: size.height(), border: 0, GL_RGBA, |
190 | GL_UNSIGNED_BYTE, NULL); |
191 | glBindTexture(GL_TEXTURE_2D, texture: 0); |
192 | |
193 | // Create render buffer |
194 | if (depthBuffer) |
195 | glDeleteRenderbuffers(n: 1, renderbuffers: &depthBuffer); |
196 | |
197 | glGenRenderbuffers(n: 1, renderbuffers: &depthBuffer); |
198 | glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer: depthBuffer); |
199 | GLenum status = glGetError(); |
200 | // glGetError docs advise to call glGetError in loop to clear all error flags |
201 | while (status) |
202 | status = glGetError(); |
203 | if (Utils::isOpenGLES()) |
204 | glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, width: size.width(), height: size.height()); |
205 | else |
206 | glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width: size.width(), height: size.height()); |
207 | |
208 | status = glGetError(); |
209 | if (status) { |
210 | qCritical() << "Selection texture render buffer creation failed:" << status; |
211 | glDeleteTextures(n: 1, textures: &textureid); |
212 | glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer: 0); |
213 | return 0; |
214 | } |
215 | glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer: 0); |
216 | |
217 | // Create frame buffer |
218 | if (!frameBuffer) |
219 | glGenFramebuffers(n: 1, framebuffers: &frameBuffer); |
220 | glBindFramebuffer(GL_FRAMEBUFFER, framebuffer: frameBuffer); |
221 | |
222 | // Attach texture to color attachment |
223 | glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture: textureid, level: 0); |
224 | // Attach renderbuffer to depth attachment |
225 | glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, renderbuffer: depthBuffer); |
226 | |
227 | // Verify that the frame buffer is complete |
228 | status = glCheckFramebufferStatus(GL_FRAMEBUFFER); |
229 | if (status != GL_FRAMEBUFFER_COMPLETE) { |
230 | qCritical() << "Selection texture frame buffer creation failed:" << status; |
231 | glDeleteTextures(n: 1, textures: &textureid); |
232 | textureid = 0; |
233 | } |
234 | |
235 | // Restore the default framebuffer |
236 | glBindFramebuffer(GL_FRAMEBUFFER, framebuffer: 0); |
237 | |
238 | return textureid; |
239 | } |
240 | |
241 | GLuint TextureHelper::createCursorPositionTexture(const QSize &size, GLuint &frameBuffer) |
242 | { |
243 | GLuint textureid; |
244 | glGenTextures(n: 1, textures: &textureid); |
245 | glBindTexture(GL_TEXTURE_2D, texture: textureid); |
246 | glTexImage2D(GL_TEXTURE_2D, level: 0, GL_RGBA, width: size.width(), height: size.height(), border: 0, GL_RGBA, |
247 | GL_UNSIGNED_BYTE, NULL); |
248 | glBindTexture(GL_TEXTURE_2D, texture: 0); |
249 | |
250 | glGenFramebuffers(n: 1, framebuffers: &frameBuffer); |
251 | glBindFramebuffer(GL_FRAMEBUFFER, framebuffer: frameBuffer); |
252 | glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, |
253 | texture: textureid, level: 0); |
254 | |
255 | GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); |
256 | if (status != GL_FRAMEBUFFER_COMPLETE) { |
257 | qCritical() << "Cursor position mapper frame buffer creation failed:" << status; |
258 | glDeleteTextures(n: 1, textures: &textureid); |
259 | textureid = 0; |
260 | } |
261 | glBindFramebuffer(GL_FRAMEBUFFER, framebuffer: 0); |
262 | |
263 | return textureid; |
264 | } |
265 | |
266 | GLuint TextureHelper::createUniformTexture(const QColor &color) |
267 | { |
268 | QImage image(QSize(int(uniformTextureWidth), int(uniformTextureHeight)), |
269 | QImage::Format_RGB32); |
270 | QPainter pmp(&image); |
271 | pmp.setBrush(QBrush(color)); |
272 | pmp.setPen(Qt::NoPen); |
273 | pmp.drawRect(x: 0, y: 0, w: int(uniformTextureWidth), h: int(uniformTextureHeight)); |
274 | |
275 | return create2DTexture(image, useTrilinearFiltering: false, convert: true, smoothScale: false, clampY: true); |
276 | } |
277 | |
278 | GLuint TextureHelper::createGradientTexture(const QLinearGradient &gradient) |
279 | { |
280 | QImage image(QSize(int(gradientTextureWidth), int(gradientTextureHeight)), |
281 | QImage::Format_RGB32); |
282 | QPainter pmp(&image); |
283 | pmp.setBrush(QBrush(gradient)); |
284 | pmp.setPen(Qt::NoPen); |
285 | pmp.drawRect(x: 0, y: 0, w: int(gradientTextureWidth), h: int(gradientTextureHeight)); |
286 | |
287 | return create2DTexture(image, useTrilinearFiltering: false, convert: true, smoothScale: false, clampY: true); |
288 | } |
289 | |
290 | GLuint TextureHelper::createDepthTexture(const QSize &size, GLuint textureSize) |
291 | { |
292 | GLuint depthtextureid = 0; |
293 | #if defined(QT_OPENGL_ES_2) |
294 | Q_UNUSED(size) |
295 | Q_UNUSED(textureSize) |
296 | #else |
297 | if (!Utils::isOpenGLES()) { |
298 | // Create depth texture for the shadow mapping |
299 | glGenTextures(n: 1, textures: &depthtextureid); |
300 | glBindTexture(GL_TEXTURE_2D, texture: depthtextureid); |
301 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
302 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
303 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
304 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
305 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); |
306 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB); |
307 | glTexImage2D(GL_TEXTURE_2D, level: 0, GL_DEPTH_COMPONENT, width: size.width() * textureSize, |
308 | height: size.height() * textureSize, border: 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL); |
309 | glBindTexture(GL_TEXTURE_2D, texture: 0); |
310 | } |
311 | #endif |
312 | return depthtextureid; |
313 | } |
314 | |
315 | GLuint TextureHelper::createDepthTextureFrameBuffer(const QSize &size, GLuint &frameBuffer, |
316 | GLuint textureSize) |
317 | { |
318 | GLuint depthtextureid = createDepthTexture(size, textureSize); |
319 | #if defined(QT_OPENGL_ES_2) |
320 | Q_UNUSED(frameBuffer) |
321 | #else |
322 | if (!Utils::isOpenGLES()) { |
323 | // Create frame buffer |
324 | if (!frameBuffer) |
325 | glGenFramebuffers(n: 1, framebuffers: &frameBuffer); |
326 | glBindFramebuffer(GL_FRAMEBUFFER, framebuffer: frameBuffer); |
327 | |
328 | // Attach texture to depth attachment |
329 | glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, texture: depthtextureid, level: 0); |
330 | |
331 | m_openGlFunctions_2_1->glDrawBuffer(GL_NONE); |
332 | m_openGlFunctions_2_1->glReadBuffer(GL_NONE); |
333 | |
334 | // Verify that the frame buffer is complete |
335 | GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); |
336 | if (status != GL_FRAMEBUFFER_COMPLETE) { |
337 | qCritical() << "Depth texture frame buffer creation failed" << status; |
338 | glDeleteTextures(n: 1, textures: &depthtextureid); |
339 | depthtextureid = 0; |
340 | } |
341 | |
342 | // Restore the default framebuffer |
343 | glBindFramebuffer(GL_FRAMEBUFFER, framebuffer: 0); |
344 | } |
345 | #endif |
346 | return depthtextureid; |
347 | } |
348 | |
349 | void TextureHelper::deleteTexture(GLuint *texture) |
350 | { |
351 | if (texture && *texture) { |
352 | if (QOpenGLContext::currentContext()) |
353 | glDeleteTextures(n: 1, textures: texture); |
354 | *texture = 0; |
355 | } |
356 | } |
357 | |
358 | QImage TextureHelper::convertToGLFormat(const QImage &srcImage) |
359 | { |
360 | QImage res(srcImage.size(), QImage::Format_ARGB32); |
361 | convertToGLFormatHelper(dstImage&: res, srcImage: srcImage.convertToFormat(f: QImage::Format_ARGB32), GL_RGBA); |
362 | return res; |
363 | } |
364 | |
365 | void TextureHelper::convertToGLFormatHelper(QImage &dstImage, const QImage &srcImage, |
366 | GLenum texture_format) |
367 | { |
368 | Q_ASSERT(dstImage.depth() == 32); |
369 | Q_ASSERT(srcImage.depth() == 32); |
370 | |
371 | if (dstImage.size() != srcImage.size()) { |
372 | int target_width = dstImage.width(); |
373 | int target_height = dstImage.height(); |
374 | float sx = target_width / float(srcImage.width()); |
375 | float sy = target_height / float(srcImage.height()); |
376 | |
377 | quint32 *dest = (quint32 *) dstImage.scanLine(0); // NB! avoid detach here |
378 | uchar *srcPixels = (uchar *) srcImage.scanLine(srcImage.height() - 1); |
379 | int sbpl = srcImage.bytesPerLine(); |
380 | int dbpl = dstImage.bytesPerLine(); |
381 | |
382 | int ix = int(0x00010000 / sx); |
383 | int iy = int(0x00010000 / sy); |
384 | |
385 | quint32 basex = int(0.5 * ix); |
386 | quint32 srcy = int(0.5 * iy); |
387 | |
388 | // scale, swizzle and mirror in one loop |
389 | while (target_height--) { |
390 | const uint *src = (const quint32 *) (srcPixels - (srcy >> 16) * sbpl); |
391 | int srcx = basex; |
392 | for (int x=0; x<target_width; ++x) { |
393 | dest[x] = qt_gl_convertToGLFormatHelper(src_pixel: src[srcx >> 16], texture_format); |
394 | srcx += ix; |
395 | } |
396 | dest = (quint32 *)(((uchar *) dest) + dbpl); |
397 | srcy += iy; |
398 | } |
399 | } else { |
400 | const int width = srcImage.width(); |
401 | const int height = srcImage.height(); |
402 | const uint *p = (const uint*) srcImage.scanLine(srcImage.height() - 1); |
403 | uint *q = (uint*) dstImage.scanLine(0); |
404 | |
405 | #if !defined(QT_OPENGL_ES_2) |
406 | if (texture_format == GL_BGRA) { |
407 | #else |
408 | if (texture_format == GL_BGRA8_EXT) { |
409 | #endif |
410 | if (QSysInfo::ByteOrder == QSysInfo::BigEndian) { |
411 | // mirror + swizzle |
412 | for (int i=0; i < height; ++i) { |
413 | const uint *end = p + width; |
414 | while (p < end) { |
415 | *q = ((*p << 24) & 0xff000000) |
416 | | ((*p >> 24) & 0x000000ff) |
417 | | ((*p << 8) & 0x00ff0000) |
418 | | ((*p >> 8) & 0x0000ff00); |
419 | p++; |
420 | q++; |
421 | } |
422 | p -= 2 * width; |
423 | } |
424 | } else { |
425 | const uint bytesPerLine = srcImage.bytesPerLine(); |
426 | for (int i=0; i < height; ++i) { |
427 | memcpy(dest: q, src: p, n: bytesPerLine); |
428 | q += width; |
429 | p -= width; |
430 | } |
431 | } |
432 | } else { |
433 | if (QSysInfo::ByteOrder == QSysInfo::BigEndian) { |
434 | for (int i=0; i < height; ++i) { |
435 | const uint *end = p + width; |
436 | while (p < end) { |
437 | *q = (*p << 8) | ((*p >> 24) & 0xff); |
438 | p++; |
439 | q++; |
440 | } |
441 | p -= 2 * width; |
442 | } |
443 | } else { |
444 | for (int i=0; i < height; ++i) { |
445 | const uint *end = p + width; |
446 | while (p < end) { |
447 | *q = ((*p << 16) & 0xff0000) | ((*p >> 16) & 0xff) | (*p & 0xff00ff00); |
448 | p++; |
449 | q++; |
450 | } |
451 | p -= 2 * width; |
452 | } |
453 | } |
454 | } |
455 | } |
456 | } |
457 | |
458 | QRgb TextureHelper::qt_gl_convertToGLFormatHelper(QRgb src_pixel, GLenum texture_format) |
459 | { |
460 | #if !defined(QT_OPENGL_ES_2) |
461 | if (texture_format == GL_BGRA) { |
462 | #else |
463 | if (texture_format == GL_BGRA8_EXT) { |
464 | #endif |
465 | if (QSysInfo::ByteOrder == QSysInfo::BigEndian) { |
466 | return ((src_pixel << 24) & 0xff000000) |
467 | | ((src_pixel >> 24) & 0x000000ff) |
468 | | ((src_pixel << 8) & 0x00ff0000) |
469 | | ((src_pixel >> 8) & 0x0000ff00); |
470 | } else { |
471 | return src_pixel; |
472 | } |
473 | } else { // GL_RGBA |
474 | if (QSysInfo::ByteOrder == QSysInfo::BigEndian) { |
475 | return (src_pixel << 8) | ((src_pixel >> 24) & 0xff); |
476 | } else { |
477 | return ((src_pixel << 16) & 0xff0000) |
478 | | ((src_pixel >> 16) & 0xff) |
479 | | (src_pixel & 0xff00ff00); |
480 | } |
481 | } |
482 | } |
483 | |
484 | QT_END_NAMESPACE_DATAVISUALIZATION |
485 | |