1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 Klaralvdalens Datakonsult AB (KDAB).
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the Qt3D module 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 https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://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 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 #include "qtextureimage.h"
41 #include "qabstracttextureimage.h"
42 #include "qtextureimage_p.h"
43 #include "qtextureimagedata_p.h"
44 #include "qtexturedata.h"
45 #include "qtexture.h"
46 #include "qtexture_p.h"
47 #include <QFileInfo>
48 #include <QMimeDatabase>
49 #include <QMimeType>
50 #include <QtCore/QBuffer>
51 #include <qendian.h>
52 #include <Qt3DCore/private/qscene_p.h>
53 #include <Qt3DCore/qaspectengine.h>
54 #include <Qt3DCore/private/qdownloadhelperservice_p.h>
55 #include <Qt3DRender/private/qrenderaspect_p.h>
56 #include <Qt3DRender/private/nodemanagers_p.h>
57 #include <Qt3DRender/private/managers_p.h>
58 #include <Qt3DRender/private/texture_p.h>
59 #include <Qt3DRender/private/qurlhelper_p.h>
60 #include <qmath.h>
61 
62 QT_BEGIN_NAMESPACE
63 
64 namespace Qt3DRender {
65 
66 namespace {
67 
68 struct DdsPixelFormat
69 {
70     quint32 size;
71     quint32 flags;
72     quint32 fourCC;
73     quint32 rgbBitCount;
74     quint32 redMask;
75     quint32 greenMask;
76     quint32 blueMask;
77     quint32 alphaMask;
78 };
79 
80 struct DdsHeader
81 {
82     char magic[4];
83     quint32 size;
84     quint32 flags;
85     quint32 height;
86     quint32 width;
87     quint32 pitchOrLinearSize;
88     quint32 depth;
89     quint32 mipmapCount;
90     quint32 reserved[11];
91     DdsPixelFormat pixelFormat;
92     quint32 caps;
93     quint32 caps2;
94     quint32 caps3;
95     quint32 caps4;
96     quint32 reserved2;
97 };
98 
99 struct DdsDX10Header
100 {
101     quint32 format;
102     quint32 dimension;
103     quint32 miscFlag;
104     quint32 arraySize;
105     quint32 miscFlags2;
106 };
107 
108 enum DdsFlags
109 {
110     MipmapCountFlag             = 0x20000,
111 };
112 
113 enum PixelFormatFlag
114 {
115     AlphaFlag                   = 0x1,
116     FourCCFlag                  = 0x4,
117     RGBFlag                     = 0x40,
118     RGBAFlag                    = RGBFlag | AlphaFlag,
119     YUVFlag                     = 0x200,
120     LuminanceFlag               = 0x20000
121 };
122 
123 enum Caps2Flags
124 {
125     CubemapFlag                 = 0x200,
126     CubemapPositiveXFlag        = 0x400,
127     CubemapNegativeXFlag        = 0x800,
128     CubemapPositiveYFlag        = 0x1000,
129     CubemapNegativeYFlag        = 0x2000,
130     CubemapPositiveZFlag        = 0x4000,
131     CubemapNegativeZFlag        = 0x8000,
132     AllCubemapFaceFlags         = CubemapPositiveXFlag |
133     CubemapNegativeXFlag |
134     CubemapPositiveYFlag |
135     CubemapNegativeYFlag |
136     CubemapPositiveZFlag |
137     CubemapNegativeZFlag,
138     VolumeFlag                  = 0x200000
139 };
140 
141 enum DXGIFormat
142 {
143     DXGI_FORMAT_UNKNOWN                     = 0,
144     DXGI_FORMAT_R32G32B32A32_TYPELESS       = 1,
145     DXGI_FORMAT_R32G32B32A32_FLOAT          = 2,
146     DXGI_FORMAT_R32G32B32A32_UINT           = 3,
147     DXGI_FORMAT_R32G32B32A32_SINT           = 4,
148     DXGI_FORMAT_R32G32B32_TYPELESS          = 5,
149     DXGI_FORMAT_R32G32B32_FLOAT             = 6,
150     DXGI_FORMAT_R32G32B32_UINT              = 7,
151     DXGI_FORMAT_R32G32B32_SINT              = 8,
152     DXGI_FORMAT_R16G16B16A16_TYPELESS       = 9,
153     DXGI_FORMAT_R16G16B16A16_FLOAT          = 10,
154     DXGI_FORMAT_R16G16B16A16_UNORM          = 11,
155     DXGI_FORMAT_R16G16B16A16_UINT           = 12,
156     DXGI_FORMAT_R16G16B16A16_SNORM          = 13,
157     DXGI_FORMAT_R16G16B16A16_SINT           = 14,
158     DXGI_FORMAT_R32G32_TYPELESS             = 15,
159     DXGI_FORMAT_R32G32_FLOAT                = 16,
160     DXGI_FORMAT_R32G32_UINT                 = 17,
161     DXGI_FORMAT_R32G32_SINT                 = 18,
162     DXGI_FORMAT_R32G8X24_TYPELESS           = 19,
163     DXGI_FORMAT_D32_FLOAT_S8X24_UINT        = 20,
164     DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS    = 21,
165     DXGI_FORMAT_X32_TYPELESS_G8X24_UINT     = 22,
166     DXGI_FORMAT_R10G10B10A2_TYPELESS        = 23,
167     DXGI_FORMAT_R10G10B10A2_UNORM           = 24,
168     DXGI_FORMAT_R10G10B10A2_UINT            = 25,
169     DXGI_FORMAT_R11G11B10_FLOAT             = 26,
170     DXGI_FORMAT_R8G8B8A8_TYPELESS           = 27,
171     DXGI_FORMAT_R8G8B8A8_UNORM              = 28,
172     DXGI_FORMAT_R8G8B8A8_UNORM_SRGB         = 29,
173     DXGI_FORMAT_R8G8B8A8_UINT               = 30,
174     DXGI_FORMAT_R8G8B8A8_SNORM              = 31,
175     DXGI_FORMAT_R8G8B8A8_SINT               = 32,
176     DXGI_FORMAT_R16G16_TYPELESS             = 33,
177     DXGI_FORMAT_R16G16_FLOAT                = 34,
178     DXGI_FORMAT_R16G16_UNORM                = 35,
179     DXGI_FORMAT_R16G16_UINT                 = 36,
180     DXGI_FORMAT_R16G16_SNORM                = 37,
181     DXGI_FORMAT_R16G16_SINT                 = 38,
182     DXGI_FORMAT_R32_TYPELESS                = 39,
183     DXGI_FORMAT_D32_FLOAT                   = 40,
184     DXGI_FORMAT_R32_FLOAT                   = 41,
185     DXGI_FORMAT_R32_UINT                    = 42,
186     DXGI_FORMAT_R32_SINT                    = 43,
187     DXGI_FORMAT_R24G8_TYPELESS              = 44,
188     DXGI_FORMAT_D24_UNORM_S8_UINT           = 45,
189     DXGI_FORMAT_R24_UNORM_X8_TYPELESS       = 46,
190     DXGI_FORMAT_X24_TYPELESS_G8_UINT        = 47,
191     DXGI_FORMAT_R8G8_TYPELESS               = 48,
192     DXGI_FORMAT_R8G8_UNORM                  = 49,
193     DXGI_FORMAT_R8G8_UINT                   = 50,
194     DXGI_FORMAT_R8G8_SNORM                  = 51,
195     DXGI_FORMAT_R8G8_SINT                   = 52,
196     DXGI_FORMAT_R16_TYPELESS                = 53,
197     DXGI_FORMAT_R16_FLOAT                   = 54,
198     DXGI_FORMAT_D16_UNORM                   = 55,
199     DXGI_FORMAT_R16_UNORM                   = 56,
200     DXGI_FORMAT_R16_UINT                    = 57,
201     DXGI_FORMAT_R16_SNORM                   = 58,
202     DXGI_FORMAT_R16_SINT                    = 59,
203     DXGI_FORMAT_R8_TYPELESS                 = 60,
204     DXGI_FORMAT_R8_UNORM                    = 61,
205     DXGI_FORMAT_R8_UINT                     = 62,
206     DXGI_FORMAT_R8_SNORM                    = 63,
207     DXGI_FORMAT_R8_SINT                     = 64,
208     DXGI_FORMAT_A8_UNORM                    = 65,
209     DXGI_FORMAT_R1_UNORM                    = 66,
210     DXGI_FORMAT_R9G9B9E5_SHAREDEXP          = 67,
211     DXGI_FORMAT_R8G8_B8G8_UNORM             = 68,
212     DXGI_FORMAT_G8R8_G8B8_UNORM             = 69,
213     DXGI_FORMAT_BC1_TYPELESS                = 70,
214     DXGI_FORMAT_BC1_UNORM                   = 71,
215     DXGI_FORMAT_BC1_UNORM_SRGB              = 72,
216     DXGI_FORMAT_BC2_TYPELESS                = 73,
217     DXGI_FORMAT_BC2_UNORM                   = 74,
218     DXGI_FORMAT_BC2_UNORM_SRGB              = 75,
219     DXGI_FORMAT_BC3_TYPELESS                = 76,
220     DXGI_FORMAT_BC3_UNORM                   = 77,
221     DXGI_FORMAT_BC3_UNORM_SRGB              = 78,
222     DXGI_FORMAT_BC4_TYPELESS                = 79,
223     DXGI_FORMAT_BC4_UNORM                   = 80,
224     DXGI_FORMAT_BC4_SNORM                   = 81,
225     DXGI_FORMAT_BC5_TYPELESS                = 82,
226     DXGI_FORMAT_BC5_UNORM                   = 83,
227     DXGI_FORMAT_BC5_SNORM                   = 84,
228     DXGI_FORMAT_B5G6R5_UNORM                = 85,
229     DXGI_FORMAT_B5G5R5A1_UNORM              = 86,
230     DXGI_FORMAT_B8G8R8A8_UNORM              = 87,
231     DXGI_FORMAT_B8G8R8X8_UNORM              = 88,
232     DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM  = 89,
233     DXGI_FORMAT_B8G8R8A8_TYPELESS           = 90,
234     DXGI_FORMAT_B8G8R8A8_UNORM_SRGB         = 91,
235     DXGI_FORMAT_B8G8R8X8_TYPELESS           = 92,
236     DXGI_FORMAT_B8G8R8X8_UNORM_SRGB         = 93,
237     DXGI_FORMAT_BC6H_TYPELESS               = 94,
238     DXGI_FORMAT_BC6H_UF16                   = 95,
239     DXGI_FORMAT_BC6H_SF16                   = 96,
240     DXGI_FORMAT_BC7_TYPELESS                = 97,
241     DXGI_FORMAT_BC7_UNORM                   = 98,
242     DXGI_FORMAT_BC7_UNORM_SRGB              = 99,
243     DXGI_FORMAT_AYUV                        = 100,
244     DXGI_FORMAT_Y410                        = 101,
245     DXGI_FORMAT_Y416                        = 102,
246     DXGI_FORMAT_NV12                        = 103,
247     DXGI_FORMAT_P010                        = 104,
248     DXGI_FORMAT_P016                        = 105,
249     DXGI_FORMAT_420_OPAQUE                  = 106,
250     DXGI_FORMAT_YUY2                        = 107,
251     DXGI_FORMAT_Y210                        = 108,
252     DXGI_FORMAT_Y216                        = 109,
253     DXGI_FORMAT_NV11                        = 110,
254     DXGI_FORMAT_AI44                        = 111,
255     DXGI_FORMAT_IA44                        = 112,
256     DXGI_FORMAT_P8                          = 113,
257     DXGI_FORMAT_A8P8                        = 114,
258     DXGI_FORMAT_B4G4R4A4_UNORM              = 115,
259     DXGI_FORMAT_P208                        = 130,
260     DXGI_FORMAT_V208                        = 131,
261     DXGI_FORMAT_V408                        = 132,
262 };
263 
264 template <int a, int b, int c, int d>
265 struct DdsFourCC
266 {
267     static const quint32 value = a | (b << 8) | (c << 16) | (d << 24);
268 };
269 
270 struct FormatInfo
271 {
272     QOpenGLTexture::PixelFormat pixelFormat;
273     QOpenGLTexture::TextureFormat textureFormat;
274     QOpenGLTexture::PixelType pixelType;
275     int components;
276     bool compressed;
277 };
278 
279 const struct RGBAFormat
280 {
281     quint32 redMask;
282     quint32 greenMask;
283     quint32 blueMask;
284     quint32 alphaMask;
285     FormatInfo formatInfo;
286 
287 } rgbaFormats[] = {
288     // unorm formats
289 { 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000,   { QOpenGLTexture::RGBA,             QOpenGLTexture::RGBA8_UNorm,    QOpenGLTexture::UInt8,           4, false } },
290 { 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000,   { QOpenGLTexture::BGRA,             QOpenGLTexture::RGBA8_UNorm,    QOpenGLTexture::UInt8,           4, false } },
291 { 0x000000ff, 0x0000ff00, 0x00ff0000, 0x00000000,   { QOpenGLTexture::RGBA,             QOpenGLTexture::RGBA8_UNorm,    QOpenGLTexture::UInt8,           4, false } },
292 { 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000,   { QOpenGLTexture::BGRA,             QOpenGLTexture::RGBA8_UNorm,    QOpenGLTexture::UInt8,           4, false } },
293 { 0x000000ff, 0x0000ff00, 0x00ff0000, 0x00000000,   { QOpenGLTexture::RGB,              QOpenGLTexture::RGB8_UNorm,     QOpenGLTexture::UInt8,           3, false } },
294 { 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000,   { QOpenGLTexture::BGR,              QOpenGLTexture::RGB8_UNorm,     QOpenGLTexture::UInt8,           3, false } },
295 
296 // packed formats
297 { 0x0000f800, 0x000007e0, 0x0000001f, 0x00000000,   { QOpenGLTexture::RGB,              QOpenGLTexture::R5G6B5,         QOpenGLTexture::UInt16_R5G6B5,   2, false } },
298 { 0x00007c00, 0x000003e0, 0x0000001f, 0x00008000,   { QOpenGLTexture::RGBA,             QOpenGLTexture::RGB5A1,         QOpenGLTexture::UInt16_RGB5A1,   2, false } },
299 { 0x00000f00, 0x000000f0, 0x0000000f, 0x0000f000,   { QOpenGLTexture::RGBA,             QOpenGLTexture::RGBA4,          QOpenGLTexture::UInt16_RGBA4,    2, false } },
300 { 0x000000e0, 0x0000001c, 0x00000003, 0x00000000,   { QOpenGLTexture::RGB,              QOpenGLTexture::RG3B2,          QOpenGLTexture::UInt8_RG3B2,     1, false } },
301 { 0x3ff00000, 0x000ffc00, 0x000003ff, 0xc0000000,   { QOpenGLTexture::RGBA,             QOpenGLTexture::RGB10A2,        QOpenGLTexture::UInt32_RGB10A2,  4, false } },
302 
303 // luminance alpha
304 { 0x000000ff, 0x000000ff, 0x000000ff, 0x00000000,   { QOpenGLTexture::Red,              QOpenGLTexture::R8_UNorm,       QOpenGLTexture::UInt8,           1, false } },
305 { 0x000000ff, 0x00000000, 0x00000000, 0x00000000,   { QOpenGLTexture::Red,              QOpenGLTexture::R8_UNorm,       QOpenGLTexture::UInt8,           1, false } },
306 { 0x000000ff, 0x000000ff, 0x000000ff, 0x0000ff00,   { QOpenGLTexture::RG,               QOpenGLTexture::RG8_UNorm,      QOpenGLTexture::UInt8,           2, false } },
307 { 0x000000ff, 0x00000000, 0x00000000, 0x0000ff00,   { QOpenGLTexture::RG,               QOpenGLTexture::RG8_UNorm,      QOpenGLTexture::UInt8,           2, false } },
308 };
309 
310 const struct FourCCFormat
311 {
312     quint32 fourCC;
313     FormatInfo formatInfo;
314 } fourCCFormats[] = {
315 { DdsFourCC<'D','X','T','1'>::value,                { QOpenGLTexture::NoSourceFormat,   QOpenGLTexture::RGBA_DXT1,      QOpenGLTexture::NoPixelType,     8, true } },
316 { DdsFourCC<'D','X','T','3'>::value,                { QOpenGLTexture::NoSourceFormat,   QOpenGLTexture::RGBA_DXT3,      QOpenGLTexture::NoPixelType,    16, true } },
317 { DdsFourCC<'D','X','T','5'>::value,                { QOpenGLTexture::NoSourceFormat,   QOpenGLTexture::RGBA_DXT5,      QOpenGLTexture::NoPixelType,    16, true } },
318 { DdsFourCC<'A','T','I','1'>::value,                { QOpenGLTexture::NoSourceFormat,   QOpenGLTexture::R_ATI1N_UNorm,  QOpenGLTexture::NoPixelType,     8, true } },
319 { DdsFourCC<'A','T','I','2'>::value,                { QOpenGLTexture::NoSourceFormat,   QOpenGLTexture::RG_ATI2N_UNorm, QOpenGLTexture::NoPixelType,    16, true } },
320 { /* DXGI_FORMAT_R16_FLOAT */         111,          { QOpenGLTexture::Red,              QOpenGLTexture::R16F,           QOpenGLTexture::Float16,        2,  false } },
321 { /* DXGI_FORMAT_R16_FLOAT */         112,          { QOpenGLTexture::RG,               QOpenGLTexture::RG16F,          QOpenGLTexture::Float16,        4,  false } },
322 { /* DXGI_FORMAT_R16G16B16A16_FLOAT */113,          { QOpenGLTexture::RGBA,             QOpenGLTexture::RGBA16F,        QOpenGLTexture::Float16,        8,  false } },
323 { /* DXGI_FORMAT_R32_FLOAT */         114,          { QOpenGLTexture::Red,              QOpenGLTexture::R32F,           QOpenGLTexture::Float32,        4,  false } },
324 { /* DXGI_FORMAT_R32G32_FLOAT */      115,          { QOpenGLTexture::RG,               QOpenGLTexture::RG32F,          QOpenGLTexture::Float32,        8,  false } },
325 { /* DXGI_FORMAT_R32G32B32A32_FLOAT */116,          { QOpenGLTexture::RGBA,             QOpenGLTexture::RGBA32F,        QOpenGLTexture::Float32,        16, false } }
326 };
327 
328 const struct DX10Format
329 {
330     DXGIFormat dxgiFormat;
331     FormatInfo formatInfo;
332 } dx10Formats[] = {
333     // unorm formats
334 { DXGI_FORMAT_R8_UNORM,                             { QOpenGLTexture::Red,              QOpenGLTexture::R8_UNorm,       QOpenGLTexture::UInt8,           1, false } },
335 { DXGI_FORMAT_R8G8_UNORM,                           { QOpenGLTexture::RG,               QOpenGLTexture::RG8_UNorm,      QOpenGLTexture::UInt8,           2, false } },
336 { DXGI_FORMAT_R8G8B8A8_UNORM,                       { QOpenGLTexture::RGBA,             QOpenGLTexture::RGBA8_UNorm,    QOpenGLTexture::UInt8,           4, false } },
337 
338 { DXGI_FORMAT_R16_UNORM,                            { QOpenGLTexture::Red,              QOpenGLTexture::R16_UNorm,      QOpenGLTexture::UInt16,          2, false } },
339 { DXGI_FORMAT_R16G16_UNORM,                         { QOpenGLTexture::RG,               QOpenGLTexture::RG16_UNorm,     QOpenGLTexture::UInt16,          4, false } },
340 { DXGI_FORMAT_R16G16B16A16_UNORM,                   { QOpenGLTexture::RGBA,             QOpenGLTexture::RGBA16_UNorm,   QOpenGLTexture::UInt16,          8, false } },
341 
342 // snorm formats
343 { DXGI_FORMAT_R8_SNORM,                             { QOpenGLTexture::Red,              QOpenGLTexture::R8_SNorm,       QOpenGLTexture::Int8,            1, false } },
344 { DXGI_FORMAT_R8G8_SNORM,                           { QOpenGLTexture::RG,               QOpenGLTexture::RG8_SNorm,      QOpenGLTexture::Int8,            2, false } },
345 { DXGI_FORMAT_R8G8B8A8_SNORM,                       { QOpenGLTexture::RGBA,             QOpenGLTexture::RGBA8_SNorm,    QOpenGLTexture::Int8,            4, false } },
346 
347 { DXGI_FORMAT_R16_SNORM,                            { QOpenGLTexture::Red,              QOpenGLTexture::R16_SNorm,      QOpenGLTexture::Int16,           2, false } },
348 { DXGI_FORMAT_R16G16_SNORM,                         { QOpenGLTexture::RG,               QOpenGLTexture::RG16_SNorm,     QOpenGLTexture::Int16,           4, false } },
349 { DXGI_FORMAT_R16G16B16A16_SNORM,                   { QOpenGLTexture::RGBA,             QOpenGLTexture::RGBA16_SNorm,   QOpenGLTexture::Int16,           8, false } },
350 
351 // unsigned integer formats
352 { DXGI_FORMAT_R8_UINT,                              { QOpenGLTexture::Red_Integer,      QOpenGLTexture::R8U,            QOpenGLTexture::UInt8,           1, false } },
353 { DXGI_FORMAT_R8G8_UINT,                            { QOpenGLTexture::RG_Integer,       QOpenGLTexture::RG8U,           QOpenGLTexture::UInt8,           2, false } },
354 { DXGI_FORMAT_R8G8B8A8_UINT,                        { QOpenGLTexture::RGBA_Integer,     QOpenGLTexture::RGBA8U,         QOpenGLTexture::UInt8,           4, false } },
355 
356 { DXGI_FORMAT_R16_UINT,                             { QOpenGLTexture::Red_Integer,      QOpenGLTexture::R16U,           QOpenGLTexture::UInt16,          2, false } },
357 { DXGI_FORMAT_R16G16_UINT,                          { QOpenGLTexture::RG_Integer,       QOpenGLTexture::RG16U,          QOpenGLTexture::UInt16,          4, false } },
358 { DXGI_FORMAT_R16G16B16A16_UINT,                    { QOpenGLTexture::RGBA_Integer,     QOpenGLTexture::RGBA16U,        QOpenGLTexture::UInt16,          8, false } },
359 
360 { DXGI_FORMAT_R32_UINT,                             { QOpenGLTexture::Red_Integer,      QOpenGLTexture::R32U,           QOpenGLTexture::UInt32,          4, false } },
361 { DXGI_FORMAT_R32G32_UINT,                          { QOpenGLTexture::RG_Integer,       QOpenGLTexture::RG32U,          QOpenGLTexture::UInt32,          8, false } },
362 { DXGI_FORMAT_R32G32B32_UINT,                       { QOpenGLTexture::RGB_Integer,      QOpenGLTexture::RGB32U,         QOpenGLTexture::UInt32,         12, false } },
363 { DXGI_FORMAT_R32G32B32A32_UINT,                    { QOpenGLTexture::RGBA_Integer,     QOpenGLTexture::RGBA32U,        QOpenGLTexture::UInt32,         16, false } },
364 
365 // signed integer formats
366 { DXGI_FORMAT_R8_SINT,                              { QOpenGLTexture::Red_Integer,      QOpenGLTexture::R8I,            QOpenGLTexture::Int8,            1, false } },
367 { DXGI_FORMAT_R8G8_SINT,                            { QOpenGLTexture::RG_Integer,       QOpenGLTexture::RG8I,           QOpenGLTexture::Int8,            2, false } },
368 { DXGI_FORMAT_R8G8B8A8_SINT,                        { QOpenGLTexture::RGBA_Integer,     QOpenGLTexture::RGBA8I,         QOpenGLTexture::Int8,            4, false } },
369 
370 { DXGI_FORMAT_R16_SINT,                             { QOpenGLTexture::Red_Integer,      QOpenGLTexture::R16I,           QOpenGLTexture::Int16,           2, false } },
371 { DXGI_FORMAT_R16G16_SINT,                          { QOpenGLTexture::RG_Integer,       QOpenGLTexture::RG16I,          QOpenGLTexture::Int16,           4, false } },
372 { DXGI_FORMAT_R16G16B16A16_SINT,                    { QOpenGLTexture::RGBA_Integer,     QOpenGLTexture::RGBA16I,        QOpenGLTexture::Int16,           8, false } },
373 
374 { DXGI_FORMAT_R32_SINT,                             { QOpenGLTexture::Red_Integer,      QOpenGLTexture::R32I,           QOpenGLTexture::Int32,           4, false } },
375 { DXGI_FORMAT_R32G32_SINT,                          { QOpenGLTexture::RG_Integer,       QOpenGLTexture::RG32I,          QOpenGLTexture::Int32,           8, false } },
376 { DXGI_FORMAT_R32G32B32_SINT,                       { QOpenGLTexture::RGB_Integer,      QOpenGLTexture::RGB32I,         QOpenGLTexture::Int32,          12, false } },
377 { DXGI_FORMAT_R32G32B32A32_SINT,                    { QOpenGLTexture::RGBA_Integer,     QOpenGLTexture::RGBA32I,        QOpenGLTexture::Int32,          16, false } },
378 
379 // floating formats
380 { DXGI_FORMAT_R16_FLOAT,                            { QOpenGLTexture::Red,              QOpenGLTexture::R16F,           QOpenGLTexture::Float16,         2, false } },
381 { DXGI_FORMAT_R16G16_FLOAT,                         { QOpenGLTexture::RG,               QOpenGLTexture::RG16F,          QOpenGLTexture::Float16,         4, false } },
382 { DXGI_FORMAT_R16G16B16A16_FLOAT,                   { QOpenGLTexture::RGBA,             QOpenGLTexture::RGBA16F,        QOpenGLTexture::Float16,         8, false } },
383 
384 { DXGI_FORMAT_R32_FLOAT,                            { QOpenGLTexture::Red,              QOpenGLTexture::R32F,           QOpenGLTexture::Float32,         4, false } },
385 { DXGI_FORMAT_R32G32_FLOAT,                         { QOpenGLTexture::RG,               QOpenGLTexture::RG32F,          QOpenGLTexture::Float32,         8, false } },
386 { DXGI_FORMAT_R32G32B32_FLOAT,                      { QOpenGLTexture::RGB,              QOpenGLTexture::RGB32F,         QOpenGLTexture::Float32,        12, false } },
387 { DXGI_FORMAT_R32G32B32A32_FLOAT,                   { QOpenGLTexture::RGBA,             QOpenGLTexture::RGBA32F,        QOpenGLTexture::Float32,        16, false } },
388 
389 // sRGB formats
390 { DXGI_FORMAT_B8G8R8X8_UNORM_SRGB,                  { QOpenGLTexture::RGB,              QOpenGLTexture::SRGB8,          QOpenGLTexture::UInt8,           4, false } },
391 { DXGI_FORMAT_R8G8B8A8_UNORM_SRGB,                  { QOpenGLTexture::RGBA,             QOpenGLTexture::SRGB8_Alpha8,   QOpenGLTexture::UInt8,           4, false } },
392 
393 // packed formats
394 // { DXGI_FORMAT_R10G10B10A2_UNORM,                 { QOpenGLTexture::RGB10A2_UNORM, QOpenGLTexture::RGBA, QOpenGLTexture::UInt32_RGB10A2, 4, false } },
395 { DXGI_FORMAT_R10G10B10A2_UINT,                     { QOpenGLTexture::RGBA_Integer,     QOpenGLTexture::RGB10A2,        QOpenGLTexture::UInt32_RGB10A2,  4, false } },
396 { DXGI_FORMAT_R9G9B9E5_SHAREDEXP,                   { QOpenGLTexture::RGB,              QOpenGLTexture::RGB9E5,         QOpenGLTexture::UInt32_RGB9_E5,  4, false } },
397 { DXGI_FORMAT_R11G11B10_FLOAT,                      { QOpenGLTexture::RGB,              QOpenGLTexture::RG11B10F,       QOpenGLTexture::UInt32_RG11B10F, 4, false } },
398 { DXGI_FORMAT_B5G6R5_UNORM,                         { QOpenGLTexture::RGB,              QOpenGLTexture::R5G6B5,         QOpenGLTexture::UInt16_R5G6B5,   2, false } },
399 { DXGI_FORMAT_B5G5R5A1_UNORM,                       { QOpenGLTexture::RGBA,             QOpenGLTexture::RGB5A1,         QOpenGLTexture::UInt16_RGB5A1,   2, false } },
400 { DXGI_FORMAT_B4G4R4A4_UNORM,                       { QOpenGLTexture::RGBA,             QOpenGLTexture::RGBA4,          QOpenGLTexture::UInt16_RGBA4,    2, false } },
401 
402 // swizzle formats
403 { DXGI_FORMAT_B8G8R8X8_UNORM,                       { QOpenGLTexture::BGRA,             QOpenGLTexture::RGB8_UNorm,     QOpenGLTexture::UInt8,           4, false } },
404 { DXGI_FORMAT_B8G8R8A8_UNORM,                       { QOpenGLTexture::BGRA,             QOpenGLTexture::RGBA8_UNorm,    QOpenGLTexture::UInt8,           4, false } },
405 { DXGI_FORMAT_B8G8R8X8_UNORM_SRGB,                  { QOpenGLTexture::BGRA,             QOpenGLTexture::SRGB8,          QOpenGLTexture::UInt8,           4, false } },
406 { DXGI_FORMAT_B8G8R8A8_UNORM_SRGB,                  { QOpenGLTexture::BGRA,             QOpenGLTexture::SRGB8_Alpha8,   QOpenGLTexture::UInt8,           4, false } },
407 
408 // luminance alpha formats
409 { DXGI_FORMAT_R8_UNORM,                             { QOpenGLTexture::Red,              QOpenGLTexture::R8_UNorm,       QOpenGLTexture::UInt8,           1, false } },
410 { DXGI_FORMAT_R8G8_UNORM,                           { QOpenGLTexture::RG,               QOpenGLTexture::RG8_UNorm,      QOpenGLTexture::UInt8,           2, false } },
411 { DXGI_FORMAT_R16_UNORM,                            { QOpenGLTexture::Red,              QOpenGLTexture::R16_UNorm,      QOpenGLTexture::UInt16,          2, false } },
412 { DXGI_FORMAT_R16G16_UNORM,                         { QOpenGLTexture::RG,               QOpenGLTexture::RG16_UNorm,     QOpenGLTexture::UInt16,          4, false } },
413 
414 // depth formats
415 { DXGI_FORMAT_D16_UNORM,                            { QOpenGLTexture::Depth,            QOpenGLTexture::D16,            QOpenGLTexture::NoPixelType,     2, false } },
416 { DXGI_FORMAT_D24_UNORM_S8_UINT,                    { QOpenGLTexture::DepthStencil,     QOpenGLTexture::D24S8,          QOpenGLTexture::NoPixelType,     4, false } },
417 { DXGI_FORMAT_D32_FLOAT,                            { QOpenGLTexture::Depth,            QOpenGLTexture::D32F,           QOpenGLTexture::NoPixelType,     4, false } },
418 { DXGI_FORMAT_D32_FLOAT_S8X24_UINT,                 { QOpenGLTexture::DepthStencil,     QOpenGLTexture::D32FS8X24,      QOpenGLTexture::NoPixelType,     8, false } },
419 
420 // compressed formats
421 { DXGI_FORMAT_BC1_UNORM,                            { QOpenGLTexture::NoSourceFormat,   QOpenGLTexture::RGBA_DXT1,      QOpenGLTexture::NoPixelType,     8, true } },
422 { DXGI_FORMAT_BC2_UNORM,                            { QOpenGLTexture::NoSourceFormat,   QOpenGLTexture::RGBA_DXT3,      QOpenGLTexture::NoPixelType,    16, true } },
423 { DXGI_FORMAT_BC3_UNORM,                            { QOpenGLTexture::NoSourceFormat,   QOpenGLTexture::RGBA_DXT5,      QOpenGLTexture::NoPixelType,    16, true } },
424 { DXGI_FORMAT_BC4_UNORM,                            { QOpenGLTexture::NoSourceFormat,   QOpenGLTexture::R_ATI1N_UNorm,  QOpenGLTexture::NoPixelType,     8, true } },
425 { DXGI_FORMAT_BC4_SNORM,                            { QOpenGLTexture::NoSourceFormat,   QOpenGLTexture::R_ATI1N_SNorm,  QOpenGLTexture::NoPixelType,     8, true } },
426 { DXGI_FORMAT_BC5_UNORM,                            { QOpenGLTexture::NoSourceFormat,   QOpenGLTexture::RG_ATI2N_UNorm, QOpenGLTexture::NoPixelType,    16, true } },
427 { DXGI_FORMAT_BC5_SNORM,                            { QOpenGLTexture::NoSourceFormat,   QOpenGLTexture::RG_ATI2N_SNorm, QOpenGLTexture::NoPixelType,    16, true } },
428 { DXGI_FORMAT_BC6H_UF16,                            { QOpenGLTexture::NoSourceFormat,   QOpenGLTexture::RGB_BP_UNSIGNED_FLOAT, QOpenGLTexture::NoPixelType, 16, true } },
429 { DXGI_FORMAT_BC6H_SF16,                            { QOpenGLTexture::NoSourceFormat,   QOpenGLTexture::RGB_BP_SIGNED_FLOAT, QOpenGLTexture::NoPixelType, 16, true } },
430 { DXGI_FORMAT_BC7_UNORM,                            { QOpenGLTexture::NoSourceFormat,   QOpenGLTexture::RGB_BP_UNorm, QOpenGLTexture::NoPixelType,      16, true } },
431 
432 // compressed sRGB formats
433 { DXGI_FORMAT_BC1_UNORM_SRGB,                       { QOpenGLTexture::NoSourceFormat,   QOpenGLTexture::SRGB_DXT1,      QOpenGLTexture::NoPixelType,     8, true } },
434 { DXGI_FORMAT_BC1_UNORM_SRGB,                       { QOpenGLTexture::NoSourceFormat,   QOpenGLTexture::SRGB_Alpha_DXT1, QOpenGLTexture::NoPixelType,    8, true } },
435 { DXGI_FORMAT_BC2_UNORM_SRGB,                       { QOpenGLTexture::NoSourceFormat,   QOpenGLTexture::SRGB_Alpha_DXT3, QOpenGLTexture::NoPixelType,   16, true } },
436 { DXGI_FORMAT_BC3_UNORM_SRGB,                       { QOpenGLTexture::NoSourceFormat,   QOpenGLTexture::SRGB_Alpha_DXT5, QOpenGLTexture::NoPixelType,   16, true } },
437 { DXGI_FORMAT_BC7_UNORM_SRGB,                       { QOpenGLTexture::NoSourceFormat,   QOpenGLTexture::SRGB_BP_UNorm,  QOpenGLTexture::NoPixelType,    16, true } },
438 };
439 
440 struct PkmHeader
441 {
442     char magic[4];
443     char version[2];
444     quint16 textureType;
445     quint16 paddedWidth;
446     quint16 paddedHeight;
447     quint16 width;
448     quint16 height;
449 };
450 
451 enum ImageFormat {
452     GenericImageFormat = 0,
453     DDS,
454     PKM,
455     HDR,
456     KTX
457 };
458 
imageFormatFromSuffix(const QString & suffix)459 ImageFormat imageFormatFromSuffix(const QString &suffix)
460 {
461     if (suffix == QStringLiteral("pkm"))
462         return PKM;
463     if (suffix == QStringLiteral("dds"))
464         return DDS;
465     if (suffix == QStringLiteral("hdr"))
466         return HDR;
467     if (suffix == QStringLiteral("ktx"))
468         return KTX;
469     return GenericImageFormat;
470 }
471 
472 // NOTE: the ktx loading code is a near-duplication of the code in qt3d-runtime, and changes
473 // should be kept up to date in both locations.
blockSizeForTextureFormat(QOpenGLTexture::TextureFormat format)474 quint32 blockSizeForTextureFormat(QOpenGLTexture::TextureFormat format)
475 {
476     switch (format) {
477     case QOpenGLTexture::RGB8_ETC1:
478     case QOpenGLTexture::RGB8_ETC2:
479     case QOpenGLTexture::SRGB8_ETC2:
480     case QOpenGLTexture::RGB8_PunchThrough_Alpha1_ETC2:
481     case QOpenGLTexture::SRGB8_PunchThrough_Alpha1_ETC2:
482     case QOpenGLTexture::R11_EAC_UNorm:
483     case QOpenGLTexture::R11_EAC_SNorm:
484     case QOpenGLTexture::RGB_DXT1:
485         return 8;
486 
487     default:
488         return 16;
489     }
490 }
491 
setKtxFile(QIODevice * source)492 QTextureImageDataPtr setKtxFile(QIODevice *source)
493 {
494     static const int KTX_IDENTIFIER_LENGTH = 12;
495     static const char ktxIdentifier[KTX_IDENTIFIER_LENGTH] = { '\xAB', 'K', 'T', 'X', ' ', '1', '1', '\xBB', '\r', '\n', '\x1A', '\n' };
496     static const quint32 platformEndianIdentifier = 0x04030201;
497     static const quint32 inversePlatformEndianIdentifier = 0x01020304;
498 
499     struct KTXHeader {
500         quint8 identifier[KTX_IDENTIFIER_LENGTH];
501         quint32 endianness;
502         quint32 glType;
503         quint32 glTypeSize;
504         quint32 glFormat;
505         quint32 glInternalFormat;
506         quint32 glBaseInternalFormat;
507         quint32 pixelWidth;
508         quint32 pixelHeight;
509         quint32 pixelDepth;
510         quint32 numberOfArrayElements;
511         quint32 numberOfFaces;
512         quint32 numberOfMipmapLevels;
513         quint32 bytesOfKeyValueData;
514     };
515 
516     KTXHeader header;
517     QTextureImageDataPtr imageData;
518     if (source->read(reinterpret_cast<char *>(&header), sizeof(header)) != sizeof(header)
519             || qstrncmp(reinterpret_cast<char *>(header.identifier), ktxIdentifier, KTX_IDENTIFIER_LENGTH) != 0
520             || (header.endianness != platformEndianIdentifier && header.endianness != inversePlatformEndianIdentifier))
521     {
522         return imageData;
523     }
524 
525     const bool isInverseEndian = (header.endianness == inversePlatformEndianIdentifier);
526     auto decode = [isInverseEndian](quint32 val) {
527         return isInverseEndian ? qbswap<quint32>(val) : val;
528     };
529 
530     const bool isCompressed = decode(header.glType) == 0 && decode(header.glFormat) == 0 && decode(header.glTypeSize) == 1;
531     if (!isCompressed) {
532         qWarning("Uncompressed ktx texture data is not supported");
533         return imageData;
534     }
535 
536     if (decode(header.numberOfArrayElements) != 0) {
537         qWarning("Array ktx textures not supported");
538         return imageData;
539     }
540 
541     if (decode(header.pixelDepth) != 0) {
542         qWarning("Only 2D and cube ktx textures are supported");
543         return imageData;
544     }
545 
546     const int bytesToSkip = decode(header.bytesOfKeyValueData);
547     if (source->read(bytesToSkip).count() != bytesToSkip) {
548         qWarning("Unexpected end of ktx data");
549         return imageData;
550     }
551 
552     const int level0Width = decode(header.pixelWidth);
553     const int level0Height = decode(header.pixelHeight);
554     const int faceCount = decode(header.numberOfFaces);
555     const int mipMapLevels = decode(header.numberOfMipmapLevels);
556     const QOpenGLTexture::TextureFormat format = QOpenGLTexture::TextureFormat(decode(header.glInternalFormat));
557     const int blockSize = blockSizeForTextureFormat(format);
558 
559     // now for each mipmap level we have (arrays and 3d textures not supported here)
560     // uint32 imageSize
561     // for each array element
562     //   for each face
563     //     for each z slice
564     //       compressed data
565     //     padding so that each face data starts at an offset that is a multiple of 4
566     // padding so that each imageSize starts at an offset that is a multiple of 4
567 
568     // assumes no depth or uncompressed textures (per above)
569     auto computeMipMapLevelSize = [&] (int level) {
570         const int w = qMax(level0Width >> level, 1);
571         const int h = qMax(level0Height >> level, 1);
572         return ((w + 3) / 4) * ((h + 3) / 4) * blockSize;
573     };
574 
575     int dataSize = 0;
576     for (auto i = 0; i < mipMapLevels; ++i)
577         dataSize += computeMipMapLevelSize(i) * faceCount + 4; // assumes a single layer (per above)
578 
579     const QByteArray rawData = source->read(dataSize);
580     if (rawData.size() < dataSize) {
581         qWarning() << "Unexpected end of data in" << source;
582         return imageData;
583     }
584 
585     if (!source->atEnd())
586         qWarning() << "Unrecognized data in" << source;
587 
588     imageData = QTextureImageDataPtr::create();
589     imageData->setTarget(faceCount == 6 ? QOpenGLTexture::TargetCubeMap : QOpenGLTexture::Target2D);
590     imageData->setFormat(format);
591     imageData->setWidth(level0Width);
592     imageData->setHeight(level0Height);
593     imageData->setLayers(1);
594     imageData->setDepth(1);
595     imageData->setFaces(faceCount);
596     imageData->setMipLevels(mipMapLevels);
597     imageData->setPixelFormat(QOpenGLTexture::NoSourceFormat);
598     imageData->setPixelType(QOpenGLTexture::NoPixelType);
599     imageData->setData(rawData, blockSize, true);
600     QTextureImageDataPrivate::get(imageData.data())->m_isKtx = true; // see note in QTextureImageDataPrivate
601 
602     return imageData;
603 }
604 
setPkmFile(QIODevice * source)605 QTextureImageDataPtr setPkmFile(QIODevice *source)
606 {
607     QTextureImageDataPtr imageData;
608 
609     PkmHeader header;
610     if ((source->read(reinterpret_cast<char *>(&header), sizeof header) != sizeof header)
611             || (qstrncmp(header.magic, "PKM ", 4) != 0))
612         return imageData;
613 
614     QOpenGLTexture::TextureFormat format = QOpenGLTexture::NoFormat;
615     int blockSize = 0;
616 
617     if (header.version[0] == '2' && header.version[1] == '0') {
618         switch (qFromBigEndian(header.textureType)) {
619         case 0:
620             format = QOpenGLTexture::RGB8_ETC1;
621             blockSize = 8;
622             break;
623 
624         case 1:
625             format = QOpenGLTexture::RGB8_ETC2;
626             blockSize = 8;
627             break;
628 
629         case 3:
630             format = QOpenGLTexture::RGBA8_ETC2_EAC;
631             blockSize = 16;
632             break;
633 
634         case 4:
635             format = QOpenGLTexture::RGB8_PunchThrough_Alpha1_ETC2;
636             blockSize = 8;
637             break;
638 
639         case 5:
640             format = QOpenGLTexture::R11_EAC_UNorm;
641             blockSize = 8;
642             break;
643 
644         case 6:
645             format = QOpenGLTexture::RG11_EAC_UNorm;
646             blockSize = 16;
647             break;
648 
649         case 7:
650             format = QOpenGLTexture::R11_EAC_SNorm;
651             blockSize = 8;
652             break;
653 
654         case 8:
655             format = QOpenGLTexture::RG11_EAC_SNorm;
656             blockSize = 16;
657             break;
658         }
659     } else {
660         format = QOpenGLTexture::RGB8_ETC1;
661         blockSize = 8;
662     }
663 
664     if (format == QOpenGLTexture::NoFormat) {
665         qWarning() << "Unrecognized compression format in" << source;
666         return imageData;
667     }
668 
669     // get the extended (multiple of 4) width and height
670     const int width = qFromBigEndian(header.paddedWidth);
671     const int height = qFromBigEndian(header.paddedHeight);
672 
673     const QByteArray data = source->readAll();
674     if (data.size() != (width / 4) * (height / 4) * blockSize) {
675         qWarning() << "Unexpected data size in" << source;
676         return imageData;
677     }
678 
679     imageData = QTextureImageDataPtr::create();
680     imageData->setTarget(QOpenGLTexture::Target2D);
681     imageData->setFormat(format);
682     imageData->setWidth(width);
683     imageData->setHeight(height);
684     imageData->setLayers(1);
685     imageData->setDepth(1);
686     imageData->setFaces(1);
687     imageData->setMipLevels(1);
688     imageData->setPixelFormat(QOpenGLTexture::NoSourceFormat);
689     imageData->setPixelType(QOpenGLTexture::NoPixelType);
690     imageData->setData(data, blockSize, true);
691 
692     return imageData;
693 }
694 
setDdsFile(QIODevice * source)695 QTextureImageDataPtr setDdsFile(QIODevice *source)
696 {
697     QTextureImageDataPtr imageData;
698 
699     DdsHeader header;
700     if ((source->read(reinterpret_cast<char *>(&header), sizeof header) != sizeof header)
701             || (qstrncmp(header.magic, "DDS ", 4) != 0))
702         return imageData;
703 
704     int layers = 1;
705     const quint32 pixelFlags = qFromLittleEndian(header.pixelFormat.flags);
706     const quint32 fourCC = qFromLittleEndian(header.pixelFormat.fourCC);
707     const FormatInfo *formatInfo = nullptr;
708 
709     if ((pixelFlags & FourCCFlag) == FourCCFlag) {
710         if (fourCC == DdsFourCC<'D', 'X', '1', '0'>::value) {
711             // DX10 texture
712             DdsDX10Header dx10Header;
713             if (source->read(reinterpret_cast<char *>(&dx10Header), sizeof dx10Header) != sizeof dx10Header)
714                 return imageData;
715 
716             layers = qFromLittleEndian(dx10Header.arraySize);
717             DXGIFormat format = static_cast<DXGIFormat>(qFromLittleEndian(dx10Header.format));
718 
719             for (const auto &info : dx10Formats) {
720                 if (info.dxgiFormat == format) {
721                     formatInfo = &info.formatInfo;
722                     break;
723                 }
724             }
725         } else {
726             // compressed, FourCC texture
727             for (const auto &info : fourCCFormats) {
728                 if (info.fourCC == fourCC) {
729                     formatInfo = &info.formatInfo;
730                     break;
731                 }
732             }
733         }
734     } else {
735         // uncompressed texture
736         const quint32 rgbBitCount   = qFromLittleEndian(header.pixelFormat.rgbBitCount);
737         const quint32 redMask       = qFromLittleEndian(header.pixelFormat.redMask);
738         const quint32 greenMask     = qFromLittleEndian(header.pixelFormat.greenMask);
739         const quint32 blueMask      = qFromLittleEndian(header.pixelFormat.blueMask);
740         const quint32 alphaMask     = qFromLittleEndian(header.pixelFormat.alphaMask);
741 
742         for (const auto &info : rgbaFormats) {
743             if (info.formatInfo.components * 8u == rgbBitCount &&
744                     info.redMask == redMask && info.greenMask == greenMask &&
745                     info.blueMask == blueMask && info.alphaMask == alphaMask) {
746                 formatInfo = &info.formatInfo;
747                 break;
748             }
749         }
750     }
751 
752     if (formatInfo == nullptr) {
753         qWarning() << "Unrecognized pixel format in" << source;
754         return imageData;
755     }
756 
757     // target
758     // XXX should worry about Target1D?
759     QOpenGLTexture::Target target;
760     const int width = qFromLittleEndian(header.width);
761     const int height = qFromLittleEndian(header.height);
762     const quint32 caps2Flags = qFromLittleEndian(header.caps2);
763     const int blockSize = formatInfo->components;
764     const bool isCompressed = formatInfo->compressed;
765     const int mipLevelCount = ((qFromLittleEndian(header.flags) & MipmapCountFlag) == MipmapCountFlag) ? qFromLittleEndian(header.mipmapCount) : 1;
766     int depth;
767     int faces;
768 
769     if ((caps2Flags & VolumeFlag) == VolumeFlag) {
770         target = QOpenGLTexture::Target3D;
771         depth = qFromLittleEndian(header.depth);
772         faces = 1;
773     } else if ((caps2Flags & CubemapFlag) == CubemapFlag) {
774         target = layers > 1 ? QOpenGLTexture::TargetCubeMapArray : QOpenGLTexture::TargetCubeMap;
775         depth = 1;
776         faces = qPopulationCount(caps2Flags & AllCubemapFaceFlags);
777     } else {
778         target = layers > 1 ? QOpenGLTexture::Target2DArray : QOpenGLTexture::Target2D;
779         depth = 1;
780         faces = 1;
781     }
782 
783     int layerSize = 0;
784     int tmpSize = 0;
785 
786     auto computeMipMapLevelSize = [&] (int level) {
787         const int w = qMax(width >> level, 1);
788         const int h = qMax(height >> level, 1);
789         const int d = qMax(depth >> level, 1);
790 
791         if (isCompressed)
792             return ((w + 3) / 4) * ((h + 3) / 4) * blockSize * d;
793         else
794             return w * h * blockSize * d;
795     };
796 
797     for (auto i = 0; i < mipLevelCount; ++i)
798         tmpSize += computeMipMapLevelSize(i);
799 
800     layerSize = faces * tmpSize;
801 
802     // data
803     const int dataSize = layers * layerSize;
804 
805     const QByteArray data = source->read(dataSize);
806     if (data.size() < dataSize) {
807         qWarning() << "Unexpected end of data in" << source;
808         return imageData;
809     }
810 
811     if (!source->atEnd())
812         qWarning() << "Unrecognized data in" << source;
813 
814     imageData = QTextureImageDataPtr::create();
815     imageData->setData(data,blockSize, isCompressed);
816 
817     // target
818     imageData->setTarget(target);
819 
820     // mip levels
821     imageData->setMipLevels(mipLevelCount);
822 
823     // texture format
824     imageData->setFormat(formatInfo->textureFormat);
825     imageData->setPixelType(formatInfo->pixelType);
826     imageData->setPixelFormat(formatInfo->pixelFormat);
827 
828     // dimensions
829     imageData->setLayers(layers);
830     imageData->setDepth(depth);
831     imageData->setWidth(width);
832     imageData->setHeight(height);
833     imageData->setFaces(faces);
834 
835     return imageData;
836 }
837 
838 // Loads Radiance RGBE images into RGBA32F image data. RGBA is chosen over RGB
839 // because this allows passing such images to compute shaders (image2D).
setHdrFile(QIODevice * source)840 QTextureImageDataPtr setHdrFile(QIODevice *source)
841 {
842     QTextureImageDataPtr imageData;
843     char sig[256];
844     source->read(sig, 11);
845     if (strncmp(sig, "#?RADIANCE\n", 11))
846         return imageData;
847 
848     QByteArray buf = source->readAll();
849     const char *p = buf.constData();
850     const char *pEnd = p + buf.size();
851 
852     // Process lines until the empty one.
853     QByteArray line;
854     while (p < pEnd) {
855         char c = *p++;
856         if (c == '\n') {
857             if (line.isEmpty())
858                 break;
859             if (line.startsWith(QByteArrayLiteral("FORMAT="))) {
860                 const QByteArray format = line.mid(7).trimmed();
861                 if (format != QByteArrayLiteral("32-bit_rle_rgbe")) {
862                     qWarning("HDR format '%s' is not supported", format.constData());
863                     return imageData;
864                 }
865             }
866             line.clear();
867         } else {
868             line.append(c);
869         }
870     }
871     if (p == pEnd) {
872         qWarning("Malformed HDR image data at property strings");
873         return imageData;
874     }
875 
876     // Get the resolution string.
877     while (p < pEnd) {
878         char c = *p++;
879         if (c == '\n')
880             break;
881         line.append(c);
882     }
883     if (p == pEnd) {
884         qWarning("Malformed HDR image data at resolution string");
885         return imageData;
886     }
887 
888     int w = 0, h = 0;
889     // We only care about the standard orientation.
890     if (!sscanf(line.constData(), "-Y %d +X %d", &h, &w)) {
891         qWarning("Unsupported HDR resolution string '%s'", line.constData());
892         return imageData;
893     }
894     if (w <= 0 || h <= 0) {
895         qWarning("Invalid HDR resolution");
896         return imageData;
897     }
898 
899     const QOpenGLTexture::TextureFormat textureFormat = QOpenGLTexture::RGBA32F;
900     const QOpenGLTexture::PixelFormat pixelFormat = QOpenGLTexture::RGBA;
901     const QOpenGLTexture::PixelType pixelType = QOpenGLTexture::Float32;
902     const int blockSize = 4 * sizeof(float);
903     QByteArray data;
904     data.resize(w * h * blockSize);
905 
906     typedef unsigned char RGBE[4];
907     RGBE *scanline = new RGBE[w];
908 
909     for (int y = 0; y < h; ++y) {
910         if (pEnd - p < 4) {
911             qWarning("Unexpected end of HDR data");
912             delete[] scanline;
913             return imageData;
914         }
915 
916         scanline[0][0] = *p++;
917         scanline[0][1] = *p++;
918         scanline[0][2] = *p++;
919         scanline[0][3] = *p++;
920 
921         if (scanline[0][0] == 2 && scanline[0][1] == 2 && scanline[0][2] < 128) {
922             // new rle, the first pixel was a dummy
923             for (int channel = 0; channel < 4; ++channel) {
924                 for (int x = 0; x < w && p < pEnd; ) {
925                     unsigned char c = *p++;
926                     if (c > 128) { // run
927                         if (p < pEnd) {
928                             int repCount = c & 127;
929                             c = *p++;
930                             while (repCount--)
931                                 scanline[x++][channel] = c;
932                         }
933                     } else { // not a run
934                         while (c-- && p < pEnd)
935                             scanline[x++][channel] = *p++;
936                     }
937                 }
938             }
939         } else {
940             // old rle
941             scanline[0][0] = 2;
942             int bitshift = 0;
943             int x = 1;
944             while (x < w && pEnd - p >= 4) {
945                 scanline[x][0] = *p++;
946                 scanline[x][1] = *p++;
947                 scanline[x][2] = *p++;
948                 scanline[x][3] = *p++;
949 
950                 if (scanline[x][0] == 1 && scanline[x][1] == 1 && scanline[x][2] == 1) { // run
951                     int repCount = scanline[x][3] << bitshift;
952                     while (repCount--) {
953                         memcpy(scanline[x], scanline[x - 1], 4);
954                         ++x;
955                     }
956                     bitshift += 8;
957                 } else { // not a run
958                     ++x;
959                     bitshift = 0;
960                 }
961             }
962         }
963 
964         // adjust for -Y orientation
965         float *fp = reinterpret_cast<float *>(data.data() + (h - 1 - y) * blockSize * w);
966         for (int x = 0; x < w; ++x) {
967             float d = qPow(2.0f, float(scanline[x][3]) - 128.0f);
968             // r, g, b, a
969             *fp++ = scanline[x][0] / 256.0f * d;
970             *fp++ = scanline[x][1] / 256.0f * d;
971             *fp++ = scanline[x][2] / 256.0f * d;
972             *fp++ = 1.0f;
973         }
974     }
975 
976     delete[] scanline;
977 
978     imageData = QTextureImageDataPtr::create();
979     imageData->setTarget(QOpenGLTexture::Target2D);
980     imageData->setFormat(textureFormat);
981     imageData->setWidth(w);
982     imageData->setHeight(h);
983     imageData->setLayers(1);
984     imageData->setDepth(1);
985     imageData->setFaces(1);
986     imageData->setMipLevels(1);
987     imageData->setPixelFormat(pixelFormat);
988     imageData->setPixelType(pixelType);
989     imageData->setData(data, blockSize, false);
990 
991     return imageData;
992 }
993 
994 } // anonynous
995 
loadTextureData(const QUrl & url,bool allow3D,bool mirrored)996 QTextureImageDataPtr TextureLoadingHelper::loadTextureData(const QUrl &url, bool allow3D, bool mirrored)
997 {
998     QTextureImageDataPtr textureData;
999     if (url.isLocalFile() || url.scheme() == QLatin1String("qrc")
1000 #ifdef Q_OS_ANDROID
1001             || url.scheme() == QLatin1String("assets")
1002 #endif
1003             ) {
1004         const QString source = Qt3DRender::QUrlHelper::urlToLocalFileOrQrc(url);
1005         QFile f(source);
1006         if (!f.open(QIODevice::ReadOnly))
1007             qWarning() << "Failed to open" << source;
1008         else
1009             textureData = loadTextureData(&f, QFileInfo(source).suffix().toLower(), allow3D, mirrored);
1010     }
1011     return textureData;
1012 }
1013 
loadTextureData(QIODevice * data,const QString & suffix,bool allow3D,bool mirrored)1014 QTextureImageDataPtr TextureLoadingHelper::loadTextureData(QIODevice *data, const QString& suffix,
1015                                                            bool allow3D, bool mirrored)
1016 {
1017     QTextureImageDataPtr textureData;
1018     ImageFormat fmt = imageFormatFromSuffix(suffix);
1019     switch (fmt) {
1020     case DDS:
1021         textureData = setDdsFile(data);
1022         break;
1023     case PKM:
1024         textureData = setPkmFile(data);
1025         break;
1026     case HDR:
1027         textureData = setHdrFile(data);
1028         break;
1029     case KTX: {
1030         textureData = setKtxFile(data);
1031         break;
1032     }
1033     default: {
1034         QImage img;
1035         if (img.load(data, suffix.toLatin1())) {
1036             textureData = QTextureImageDataPtr::create();
1037             textureData->setImage(mirrored ? img.mirrored() : img);
1038         } else {
1039             qWarning() << "Failed to load textureImage data using QImage";
1040         }
1041         break;
1042     }
1043     }
1044 
1045     if (!allow3D && textureData && (textureData->layers() > 1 || textureData->depth() > 1))
1046         qWarning() << "Texture data has a 3rd dimension which wasn't expected";
1047     return textureData;
1048 }
1049 
operator ()()1050 QTextureDataPtr QTextureFromSourceGenerator::operator ()()
1051 {
1052     QTextureDataPtr generatedData = QTextureDataPtr::create();
1053     QTextureImageDataPtr textureData;
1054 
1055     // Note: First and Second call can be seen as operator() being called twice
1056     // on the same object but actually call 2 will be made on a new generator
1057     // which is the copy of the generator used for call 1 but with m_sourceData
1058     // set.
1059     // This is required because updating the same functor wouldn't be picked up
1060     // by the backend texture sharing system.
1061     if (!Qt3DCore::QDownloadHelperService::isLocal(m_url)) {
1062         if (m_sourceData.isEmpty()) {
1063             // first time around, trigger a download
1064             if (m_texture) {
1065                 auto downloadService = Qt3DCore::QDownloadHelperService::getService(m_engine);
1066                 Qt3DCore::QDownloadRequestPtr request(new TextureDownloadRequest(sharedFromThis(),
1067                                                                                  m_url,
1068                                                                                  m_engine,
1069                                                                                  m_texture));
1070                 downloadService->submitRequest(request);
1071             }
1072             return generatedData;
1073         }
1074 
1075         // second time around, we have the data
1076         QT_PREPEND_NAMESPACE(QBuffer) buffer(&m_sourceData);
1077         if (buffer.open(QIODevice::ReadOnly)) {
1078             QString suffix = m_url.toString();
1079             suffix = suffix.right(suffix.length() - suffix.lastIndexOf('.'));
1080 
1081             QStringList ext(suffix);
1082 
1083             QMimeDatabase db;
1084             QMimeType mtype = db.mimeTypeForData(m_sourceData);
1085             if (mtype.isValid()) {
1086                 ext << mtype.suffixes();
1087             }
1088 
1089             for (const QString &s: qAsConst(ext)) {
1090                 textureData = TextureLoadingHelper::loadTextureData(&buffer, s, true, m_mirrored);
1091                 if (textureData && textureData->data().length() > 0)
1092                     break;
1093             }
1094         }
1095     } else {
1096         textureData = TextureLoadingHelper::loadTextureData(m_url, true, m_mirrored);
1097     }
1098 
1099     // Update any properties explicitly set by the user
1100     if (textureData && m_format != QAbstractTexture::NoFormat && m_format != QAbstractTexture::Automatic)
1101         textureData->setFormat(static_cast<QOpenGLTexture::TextureFormat>(m_format));
1102 
1103     if (textureData && textureData->data().length() > 0) {
1104         generatedData->setTarget(static_cast<QAbstractTexture::Target>(textureData->target()));
1105         generatedData->setFormat(static_cast<QAbstractTexture::TextureFormat>(textureData->format()));
1106         generatedData->setWidth(textureData->width());
1107         generatedData->setHeight(textureData->height());
1108         generatedData->setDepth(textureData->depth());
1109         generatedData->setLayers(textureData->layers());
1110         generatedData->addImageData(textureData);
1111     }
1112 
1113     return generatedData;
1114 }
1115 
TextureDownloadRequest(const QTextureFromSourceGeneratorPtr & functor,const QUrl & source,Qt3DCore::QAspectEngine * engine,Qt3DCore::QNodeId texNodeId)1116 TextureDownloadRequest::TextureDownloadRequest(const QTextureFromSourceGeneratorPtr &functor,
1117                                                const QUrl &source,
1118                                                Qt3DCore::QAspectEngine *engine,
1119                                                Qt3DCore::QNodeId texNodeId)
1120     : Qt3DCore::QDownloadRequest(source)
1121     , m_functor(functor)
1122     , m_engine(engine)
1123     , m_texNodeId(texNodeId)
1124 {
1125 
1126 }
1127 
1128 // Executed in main thread
onCompleted()1129 void TextureDownloadRequest::onCompleted()
1130 {
1131     if (cancelled() || !succeeded())
1132         return;
1133 
1134     QRenderAspectPrivate* d_aspect = QRenderAspectPrivate::findPrivate(m_engine);
1135     if (!d_aspect)
1136         return;
1137 
1138     Render::TextureManager *textureManager = d_aspect->m_nodeManagers->textureManager();
1139     Render::Texture *texture = textureManager->lookupResource(m_texNodeId);
1140     if (texture == nullptr)
1141         return;
1142 
1143     QTextureFromSourceGeneratorPtr oldGenerator = qSharedPointerCast<QTextureFromSourceGenerator>(texture->dataGenerator());
1144 
1145     // Set raw data on functor so that it can really load something
1146     oldGenerator->m_sourceData = m_data;
1147 
1148     // Mark the texture as dirty so that the functor runs again with the downloaded data
1149     texture->addDirtyFlag(Render::Texture::DirtyDataGenerator);
1150 }
1151 
1152 /*!
1153     \class Qt3DRender::QTexture1D
1154     \inheaderfile Qt3DRender/QTexture
1155     \inmodule Qt3DRender
1156     \since 5.5
1157     \brief A QAbstractTexture with a Target1D target format.
1158  */
1159 /*!
1160     \qmltype Texture1D
1161     \instantiates Qt3DRender::QTexture1D
1162     \inqmlmodule Qt3D.Render
1163     \since 5.5
1164     \brief An AbstractTexture with a Target1D target format.
1165  */
1166 
1167 /*!
1168     Constructs a new Qt3DRender::QTexture1D instance with \a parent as parent.
1169  */
QTexture1D(QNode * parent)1170 QTexture1D::QTexture1D(QNode *parent)
1171     : QAbstractTexture(Target1D, parent)
1172 {
1173 }
1174 
1175 /*! \internal */
~QTexture1D()1176 QTexture1D::~QTexture1D()
1177 {
1178 }
1179 
1180 /*!
1181     \class Qt3DRender::QTexture1DArray
1182     \inheaderfile Qt3DRender/QTexture
1183     \inmodule Qt3DRender
1184     \since 5.5
1185     \brief A QAbstractTexture with a Target1DArray target format.
1186  */
1187 /*!
1188     \qmltype Texture1DArray
1189     \instantiates Qt3DRender::QTexture1DArray
1190     \inqmlmodule Qt3D.Render
1191     \since 5.5
1192     \brief An AbstractTexture with a Target1DArray target format.
1193  */
1194 
1195 /*!
1196     Constructs a new Qt3DRender::QTexture1DArray instance with \a parent as parent.
1197  */
QTexture1DArray(QNode * parent)1198 QTexture1DArray::QTexture1DArray(QNode *parent)
1199     : QAbstractTexture(Target1DArray, parent)
1200 {
1201 }
1202 
1203 /*! \internal */
~QTexture1DArray()1204 QTexture1DArray::~QTexture1DArray()
1205 {
1206 }
1207 
1208 /*!
1209     \class Qt3DRender::QTexture2D
1210     \inheaderfile Qt3DRender/QTexture
1211     \inmodule Qt3DRender
1212     \since 5.5
1213     \brief A QAbstractTexture with a Target2D target format.
1214  */
1215 /*!
1216     \qmltype Texture2D
1217     \instantiates Qt3DRender::QTexture2D
1218     \inqmlmodule Qt3D.Render
1219     \since 5.5
1220     \brief An AbstractTexture with a Target2D target format.
1221  */
1222 
1223 /*!
1224     Constructs a new Qt3DRender::QTexture2D instance with \a parent as parent.
1225  */
QTexture2D(QNode * parent)1226 QTexture2D::QTexture2D(QNode *parent)
1227     : QAbstractTexture(Target2D, parent)
1228 {
1229 }
1230 
1231 /*! \internal */
~QTexture2D()1232 QTexture2D::~QTexture2D()
1233 {
1234 }
1235 
1236 /*!
1237     \class Qt3DRender::QTexture2DArray
1238     \inheaderfile Qt3DRender/QTexture
1239     \inmodule Qt3DRender
1240     \since 5.5
1241     \brief A QAbstractTexture with a Target2DArray target format.
1242  */
1243 /*!
1244     \qmltype Texture2DArray
1245     \instantiates Qt3DRender::QTexture2DArray
1246     \inqmlmodule Qt3D.Render
1247     \since 5.5
1248     \brief An AbstractTexture with a Target2DArray target format.
1249  */
1250 
1251 /*!
1252     Constructs a new Qt3DRender::QTexture2DArray instance with \a parent as parent.
1253  */
QTexture2DArray(QNode * parent)1254 QTexture2DArray::QTexture2DArray(QNode *parent)
1255     : QAbstractTexture(Target2DArray, parent)
1256 {
1257 }
1258 
1259 /*! \internal */
~QTexture2DArray()1260 QTexture2DArray::~QTexture2DArray()
1261 {
1262 }
1263 
1264 /*!
1265     \class Qt3DRender::QTexture3D
1266     \inheaderfile Qt3DRender/QTexture
1267     \inmodule Qt3DRender
1268     \since 5.5
1269     \brief A QAbstractTexture with a Target3D target format.
1270  */
1271 /*!
1272     \qmltype Texture3D
1273     \instantiates Qt3DRender::QTexture3D
1274     \inqmlmodule Qt3D.Render
1275     \since 5.5
1276     \brief An AbstractTexture with a Target3D target format.
1277  */
1278 
1279 /*!
1280     Constructs a new Qt3DRender::QTexture3D instance with \a parent as parent.
1281  */
QTexture3D(QNode * parent)1282 QTexture3D::QTexture3D(QNode *parent)
1283     : QAbstractTexture(Target3D, parent)
1284 {
1285 }
1286 
1287 /*! \internal */
~QTexture3D()1288 QTexture3D::~QTexture3D()
1289 {
1290 }
1291 
1292 /*!
1293     \class Qt3DRender::QTextureCubeMap
1294     \inheaderfile Qt3DRender/QTexture
1295     \inmodule Qt3DRender
1296     \since 5.5
1297     \brief A QAbstractTexture with a TargetCubeMap target format.
1298  */
1299 /*!
1300     \qmltype TextureCubeMap
1301     \instantiates Qt3DRender::QTextureCubeMap
1302     \inqmlmodule Qt3D.Render
1303     \since 5.5
1304     \brief An AbstractTexture with a TargetCubeMap target format.
1305  */
1306 
1307 /*!
1308     Constructs a new Qt3DRender::QTextureCubeMap instance with \a parent as parent.
1309  */
QTextureCubeMap(QNode * parent)1310 QTextureCubeMap::QTextureCubeMap(QNode *parent)
1311     : QAbstractTexture(TargetCubeMap, parent)
1312 {
1313 }
1314 
1315 /*! \internal */
~QTextureCubeMap()1316 QTextureCubeMap::~QTextureCubeMap()
1317 {
1318 }
1319 
1320 /*!
1321     \class Qt3DRender::QTextureCubeMapArray
1322     \inheaderfile Qt3DRender/QTexture
1323     \inmodule Qt3DRender
1324     \since 5.5
1325     \brief A QAbstractTexture with a TargetCubeMapArray target format.
1326  */
1327 /*!
1328     \qmltype TextureCubeMapArray
1329     \instantiates Qt3DRender::QTextureCubeMapArray
1330     \inqmlmodule Qt3D.Render
1331     \since 5.5
1332     \brief An AbstractTexture with a TargetCubeMapArray target format.
1333  */
1334 
1335 /*!
1336     Constructs a new Qt3DRender::QTextureCubeMapArray instance with \a parent as parent.
1337  */
QTextureCubeMapArray(QNode * parent)1338 QTextureCubeMapArray::QTextureCubeMapArray(QNode *parent)
1339     : QAbstractTexture(TargetCubeMapArray, parent)
1340 {
1341 }
1342 
1343 /*! \internal */
~QTextureCubeMapArray()1344 QTextureCubeMapArray::~QTextureCubeMapArray()
1345 {
1346 }
1347 
1348 /*!
1349     \class Qt3DRender::QTexture2DMultisample
1350     \inheaderfile Qt3DRender/QTexture
1351     \inmodule Qt3DRender
1352     \since 5.5
1353     \brief A QAbstractTexture with a Target2DMultisample target format.
1354  */
1355 /*!
1356     \qmltype Texture2DMultisample
1357     \instantiates Qt3DRender::QTexture2DMultisample
1358     \inqmlmodule Qt3D.Render
1359     \since 5.5
1360     \brief An AbstractTexture with a Target2DMultisample target format.
1361  */
1362 
1363 /*!
1364     Constructs a new Qt3DRender::QTexture2DMultisample instance with \a parent as parent.
1365  */
QTexture2DMultisample(QNode * parent)1366 QTexture2DMultisample::QTexture2DMultisample(QNode *parent)
1367     : QAbstractTexture(Target2DMultisample, parent)
1368 {
1369 }
1370 
1371 /*! \internal */
~QTexture2DMultisample()1372 QTexture2DMultisample::~QTexture2DMultisample()
1373 {
1374 }
1375 
1376 /*!
1377     \class Qt3DRender::QTexture2DMultisampleArray
1378     \inheaderfile Qt3DRender/QTexture
1379     \inmodule Qt3DRender
1380     \since 5.5
1381     \brief A QAbstractTexture with a Target2DMultisampleArray target format.
1382  */
1383 /*!
1384     \qmltype Texture2DMultisampleArray
1385     \instantiates Qt3DRender::QTexture2DMultisampleArray
1386     \inqmlmodule Qt3D.Render
1387     \since 5.5
1388     \brief An AbstractTexture with a Target2DMultisampleArray target format.
1389  */
1390 
1391 /*!
1392     Constructs a new Qt3DRender::QTexture2DMultisampleArray instance with \a parent as parent.
1393  */
QTexture2DMultisampleArray(QNode * parent)1394 QTexture2DMultisampleArray::QTexture2DMultisampleArray(QNode *parent)
1395     : QAbstractTexture(Target2DMultisampleArray, parent)
1396 {
1397 }
1398 
1399 /*! \internal */
~QTexture2DMultisampleArray()1400 QTexture2DMultisampleArray::~QTexture2DMultisampleArray()
1401 {
1402 }
1403 
1404 /*!
1405     \class Qt3DRender::QTextureRectangle
1406     \inheaderfile Qt3DRender/QTexture
1407     \inmodule Qt3DRender
1408     \since 5.5
1409     \brief A QAbstractTexture with a TargetRectangle target format.
1410  */
1411 /*!
1412     \qmltype TextureRectangle
1413     \instantiates Qt3DRender::QTextureRectangle
1414     \inqmlmodule Qt3D.Render
1415     \since 5.5
1416     \brief An AbstractTexture with a TargetRectangle target format.
1417  */
1418 
1419 /*!
1420     Constructs a new Qt3DRender::QTextureRectangle instance with \a parent as parent.
1421  */
QTextureRectangle(QNode * parent)1422 QTextureRectangle::QTextureRectangle(QNode *parent)
1423     : QAbstractTexture(TargetRectangle, parent)
1424 {
1425 }
1426 
1427 /*! \internal */
~QTextureRectangle()1428 QTextureRectangle::~QTextureRectangle()
1429 {
1430 }
1431 
1432 /*!
1433     \class Qt3DRender::QTextureBuffer
1434     \inheaderfile Qt3DRender/QTexture
1435     \inmodule Qt3DRender
1436     \since 5.5
1437     \brief A QAbstractTexture with a TargetBuffer target format.
1438  */
1439 /*!
1440     \qmltype TextureBuffer
1441     \instantiates Qt3DRender::QTextureBuffer
1442     \inqmlmodule Qt3D.Render
1443     \since 5.5
1444     \brief An AbstractTexture with a TargetBuffer target format.
1445  */
1446 
1447 /*!
1448     Constructs a new Qt3DRender::QTextureBuffer instance with \a parent as parent.
1449  */
QTextureBuffer(QNode * parent)1450 QTextureBuffer::QTextureBuffer(QNode *parent)
1451     : QAbstractTexture(TargetBuffer, parent)
1452 {
1453 }
1454 
1455 /*! \internal */
~QTextureBuffer()1456 QTextureBuffer::~QTextureBuffer()
1457 {
1458 }
1459 
QTextureLoaderPrivate()1460 QTextureLoaderPrivate::QTextureLoaderPrivate()
1461     : QAbstractTexturePrivate()
1462     , m_mirrored(true)
1463 {
1464 }
1465 
setScene(Qt3DCore::QScene * scene)1466 void QTextureLoaderPrivate::setScene(Qt3DCore::QScene *scene)
1467 {
1468     QAbstractTexturePrivate::setScene(scene);
1469     updateGenerator();
1470 }
1471 
updateGenerator()1472 void QTextureLoaderPrivate::updateGenerator()
1473 {
1474     Q_Q(QTextureLoader);
1475     Qt3DCore::QAspectEngine *engine = m_scene ? m_scene->engine() : nullptr;
1476     setDataFunctor(QTextureFromSourceGeneratorPtr::create(q, engine, m_id));
1477 }
1478 
1479 /*!
1480    \class Qt3DRender::QTextureLoader
1481    \inheaderfile Qt3DRender/QTexture
1482    \inmodule Qt3DRender
1483    \brief Handles the texture loading and setting the texture's properties.
1484 */
1485 /*!
1486    \qmltype TextureLoader
1487    \instantiates Qt3DRender::QTextureLoader
1488    \inqmlmodule Qt3D.Render
1489 
1490    \brief Handles the texture loading and setting the texture's properties.
1491 */
1492 /*!
1493  * Constructs a new Qt3DRender::QTextureLoader instance with \a parent as parent.
1494  *
1495  * Note that by default, if not contradicted by the file metadata, the loaded texture
1496  * will have the following properties set:
1497  *  - wrapMode set to Repeat
1498  *  - minificationFilter set to LinearMipMapLinear
1499  *  - magnificationFilter set to Linear
1500  *  - generateMipMaps set to true
1501  *  - maximumAnisotropy set to 16.0f
1502  *  - target set to TargetAutomatic
1503  */
QTextureLoader(QNode * parent)1504 QTextureLoader::QTextureLoader(QNode *parent)
1505     : QAbstractTexture(*new QTextureLoaderPrivate, parent)
1506 {
1507     d_func()->m_wrapMode.setX(QTextureWrapMode::Repeat);
1508     d_func()->m_wrapMode.setY(QTextureWrapMode::Repeat);
1509     d_func()->m_minFilter = LinearMipMapLinear;
1510     d_func()->m_magFilter = Linear;
1511     d_func()->m_autoMipMap = true;
1512     d_func()->m_maximumAnisotropy = 16.0f;
1513     d_func()->m_target = TargetAutomatic;
1514 
1515     // Regenerate the texture functor when properties we support overriding
1516     // from QAbstractTexture get changed.
1517     Q_D(QTextureLoader);
1518     auto regenerate = [=] () {
1519         if (!notificationsBlocked())    // check the change doesn't come from the backend
1520             d->updateGenerator();
1521     };
1522     connect(this, &QAbstractTexture::formatChanged, regenerate);
1523 }
1524 
1525 /*! \internal */
~QTextureLoader()1526 QTextureLoader::~QTextureLoader()
1527 {
1528 }
1529 
1530 /*!
1531     \property QTextureLoader::source
1532 
1533     \brief The current texture source.
1534 */
1535 /*!
1536     \qmlproperty url Qt3D.Render::TextureLoader::source
1537 
1538     This property holds the current texture source.
1539 */
source() const1540 QUrl QTextureLoader::source() const
1541 {
1542     Q_D(const QTextureLoader);
1543     return d->m_source;
1544 }
1545 
isMirrored() const1546 bool QTextureLoader::isMirrored() const
1547 {
1548     Q_D(const QTextureLoader);
1549     return d->m_mirrored;
1550 }
1551 
1552 /*!
1553  * Sets the texture loader source to \a source.
1554  * \param source
1555  */
setSource(const QUrl & source)1556 void QTextureLoader::setSource(const QUrl& source)
1557 {
1558     Q_D(QTextureLoader);
1559     if (source != d->m_source) {
1560         d->m_source = source;
1561 
1562         // Reset target and format
1563         d->m_target = TargetAutomatic;
1564         setFormat(NoFormat);
1565 
1566         d->updateGenerator();
1567         const bool blocked = blockNotifications(true);
1568         emit sourceChanged(source);
1569         blockNotifications(blocked);
1570     }
1571 }
1572 
1573 /*!
1574   \property Qt3DRender::QTextureLoader::mirrored
1575 
1576   This property specifies whether the texture should be mirrored when loaded. This
1577   is a convenience to avoid having to manipulate images to match the origin of
1578   the texture coordinates used by the rendering API. By default this property
1579   is set to true. This has no effect when using GPU compressed texture formats.
1580 
1581   \warning This property results in a performance price payed at runtime when
1582   loading uncompressed or CPU compressed image formats such as PNG. To avoid this
1583   performance price it is better to set this property to false and load texture
1584   assets that have been pre-mirrored.
1585 
1586   \note OpenGL specifies the origin of texture coordinates from the lower left
1587   hand corner whereas DirectX uses the the upper left hand corner.
1588 
1589   \note When using cube map texture you'll probably want mirroring disabled as
1590   the cube map sampler takes a direction rather than regular texture
1591   coordinates.
1592 */
1593 
1594 /*!
1595   \qmlproperty bool Qt3D.Render::TextureLoader::mirrored
1596 
1597   This property specifies whether the texture should be mirrored when loaded. This
1598   is a convenience to avoid having to manipulate images to match the origin of
1599   the texture coordinates used by the rendering API. By default this property
1600   is set to true. This has no effect when using GPU compressed texture formats.
1601 
1602   \warning This property results in a performance price payed at runtime when
1603   loading uncompressed or CPU compressed image formats such as PNG. To avoid this
1604   performance price it is better to set this property to false and load texture
1605   assets that have been pre-mirrored.
1606 
1607   \note OpenGL specifies the origin of texture coordinates from the lower left
1608   hand corner whereas DirectX uses the the upper left hand corner.
1609 
1610   \note When using cube map texture you'll probably want mirroring disabled as
1611   the cube map sampler takes a direction rather than regular texture
1612   coordinates.
1613 */
1614 
1615 /*!
1616     Sets mirroring to \a mirrored.
1617     \note This internally triggers a call to update the data generator.
1618  */
setMirrored(bool mirrored)1619 void QTextureLoader::setMirrored(bool mirrored)
1620 {
1621     Q_D(QTextureLoader);
1622     if (mirrored != d->m_mirrored) {
1623         d->m_mirrored = mirrored;
1624         d->updateGenerator();
1625         const bool blocked = blockNotifications(true);
1626         emit mirroredChanged(mirrored);
1627         blockNotifications(blocked);
1628     }
1629 }
1630 
1631 /*
1632  * Constructs a new QTextureFromSourceGenerator::QTextureFromSourceGenerator
1633  * instance with properties passed in via \a textureLoader
1634  * \param url
1635  */
QTextureFromSourceGenerator(QTextureLoader * textureLoader,Qt3DCore::QAspectEngine * engine,Qt3DCore::QNodeId textureId)1636 QTextureFromSourceGenerator::QTextureFromSourceGenerator(QTextureLoader *textureLoader,
1637                                                          Qt3DCore::QAspectEngine *engine,
1638                                                          Qt3DCore::QNodeId textureId)
1639     : QTextureGenerator()
1640     , QEnableSharedFromThis<QTextureFromSourceGenerator>()
1641     , m_url()
1642     , m_status(QAbstractTexture::None)
1643     , m_mirrored()
1644     , m_texture(textureId)
1645     , m_engine(engine)
1646     , m_format(QAbstractTexture::NoFormat)
1647 {
1648     Q_ASSERT(textureLoader);
1649 
1650     // We always get QTextureLoader's "own" additional properties
1651     m_url = textureLoader->source();
1652     m_mirrored = textureLoader->isMirrored();
1653 
1654     // For the properties on the base QAbstractTexture we only apply
1655     // those that have been explicitly set and which we support here.
1656     // For more control, the user can themselves use a QTexture2D and
1657     // create the texture images themselves, or even better, go create
1658     // proper texture files themselves (dds/ktx etc). This is purely a
1659     // convenience for some common use cases and will always be less
1660     // ideal than using compressed textures and generating mips offline.
1661     m_format = textureLoader->format();
1662 }
1663 
QTextureFromSourceGenerator(const QTextureFromSourceGenerator & other)1664 QTextureFromSourceGenerator::QTextureFromSourceGenerator(const QTextureFromSourceGenerator &other)
1665     : QTextureGenerator()
1666     , QEnableSharedFromThis<QTextureFromSourceGenerator>()
1667     , m_url(other.m_url)
1668     , m_status(other.m_status)
1669     , m_mirrored(other.m_mirrored)
1670     , m_sourceData(other.m_sourceData)
1671     , m_texture(other.m_texture)
1672     , m_engine(other.m_engine)
1673     , m_format(other.m_format)
1674 {
1675 }
1676 
1677 /*
1678  * Takes in a TextureGenerator via \a other and
1679  * \return whether generators have the same source.
1680  */
operator ==(const QTextureGenerator & other) const1681 bool QTextureFromSourceGenerator::operator ==(const QTextureGenerator &other) const
1682 {
1683     const QTextureFromSourceGenerator *otherFunctor = functor_cast<QTextureFromSourceGenerator>(&other);
1684     return (otherFunctor != nullptr &&
1685             otherFunctor->m_url == m_url &&
1686             otherFunctor->m_mirrored == m_mirrored &&
1687             otherFunctor->m_engine == m_engine &&
1688             otherFunctor->m_format == m_format &&
1689             otherFunctor->m_sourceData == m_sourceData);
1690 }
1691 
url() const1692 QUrl QTextureFromSourceGenerator::url() const
1693 {
1694     return m_url;
1695 }
1696 
isMirrored() const1697 bool QTextureFromSourceGenerator::isMirrored() const
1698 {
1699     return m_mirrored;
1700 }
1701 
1702 /*!
1703  * \class Qt3DRender::QSharedGLTexture
1704  * \inmodule Qt3DRender
1705  * \inheaderfile Qt3DRender/QTexture
1706  * \brief Allows to use a textureId from a separate OpenGL context in a Qt 3D scene.
1707  *
1708  * Depending on the rendering mode used by Qt 3D, the shared context will either be:
1709  * \list
1710  * \li qt_gl_global_share_context when letting Qt 3D drive the rendering. When
1711  * setting the attribute Qt::AA_ShareOpenGLContexts on the QApplication class,
1712  * this will automatically make QOpenGLWidget instances have their context shared
1713  * with qt_gl_global_share_context.
1714  * \li the shared context from the QtQuick scene. You might have to subclass
1715  * QWindow or use QtQuickRenderControl to have control over what that shared
1716  * context is though as of 5.13 it is qt_gl_global_share_context.
1717  * \endlist
1718  *
1719  * \since 5.13
1720  *
1721  * Any 3rd party engine that shares its context with the Qt 3D renderer can now
1722  * provide texture ids that will be referenced by the Qt 3D texture.
1723  *
1724  * You can omit specifying the texture properties, Qt 3D will try at runtime to
1725  * determine what they are. If you know them, you can of course provide them,
1726  * avoid additional work for Qt 3D.
1727  *
1728  * Keep in mind that if you are using custom materials and shaders, you need to
1729  * specify the correct sampler type to be used.
1730  */
1731 
1732 /*!
1733     \qmltype SharedGLTexture
1734     \instantiates Qt3DRender::QSharedGLTexture
1735     \inqmlmodule Qt3D.Render
1736     \brief Allows to use a textureId from a separate OpenGL context in a Qt 3D scene.
1737     \since 5.13
1738 */
1739 
QSharedGLTexture(Qt3DCore::QNode * parent)1740 QSharedGLTexture::QSharedGLTexture(Qt3DCore::QNode *parent)
1741     : QAbstractTexture(parent)
1742 {
1743     QAbstractTexturePrivate *d = static_cast<QAbstractTexturePrivate *>(Qt3DCore::QNodePrivate::get(this));
1744     d->m_target = TargetAutomatic;
1745 }
1746 
~QSharedGLTexture()1747 QSharedGLTexture::~QSharedGLTexture()
1748 {
1749 }
1750 
1751 /*!
1752  * \qmlproperty int SharedGLTexture::textureId
1753  *
1754  * The OpenGL texture id value that you want Qt3D to gain access to.
1755  */
1756 /*!
1757  *\property Qt3DRender::QSharedGLTexture::textureId
1758  *
1759  * The OpenGL texture id value that you want Qt3D to gain access to.
1760  */
textureId() const1761 int QSharedGLTexture::textureId() const
1762 {
1763     return static_cast<QAbstractTexturePrivate *>(d_ptr.get())->m_sharedTextureId;
1764 }
1765 
setTextureId(int id)1766 void QSharedGLTexture::setTextureId(int id)
1767 {
1768     QAbstractTexturePrivate *d = static_cast<QAbstractTexturePrivate *>(Qt3DCore::QNodePrivate::get(this));
1769     if (d->m_sharedTextureId != id) {
1770         d->m_sharedTextureId = id;
1771         emit textureIdChanged(id);
1772     }
1773 }
1774 
1775 } // namespace Qt3DRender
1776 
1777 QT_END_NAMESPACE
1778