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 |
81 | { |
82 | char [4]; |
83 | quint32 ; |
84 | quint32 ; |
85 | quint32 ; |
86 | quint32 ; |
87 | quint32 ; |
88 | quint32 ; |
89 | quint32 ; |
90 | quint32 [11]; |
91 | DdsPixelFormat ; |
92 | quint32 ; |
93 | quint32 ; |
94 | quint32 ; |
95 | quint32 ; |
96 | quint32 ; |
97 | }; |
98 | |
99 | struct |
100 | { |
101 | quint32 ; |
102 | quint32 ; |
103 | quint32 ; |
104 | quint32 ; |
105 | quint32 ; |
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 | { .redMask: 0x000000ff, .greenMask: 0x0000ff00, .blueMask: 0x00ff0000, .alphaMask: 0xff000000, .formatInfo: { .pixelFormat: QOpenGLTexture::RGBA, .textureFormat: QOpenGLTexture::RGBA8_UNorm, .pixelType: QOpenGLTexture::UInt8, .components: 4, .compressed: false } }, |
290 | { .redMask: 0x00ff0000, .greenMask: 0x0000ff00, .blueMask: 0x000000ff, .alphaMask: 0xff000000, .formatInfo: { .pixelFormat: QOpenGLTexture::BGRA, .textureFormat: QOpenGLTexture::RGBA8_UNorm, .pixelType: QOpenGLTexture::UInt8, .components: 4, .compressed: false } }, |
291 | { .redMask: 0x000000ff, .greenMask: 0x0000ff00, .blueMask: 0x00ff0000, .alphaMask: 0x00000000, .formatInfo: { .pixelFormat: QOpenGLTexture::RGBA, .textureFormat: QOpenGLTexture::RGBA8_UNorm, .pixelType: QOpenGLTexture::UInt8, .components: 4, .compressed: false } }, |
292 | { .redMask: 0x00ff0000, .greenMask: 0x0000ff00, .blueMask: 0x000000ff, .alphaMask: 0x00000000, .formatInfo: { .pixelFormat: QOpenGLTexture::BGRA, .textureFormat: QOpenGLTexture::RGBA8_UNorm, .pixelType: QOpenGLTexture::UInt8, .components: 4, .compressed: false } }, |
293 | { .redMask: 0x000000ff, .greenMask: 0x0000ff00, .blueMask: 0x00ff0000, .alphaMask: 0x00000000, .formatInfo: { .pixelFormat: QOpenGLTexture::RGB, .textureFormat: QOpenGLTexture::RGB8_UNorm, .pixelType: QOpenGLTexture::UInt8, .components: 3, .compressed: false } }, |
294 | { .redMask: 0x00ff0000, .greenMask: 0x0000ff00, .blueMask: 0x000000ff, .alphaMask: 0x00000000, .formatInfo: { .pixelFormat: QOpenGLTexture::BGR, .textureFormat: QOpenGLTexture::RGB8_UNorm, .pixelType: QOpenGLTexture::UInt8, .components: 3, .compressed: false } }, |
295 | |
296 | // packed formats |
297 | { .redMask: 0x0000f800, .greenMask: 0x000007e0, .blueMask: 0x0000001f, .alphaMask: 0x00000000, .formatInfo: { .pixelFormat: QOpenGLTexture::RGB, .textureFormat: QOpenGLTexture::R5G6B5, .pixelType: QOpenGLTexture::UInt16_R5G6B5, .components: 2, .compressed: false } }, |
298 | { .redMask: 0x00007c00, .greenMask: 0x000003e0, .blueMask: 0x0000001f, .alphaMask: 0x00008000, .formatInfo: { .pixelFormat: QOpenGLTexture::RGBA, .textureFormat: QOpenGLTexture::RGB5A1, .pixelType: QOpenGLTexture::UInt16_RGB5A1, .components: 2, .compressed: false } }, |
299 | { .redMask: 0x00000f00, .greenMask: 0x000000f0, .blueMask: 0x0000000f, .alphaMask: 0x0000f000, .formatInfo: { .pixelFormat: QOpenGLTexture::RGBA, .textureFormat: QOpenGLTexture::RGBA4, .pixelType: QOpenGLTexture::UInt16_RGBA4, .components: 2, .compressed: false } }, |
300 | { .redMask: 0x000000e0, .greenMask: 0x0000001c, .blueMask: 0x00000003, .alphaMask: 0x00000000, .formatInfo: { .pixelFormat: QOpenGLTexture::RGB, .textureFormat: QOpenGLTexture::RG3B2, .pixelType: QOpenGLTexture::UInt8_RG3B2, .components: 1, .compressed: false } }, |
301 | { .redMask: 0x3ff00000, .greenMask: 0x000ffc00, .blueMask: 0x000003ff, .alphaMask: 0xc0000000, .formatInfo: { .pixelFormat: QOpenGLTexture::RGBA, .textureFormat: QOpenGLTexture::RGB10A2, .pixelType: QOpenGLTexture::UInt32_RGB10A2, .components: 4, .compressed: false } }, |
302 | |
303 | // luminance alpha |
304 | { .redMask: 0x000000ff, .greenMask: 0x000000ff, .blueMask: 0x000000ff, .alphaMask: 0x00000000, .formatInfo: { .pixelFormat: QOpenGLTexture::Red, .textureFormat: QOpenGLTexture::R8_UNorm, .pixelType: QOpenGLTexture::UInt8, .components: 1, .compressed: false } }, |
305 | { .redMask: 0x000000ff, .greenMask: 0x00000000, .blueMask: 0x00000000, .alphaMask: 0x00000000, .formatInfo: { .pixelFormat: QOpenGLTexture::Red, .textureFormat: QOpenGLTexture::R8_UNorm, .pixelType: QOpenGLTexture::UInt8, .components: 1, .compressed: false } }, |
306 | { .redMask: 0x000000ff, .greenMask: 0x000000ff, .blueMask: 0x000000ff, .alphaMask: 0x0000ff00, .formatInfo: { .pixelFormat: QOpenGLTexture::RG, .textureFormat: QOpenGLTexture::RG8_UNorm, .pixelType: QOpenGLTexture::UInt8, .components: 2, .compressed: false } }, |
307 | { .redMask: 0x000000ff, .greenMask: 0x00000000, .blueMask: 0x00000000, .alphaMask: 0x0000ff00, .formatInfo: { .pixelFormat: QOpenGLTexture::RG, .textureFormat: QOpenGLTexture::RG8_UNorm, .pixelType: QOpenGLTexture::UInt8, .components: 2, .compressed: false } }, |
308 | }; |
309 | |
310 | const struct FourCCFormat |
311 | { |
312 | quint32 fourCC; |
313 | FormatInfo formatInfo; |
314 | } fourCCFormats[] = { |
315 | { .fourCC: DdsFourCC<'D','X','T','1'>::value, .formatInfo: { .pixelFormat: QOpenGLTexture::NoSourceFormat, .textureFormat: QOpenGLTexture::RGBA_DXT1, .pixelType: QOpenGLTexture::NoPixelType, .components: 8, .compressed: true } }, |
316 | { .fourCC: DdsFourCC<'D','X','T','3'>::value, .formatInfo: { .pixelFormat: QOpenGLTexture::NoSourceFormat, .textureFormat: QOpenGLTexture::RGBA_DXT3, .pixelType: QOpenGLTexture::NoPixelType, .components: 16, .compressed: true } }, |
317 | { .fourCC: DdsFourCC<'D','X','T','5'>::value, .formatInfo: { .pixelFormat: QOpenGLTexture::NoSourceFormat, .textureFormat: QOpenGLTexture::RGBA_DXT5, .pixelType: QOpenGLTexture::NoPixelType, .components: 16, .compressed: true } }, |
318 | { .fourCC: DdsFourCC<'A','T','I','1'>::value, .formatInfo: { .pixelFormat: QOpenGLTexture::NoSourceFormat, .textureFormat: QOpenGLTexture::R_ATI1N_UNorm, .pixelType: QOpenGLTexture::NoPixelType, .components: 8, .compressed: true } }, |
319 | { .fourCC: DdsFourCC<'A','T','I','2'>::value, .formatInfo: { .pixelFormat: QOpenGLTexture::NoSourceFormat, .textureFormat: QOpenGLTexture::RG_ATI2N_UNorm, .pixelType: QOpenGLTexture::NoPixelType, .components: 16, .compressed: true } }, |
320 | { /* DXGI_FORMAT_R16_FLOAT */ .fourCC: 111, .formatInfo: { .pixelFormat: QOpenGLTexture::Red, .textureFormat: QOpenGLTexture::R16F, .pixelType: QOpenGLTexture::Float16, .components: 2, .compressed: false } }, |
321 | { /* DXGI_FORMAT_R16_FLOAT */ .fourCC: 112, .formatInfo: { .pixelFormat: QOpenGLTexture::RG, .textureFormat: QOpenGLTexture::RG16F, .pixelType: QOpenGLTexture::Float16, .components: 4, .compressed: false } }, |
322 | { /* DXGI_FORMAT_R16G16B16A16_FLOAT */.fourCC: 113, .formatInfo: { .pixelFormat: QOpenGLTexture::RGBA, .textureFormat: QOpenGLTexture::RGBA16F, .pixelType: QOpenGLTexture::Float16, .components: 8, .compressed: false } }, |
323 | { /* DXGI_FORMAT_R32_FLOAT */ .fourCC: 114, .formatInfo: { .pixelFormat: QOpenGLTexture::Red, .textureFormat: QOpenGLTexture::R32F, .pixelType: QOpenGLTexture::Float32, .components: 4, .compressed: false } }, |
324 | { /* DXGI_FORMAT_R32G32_FLOAT */ .fourCC: 115, .formatInfo: { .pixelFormat: QOpenGLTexture::RG, .textureFormat: QOpenGLTexture::RG32F, .pixelType: QOpenGLTexture::Float32, .components: 8, .compressed: false } }, |
325 | { /* DXGI_FORMAT_R32G32B32A32_FLOAT */.fourCC: 116, .formatInfo: { .pixelFormat: QOpenGLTexture::RGBA, .textureFormat: QOpenGLTexture::RGBA32F, .pixelType: QOpenGLTexture::Float32, .components: 16, .compressed: false } } |
326 | }; |
327 | |
328 | const struct DX10Format |
329 | { |
330 | DXGIFormat dxgiFormat; |
331 | FormatInfo formatInfo; |
332 | } dx10Formats[] = { |
333 | // unorm formats |
334 | { .dxgiFormat: DXGI_FORMAT_R8_UNORM, .formatInfo: { .pixelFormat: QOpenGLTexture::Red, .textureFormat: QOpenGLTexture::R8_UNorm, .pixelType: QOpenGLTexture::UInt8, .components: 1, .compressed: false } }, |
335 | { .dxgiFormat: DXGI_FORMAT_R8G8_UNORM, .formatInfo: { .pixelFormat: QOpenGLTexture::RG, .textureFormat: QOpenGLTexture::RG8_UNorm, .pixelType: QOpenGLTexture::UInt8, .components: 2, .compressed: false } }, |
336 | { .dxgiFormat: DXGI_FORMAT_R8G8B8A8_UNORM, .formatInfo: { .pixelFormat: QOpenGLTexture::RGBA, .textureFormat: QOpenGLTexture::RGBA8_UNorm, .pixelType: QOpenGLTexture::UInt8, .components: 4, .compressed: false } }, |
337 | |
338 | { .dxgiFormat: DXGI_FORMAT_R16_UNORM, .formatInfo: { .pixelFormat: QOpenGLTexture::Red, .textureFormat: QOpenGLTexture::R16_UNorm, .pixelType: QOpenGLTexture::UInt16, .components: 2, .compressed: false } }, |
339 | { .dxgiFormat: DXGI_FORMAT_R16G16_UNORM, .formatInfo: { .pixelFormat: QOpenGLTexture::RG, .textureFormat: QOpenGLTexture::RG16_UNorm, .pixelType: QOpenGLTexture::UInt16, .components: 4, .compressed: false } }, |
340 | { .dxgiFormat: DXGI_FORMAT_R16G16B16A16_UNORM, .formatInfo: { .pixelFormat: QOpenGLTexture::RGBA, .textureFormat: QOpenGLTexture::RGBA16_UNorm, .pixelType: QOpenGLTexture::UInt16, .components: 8, .compressed: false } }, |
341 | |
342 | // snorm formats |
343 | { .dxgiFormat: DXGI_FORMAT_R8_SNORM, .formatInfo: { .pixelFormat: QOpenGLTexture::Red, .textureFormat: QOpenGLTexture::R8_SNorm, .pixelType: QOpenGLTexture::Int8, .components: 1, .compressed: false } }, |
344 | { .dxgiFormat: DXGI_FORMAT_R8G8_SNORM, .formatInfo: { .pixelFormat: QOpenGLTexture::RG, .textureFormat: QOpenGLTexture::RG8_SNorm, .pixelType: QOpenGLTexture::Int8, .components: 2, .compressed: false } }, |
345 | { .dxgiFormat: DXGI_FORMAT_R8G8B8A8_SNORM, .formatInfo: { .pixelFormat: QOpenGLTexture::RGBA, .textureFormat: QOpenGLTexture::RGBA8_SNorm, .pixelType: QOpenGLTexture::Int8, .components: 4, .compressed: false } }, |
346 | |
347 | { .dxgiFormat: DXGI_FORMAT_R16_SNORM, .formatInfo: { .pixelFormat: QOpenGLTexture::Red, .textureFormat: QOpenGLTexture::R16_SNorm, .pixelType: QOpenGLTexture::Int16, .components: 2, .compressed: false } }, |
348 | { .dxgiFormat: DXGI_FORMAT_R16G16_SNORM, .formatInfo: { .pixelFormat: QOpenGLTexture::RG, .textureFormat: QOpenGLTexture::RG16_SNorm, .pixelType: QOpenGLTexture::Int16, .components: 4, .compressed: false } }, |
349 | { .dxgiFormat: DXGI_FORMAT_R16G16B16A16_SNORM, .formatInfo: { .pixelFormat: QOpenGLTexture::RGBA, .textureFormat: QOpenGLTexture::RGBA16_SNorm, .pixelType: QOpenGLTexture::Int16, .components: 8, .compressed: false } }, |
350 | |
351 | // unsigned integer formats |
352 | { .dxgiFormat: DXGI_FORMAT_R8_UINT, .formatInfo: { .pixelFormat: QOpenGLTexture::Red_Integer, .textureFormat: QOpenGLTexture::R8U, .pixelType: QOpenGLTexture::UInt8, .components: 1, .compressed: false } }, |
353 | { .dxgiFormat: DXGI_FORMAT_R8G8_UINT, .formatInfo: { .pixelFormat: QOpenGLTexture::RG_Integer, .textureFormat: QOpenGLTexture::RG8U, .pixelType: QOpenGLTexture::UInt8, .components: 2, .compressed: false } }, |
354 | { .dxgiFormat: DXGI_FORMAT_R8G8B8A8_UINT, .formatInfo: { .pixelFormat: QOpenGLTexture::RGBA_Integer, .textureFormat: QOpenGLTexture::RGBA8U, .pixelType: QOpenGLTexture::UInt8, .components: 4, .compressed: false } }, |
355 | |
356 | { .dxgiFormat: DXGI_FORMAT_R16_UINT, .formatInfo: { .pixelFormat: QOpenGLTexture::Red_Integer, .textureFormat: QOpenGLTexture::R16U, .pixelType: QOpenGLTexture::UInt16, .components: 2, .compressed: false } }, |
357 | { .dxgiFormat: DXGI_FORMAT_R16G16_UINT, .formatInfo: { .pixelFormat: QOpenGLTexture::RG_Integer, .textureFormat: QOpenGLTexture::RG16U, .pixelType: QOpenGLTexture::UInt16, .components: 4, .compressed: false } }, |
358 | { .dxgiFormat: DXGI_FORMAT_R16G16B16A16_UINT, .formatInfo: { .pixelFormat: QOpenGLTexture::RGBA_Integer, .textureFormat: QOpenGLTexture::RGBA16U, .pixelType: QOpenGLTexture::UInt16, .components: 8, .compressed: false } }, |
359 | |
360 | { .dxgiFormat: DXGI_FORMAT_R32_UINT, .formatInfo: { .pixelFormat: QOpenGLTexture::Red_Integer, .textureFormat: QOpenGLTexture::R32U, .pixelType: QOpenGLTexture::UInt32, .components: 4, .compressed: false } }, |
361 | { .dxgiFormat: DXGI_FORMAT_R32G32_UINT, .formatInfo: { .pixelFormat: QOpenGLTexture::RG_Integer, .textureFormat: QOpenGLTexture::RG32U, .pixelType: QOpenGLTexture::UInt32, .components: 8, .compressed: false } }, |
362 | { .dxgiFormat: DXGI_FORMAT_R32G32B32_UINT, .formatInfo: { .pixelFormat: QOpenGLTexture::RGB_Integer, .textureFormat: QOpenGLTexture::RGB32U, .pixelType: QOpenGLTexture::UInt32, .components: 12, .compressed: false } }, |
363 | { .dxgiFormat: DXGI_FORMAT_R32G32B32A32_UINT, .formatInfo: { .pixelFormat: QOpenGLTexture::RGBA_Integer, .textureFormat: QOpenGLTexture::RGBA32U, .pixelType: QOpenGLTexture::UInt32, .components: 16, .compressed: false } }, |
364 | |
365 | // signed integer formats |
366 | { .dxgiFormat: DXGI_FORMAT_R8_SINT, .formatInfo: { .pixelFormat: QOpenGLTexture::Red_Integer, .textureFormat: QOpenGLTexture::R8I, .pixelType: QOpenGLTexture::Int8, .components: 1, .compressed: false } }, |
367 | { .dxgiFormat: DXGI_FORMAT_R8G8_SINT, .formatInfo: { .pixelFormat: QOpenGLTexture::RG_Integer, .textureFormat: QOpenGLTexture::RG8I, .pixelType: QOpenGLTexture::Int8, .components: 2, .compressed: false } }, |
368 | { .dxgiFormat: DXGI_FORMAT_R8G8B8A8_SINT, .formatInfo: { .pixelFormat: QOpenGLTexture::RGBA_Integer, .textureFormat: QOpenGLTexture::RGBA8I, .pixelType: QOpenGLTexture::Int8, .components: 4, .compressed: false } }, |
369 | |
370 | { .dxgiFormat: DXGI_FORMAT_R16_SINT, .formatInfo: { .pixelFormat: QOpenGLTexture::Red_Integer, .textureFormat: QOpenGLTexture::R16I, .pixelType: QOpenGLTexture::Int16, .components: 2, .compressed: false } }, |
371 | { .dxgiFormat: DXGI_FORMAT_R16G16_SINT, .formatInfo: { .pixelFormat: QOpenGLTexture::RG_Integer, .textureFormat: QOpenGLTexture::RG16I, .pixelType: QOpenGLTexture::Int16, .components: 4, .compressed: false } }, |
372 | { .dxgiFormat: DXGI_FORMAT_R16G16B16A16_SINT, .formatInfo: { .pixelFormat: QOpenGLTexture::RGBA_Integer, .textureFormat: QOpenGLTexture::RGBA16I, .pixelType: QOpenGLTexture::Int16, .components: 8, .compressed: false } }, |
373 | |
374 | { .dxgiFormat: DXGI_FORMAT_R32_SINT, .formatInfo: { .pixelFormat: QOpenGLTexture::Red_Integer, .textureFormat: QOpenGLTexture::R32I, .pixelType: QOpenGLTexture::Int32, .components: 4, .compressed: false } }, |
375 | { .dxgiFormat: DXGI_FORMAT_R32G32_SINT, .formatInfo: { .pixelFormat: QOpenGLTexture::RG_Integer, .textureFormat: QOpenGLTexture::RG32I, .pixelType: QOpenGLTexture::Int32, .components: 8, .compressed: false } }, |
376 | { .dxgiFormat: DXGI_FORMAT_R32G32B32_SINT, .formatInfo: { .pixelFormat: QOpenGLTexture::RGB_Integer, .textureFormat: QOpenGLTexture::RGB32I, .pixelType: QOpenGLTexture::Int32, .components: 12, .compressed: false } }, |
377 | { .dxgiFormat: DXGI_FORMAT_R32G32B32A32_SINT, .formatInfo: { .pixelFormat: QOpenGLTexture::RGBA_Integer, .textureFormat: QOpenGLTexture::RGBA32I, .pixelType: QOpenGLTexture::Int32, .components: 16, .compressed: false } }, |
378 | |
379 | // floating formats |
380 | { .dxgiFormat: DXGI_FORMAT_R16_FLOAT, .formatInfo: { .pixelFormat: QOpenGLTexture::Red, .textureFormat: QOpenGLTexture::R16F, .pixelType: QOpenGLTexture::Float16, .components: 2, .compressed: false } }, |
381 | { .dxgiFormat: DXGI_FORMAT_R16G16_FLOAT, .formatInfo: { .pixelFormat: QOpenGLTexture::RG, .textureFormat: QOpenGLTexture::RG16F, .pixelType: QOpenGLTexture::Float16, .components: 4, .compressed: false } }, |
382 | { .dxgiFormat: DXGI_FORMAT_R16G16B16A16_FLOAT, .formatInfo: { .pixelFormat: QOpenGLTexture::RGBA, .textureFormat: QOpenGLTexture::RGBA16F, .pixelType: QOpenGLTexture::Float16, .components: 8, .compressed: false } }, |
383 | |
384 | { .dxgiFormat: DXGI_FORMAT_R32_FLOAT, .formatInfo: { .pixelFormat: QOpenGLTexture::Red, .textureFormat: QOpenGLTexture::R32F, .pixelType: QOpenGLTexture::Float32, .components: 4, .compressed: false } }, |
385 | { .dxgiFormat: DXGI_FORMAT_R32G32_FLOAT, .formatInfo: { .pixelFormat: QOpenGLTexture::RG, .textureFormat: QOpenGLTexture::RG32F, .pixelType: QOpenGLTexture::Float32, .components: 8, .compressed: false } }, |
386 | { .dxgiFormat: DXGI_FORMAT_R32G32B32_FLOAT, .formatInfo: { .pixelFormat: QOpenGLTexture::RGB, .textureFormat: QOpenGLTexture::RGB32F, .pixelType: QOpenGLTexture::Float32, .components: 12, .compressed: false } }, |
387 | { .dxgiFormat: DXGI_FORMAT_R32G32B32A32_FLOAT, .formatInfo: { .pixelFormat: QOpenGLTexture::RGBA, .textureFormat: QOpenGLTexture::RGBA32F, .pixelType: QOpenGLTexture::Float32, .components: 16, .compressed: false } }, |
388 | |
389 | // sRGB formats |
390 | { .dxgiFormat: DXGI_FORMAT_B8G8R8X8_UNORM_SRGB, .formatInfo: { .pixelFormat: QOpenGLTexture::RGB, .textureFormat: QOpenGLTexture::SRGB8, .pixelType: QOpenGLTexture::UInt8, .components: 4, .compressed: false } }, |
391 | { .dxgiFormat: DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, .formatInfo: { .pixelFormat: QOpenGLTexture::RGBA, .textureFormat: QOpenGLTexture::SRGB8_Alpha8, .pixelType: QOpenGLTexture::UInt8, .components: 4, .compressed: false } }, |
392 | |
393 | // packed formats |
394 | // { DXGI_FORMAT_R10G10B10A2_UNORM, { QOpenGLTexture::RGB10A2_UNORM, QOpenGLTexture::RGBA, QOpenGLTexture::UInt32_RGB10A2, 4, false } }, |
395 | { .dxgiFormat: DXGI_FORMAT_R10G10B10A2_UINT, .formatInfo: { .pixelFormat: QOpenGLTexture::RGBA_Integer, .textureFormat: QOpenGLTexture::RGB10A2, .pixelType: QOpenGLTexture::UInt32_RGB10A2, .components: 4, .compressed: false } }, |
396 | { .dxgiFormat: DXGI_FORMAT_R9G9B9E5_SHAREDEXP, .formatInfo: { .pixelFormat: QOpenGLTexture::RGB, .textureFormat: QOpenGLTexture::RGB9E5, .pixelType: QOpenGLTexture::UInt32_RGB9_E5, .components: 4, .compressed: false } }, |
397 | { .dxgiFormat: DXGI_FORMAT_R11G11B10_FLOAT, .formatInfo: { .pixelFormat: QOpenGLTexture::RGB, .textureFormat: QOpenGLTexture::RG11B10F, .pixelType: QOpenGLTexture::UInt32_RG11B10F, .components: 4, .compressed: false } }, |
398 | { .dxgiFormat: DXGI_FORMAT_B5G6R5_UNORM, .formatInfo: { .pixelFormat: QOpenGLTexture::RGB, .textureFormat: QOpenGLTexture::R5G6B5, .pixelType: QOpenGLTexture::UInt16_R5G6B5, .components: 2, .compressed: false } }, |
399 | { .dxgiFormat: DXGI_FORMAT_B5G5R5A1_UNORM, .formatInfo: { .pixelFormat: QOpenGLTexture::RGBA, .textureFormat: QOpenGLTexture::RGB5A1, .pixelType: QOpenGLTexture::UInt16_RGB5A1, .components: 2, .compressed: false } }, |
400 | { .dxgiFormat: DXGI_FORMAT_B4G4R4A4_UNORM, .formatInfo: { .pixelFormat: QOpenGLTexture::RGBA, .textureFormat: QOpenGLTexture::RGBA4, .pixelType: QOpenGLTexture::UInt16_RGBA4, .components: 2, .compressed: false } }, |
401 | |
402 | // swizzle formats |
403 | { .dxgiFormat: DXGI_FORMAT_B8G8R8X8_UNORM, .formatInfo: { .pixelFormat: QOpenGLTexture::BGRA, .textureFormat: QOpenGLTexture::RGB8_UNorm, .pixelType: QOpenGLTexture::UInt8, .components: 4, .compressed: false } }, |
404 | { .dxgiFormat: DXGI_FORMAT_B8G8R8A8_UNORM, .formatInfo: { .pixelFormat: QOpenGLTexture::BGRA, .textureFormat: QOpenGLTexture::RGBA8_UNorm, .pixelType: QOpenGLTexture::UInt8, .components: 4, .compressed: false } }, |
405 | { .dxgiFormat: DXGI_FORMAT_B8G8R8X8_UNORM_SRGB, .formatInfo: { .pixelFormat: QOpenGLTexture::BGRA, .textureFormat: QOpenGLTexture::SRGB8, .pixelType: QOpenGLTexture::UInt8, .components: 4, .compressed: false } }, |
406 | { .dxgiFormat: DXGI_FORMAT_B8G8R8A8_UNORM_SRGB, .formatInfo: { .pixelFormat: QOpenGLTexture::BGRA, .textureFormat: QOpenGLTexture::SRGB8_Alpha8, .pixelType: QOpenGLTexture::UInt8, .components: 4, .compressed: false } }, |
407 | |
408 | // luminance alpha formats |
409 | { .dxgiFormat: DXGI_FORMAT_R8_UNORM, .formatInfo: { .pixelFormat: QOpenGLTexture::Red, .textureFormat: QOpenGLTexture::R8_UNorm, .pixelType: QOpenGLTexture::UInt8, .components: 1, .compressed: false } }, |
410 | { .dxgiFormat: DXGI_FORMAT_R8G8_UNORM, .formatInfo: { .pixelFormat: QOpenGLTexture::RG, .textureFormat: QOpenGLTexture::RG8_UNorm, .pixelType: QOpenGLTexture::UInt8, .components: 2, .compressed: false } }, |
411 | { .dxgiFormat: DXGI_FORMAT_R16_UNORM, .formatInfo: { .pixelFormat: QOpenGLTexture::Red, .textureFormat: QOpenGLTexture::R16_UNorm, .pixelType: QOpenGLTexture::UInt16, .components: 2, .compressed: false } }, |
412 | { .dxgiFormat: DXGI_FORMAT_R16G16_UNORM, .formatInfo: { .pixelFormat: QOpenGLTexture::RG, .textureFormat: QOpenGLTexture::RG16_UNorm, .pixelType: QOpenGLTexture::UInt16, .components: 4, .compressed: false } }, |
413 | |
414 | // depth formats |
415 | { .dxgiFormat: DXGI_FORMAT_D16_UNORM, .formatInfo: { .pixelFormat: QOpenGLTexture::Depth, .textureFormat: QOpenGLTexture::D16, .pixelType: QOpenGLTexture::NoPixelType, .components: 2, .compressed: false } }, |
416 | { .dxgiFormat: DXGI_FORMAT_D24_UNORM_S8_UINT, .formatInfo: { .pixelFormat: QOpenGLTexture::DepthStencil, .textureFormat: QOpenGLTexture::D24S8, .pixelType: QOpenGLTexture::NoPixelType, .components: 4, .compressed: false } }, |
417 | { .dxgiFormat: DXGI_FORMAT_D32_FLOAT, .formatInfo: { .pixelFormat: QOpenGLTexture::Depth, .textureFormat: QOpenGLTexture::D32F, .pixelType: QOpenGLTexture::NoPixelType, .components: 4, .compressed: false } }, |
418 | { .dxgiFormat: DXGI_FORMAT_D32_FLOAT_S8X24_UINT, .formatInfo: { .pixelFormat: QOpenGLTexture::DepthStencil, .textureFormat: QOpenGLTexture::D32FS8X24, .pixelType: QOpenGLTexture::NoPixelType, .components: 8, .compressed: false } }, |
419 | |
420 | // compressed formats |
421 | { .dxgiFormat: DXGI_FORMAT_BC1_UNORM, .formatInfo: { .pixelFormat: QOpenGLTexture::NoSourceFormat, .textureFormat: QOpenGLTexture::RGBA_DXT1, .pixelType: QOpenGLTexture::NoPixelType, .components: 8, .compressed: true } }, |
422 | { .dxgiFormat: DXGI_FORMAT_BC2_UNORM, .formatInfo: { .pixelFormat: QOpenGLTexture::NoSourceFormat, .textureFormat: QOpenGLTexture::RGBA_DXT3, .pixelType: QOpenGLTexture::NoPixelType, .components: 16, .compressed: true } }, |
423 | { .dxgiFormat: DXGI_FORMAT_BC3_UNORM, .formatInfo: { .pixelFormat: QOpenGLTexture::NoSourceFormat, .textureFormat: QOpenGLTexture::RGBA_DXT5, .pixelType: QOpenGLTexture::NoPixelType, .components: 16, .compressed: true } }, |
424 | { .dxgiFormat: DXGI_FORMAT_BC4_UNORM, .formatInfo: { .pixelFormat: QOpenGLTexture::NoSourceFormat, .textureFormat: QOpenGLTexture::R_ATI1N_UNorm, .pixelType: QOpenGLTexture::NoPixelType, .components: 8, .compressed: true } }, |
425 | { .dxgiFormat: DXGI_FORMAT_BC4_SNORM, .formatInfo: { .pixelFormat: QOpenGLTexture::NoSourceFormat, .textureFormat: QOpenGLTexture::R_ATI1N_SNorm, .pixelType: QOpenGLTexture::NoPixelType, .components: 8, .compressed: true } }, |
426 | { .dxgiFormat: DXGI_FORMAT_BC5_UNORM, .formatInfo: { .pixelFormat: QOpenGLTexture::NoSourceFormat, .textureFormat: QOpenGLTexture::RG_ATI2N_UNorm, .pixelType: QOpenGLTexture::NoPixelType, .components: 16, .compressed: true } }, |
427 | { .dxgiFormat: DXGI_FORMAT_BC5_SNORM, .formatInfo: { .pixelFormat: QOpenGLTexture::NoSourceFormat, .textureFormat: QOpenGLTexture::RG_ATI2N_SNorm, .pixelType: QOpenGLTexture::NoPixelType, .components: 16, .compressed: true } }, |
428 | { .dxgiFormat: DXGI_FORMAT_BC6H_UF16, .formatInfo: { .pixelFormat: QOpenGLTexture::NoSourceFormat, .textureFormat: QOpenGLTexture::RGB_BP_UNSIGNED_FLOAT, .pixelType: QOpenGLTexture::NoPixelType, .components: 16, .compressed: true } }, |
429 | { .dxgiFormat: DXGI_FORMAT_BC6H_SF16, .formatInfo: { .pixelFormat: QOpenGLTexture::NoSourceFormat, .textureFormat: QOpenGLTexture::RGB_BP_SIGNED_FLOAT, .pixelType: QOpenGLTexture::NoPixelType, .components: 16, .compressed: true } }, |
430 | { .dxgiFormat: DXGI_FORMAT_BC7_UNORM, .formatInfo: { .pixelFormat: QOpenGLTexture::NoSourceFormat, .textureFormat: QOpenGLTexture::RGB_BP_UNorm, .pixelType: QOpenGLTexture::NoPixelType, .components: 16, .compressed: true } }, |
431 | |
432 | // compressed sRGB formats |
433 | { .dxgiFormat: DXGI_FORMAT_BC1_UNORM_SRGB, .formatInfo: { .pixelFormat: QOpenGLTexture::NoSourceFormat, .textureFormat: QOpenGLTexture::SRGB_DXT1, .pixelType: QOpenGLTexture::NoPixelType, .components: 8, .compressed: true } }, |
434 | { .dxgiFormat: DXGI_FORMAT_BC1_UNORM_SRGB, .formatInfo: { .pixelFormat: QOpenGLTexture::NoSourceFormat, .textureFormat: QOpenGLTexture::SRGB_Alpha_DXT1, .pixelType: QOpenGLTexture::NoPixelType, .components: 8, .compressed: true } }, |
435 | { .dxgiFormat: DXGI_FORMAT_BC2_UNORM_SRGB, .formatInfo: { .pixelFormat: QOpenGLTexture::NoSourceFormat, .textureFormat: QOpenGLTexture::SRGB_Alpha_DXT3, .pixelType: QOpenGLTexture::NoPixelType, .components: 16, .compressed: true } }, |
436 | { .dxgiFormat: DXGI_FORMAT_BC3_UNORM_SRGB, .formatInfo: { .pixelFormat: QOpenGLTexture::NoSourceFormat, .textureFormat: QOpenGLTexture::SRGB_Alpha_DXT5, .pixelType: QOpenGLTexture::NoPixelType, .components: 16, .compressed: true } }, |
437 | { .dxgiFormat: DXGI_FORMAT_BC7_UNORM_SRGB, .formatInfo: { .pixelFormat: QOpenGLTexture::NoSourceFormat, .textureFormat: QOpenGLTexture::SRGB_BP_UNorm, .pixelType: QOpenGLTexture::NoPixelType, .components: 16, .compressed: true } }, |
438 | }; |
439 | |
440 | struct |
441 | { |
442 | char [4]; |
443 | char [2]; |
444 | quint16 ; |
445 | quint16 ; |
446 | quint16 ; |
447 | quint16 ; |
448 | quint16 ; |
449 | }; |
450 | |
451 | enum ImageFormat { |
452 | GenericImageFormat = 0, |
453 | DDS, |
454 | PKM, |
455 | HDR, |
456 | KTX |
457 | }; |
458 | |
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. |
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 | |
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 { |
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 ; |
517 | QTextureImageDataPtr imageData; |
518 | if (source->read(data: reinterpret_cast<char *>(&header), maxlen: sizeof(header)) != sizeof(header) |
519 | || qstrncmp(str1: reinterpret_cast<char *>(header.identifier), str2: ktxIdentifier, len: 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>(source: 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(msg: "Uncompressed ktx texture data is not supported" ); |
533 | return imageData; |
534 | } |
535 | |
536 | if (decode(header.numberOfArrayElements) != 0) { |
537 | qWarning(msg: "Array ktx textures not supported" ); |
538 | return imageData; |
539 | } |
540 | |
541 | if (decode(header.pixelDepth) != 0) { |
542 | qWarning(msg: "Only 2D and cube ktx textures are supported" ); |
543 | return imageData; |
544 | } |
545 | |
546 | const int bytesToSkip = decode(header.bytesOfKeyValueData); |
547 | if (source->read(maxlen: bytesToSkip).count() != bytesToSkip) { |
548 | qWarning(msg: "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(a: level0Width >> level, b: 1); |
571 | const int h = qMax(a: level0Height >> level, b: 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(maxlen: 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(data: rawData, blockSize, isCompressed: true); |
600 | QTextureImageDataPrivate::get(imageData: imageData.data())->m_isKtx = true; // see note in QTextureImageDataPrivate |
601 | |
602 | return imageData; |
603 | } |
604 | |
605 | QTextureImageDataPtr setPkmFile(QIODevice *source) |
606 | { |
607 | QTextureImageDataPtr imageData; |
608 | |
609 | PkmHeader ; |
610 | if ((source->read(data: reinterpret_cast<char *>(&header), maxlen: sizeof header) != sizeof header) |
611 | || (qstrncmp(str1: header.magic, str2: "PKM " , len: 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(source: 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(source: header.paddedWidth); |
671 | const int height = qFromBigEndian(source: 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, isCompressed: true); |
691 | |
692 | return imageData; |
693 | } |
694 | |
695 | QTextureImageDataPtr setDdsFile(QIODevice *source) |
696 | { |
697 | QTextureImageDataPtr imageData; |
698 | |
699 | DdsHeader ; |
700 | if ((source->read(data: reinterpret_cast<char *>(&header), maxlen: sizeof header) != sizeof header) |
701 | || (qstrncmp(str1: header.magic, str2: "DDS " , len: 4) != 0)) |
702 | return imageData; |
703 | |
704 | int layers = 1; |
705 | const quint32 pixelFlags = qFromLittleEndian(source: header.pixelFormat.flags); |
706 | const quint32 fourCC = qFromLittleEndian(source: 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 ; |
713 | if (source->read(data: reinterpret_cast<char *>(&dx10Header), maxlen: sizeof dx10Header) != sizeof dx10Header) |
714 | return imageData; |
715 | |
716 | layers = qFromLittleEndian(source: dx10Header.arraySize); |
717 | DXGIFormat format = static_cast<DXGIFormat>(qFromLittleEndian(source: 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(source: header.pixelFormat.rgbBitCount); |
737 | const quint32 redMask = qFromLittleEndian(source: header.pixelFormat.redMask); |
738 | const quint32 greenMask = qFromLittleEndian(source: header.pixelFormat.greenMask); |
739 | const quint32 blueMask = qFromLittleEndian(source: header.pixelFormat.blueMask); |
740 | const quint32 alphaMask = qFromLittleEndian(source: 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(source: header.width); |
761 | const int height = qFromLittleEndian(source: header.height); |
762 | const quint32 caps2Flags = qFromLittleEndian(source: header.caps2); |
763 | const int blockSize = formatInfo->components; |
764 | const bool isCompressed = formatInfo->compressed; |
765 | const int mipLevelCount = ((qFromLittleEndian(source: header.flags) & MipmapCountFlag) == MipmapCountFlag) ? qFromLittleEndian(source: header.mipmapCount) : 1; |
766 | int depth; |
767 | int faces; |
768 | |
769 | if ((caps2Flags & VolumeFlag) == VolumeFlag) { |
770 | target = QOpenGLTexture::Target3D; |
771 | depth = qFromLittleEndian(source: 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(v: 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(a: width >> level, b: 1); |
788 | const int h = qMax(a: height >> level, b: 1); |
789 | const int d = qMax(a: depth >> level, b: 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(maxlen: 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). |
840 | QTextureImageDataPtr setHdrFile(QIODevice *source) |
841 | { |
842 | QTextureImageDataPtr imageData; |
843 | char sig[256]; |
844 | source->read(data: sig, maxlen: 11); |
845 | if (strncmp(s1: sig, s2: "#?RADIANCE\n" , 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(index: 7).trimmed(); |
861 | if (format != QByteArrayLiteral("32-bit_rle_rgbe" )) { |
862 | qWarning(msg: "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(msg: "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(msg: "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(s: line.constData(), format: "-Y %d +X %d" , &h, &w)) { |
891 | qWarning(msg: "Unsupported HDR resolution string '%s'" , line.constData()); |
892 | return imageData; |
893 | } |
894 | if (w <= 0 || h <= 0) { |
895 | qWarning(msg: "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(size: 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(msg: "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(dest: scanline[x], src: scanline[x - 1], n: 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(x: 2.0f, y: 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, isCompressed: false); |
990 | |
991 | return imageData; |
992 | } |
993 | |
994 | } // anonynous |
995 | |
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(flags: QIODevice::ReadOnly)) |
1007 | qWarning() << "Failed to open" << source; |
1008 | else |
1009 | textureData = loadTextureData(data: &f, suffix: QFileInfo(source).suffix().toLower(), allow3D, mirrored); |
1010 | } |
1011 | return textureData; |
1012 | } |
1013 | |
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(device: data, format: 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 | |
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(url: m_url)) { |
1062 | if (m_sourceData.isEmpty()) { |
1063 | // first time around, trigger a download |
1064 | if (m_texture) { |
1065 | auto downloadService = Qt3DCore::QDownloadHelperService::getService(engine: 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(openMode: QIODevice::ReadOnly)) { |
1078 | QString suffix = m_url.toString(); |
1079 | suffix = suffix.right(n: suffix.length() - suffix.lastIndexOf(c: '.')); |
1080 | |
1081 | QStringList ext(suffix); |
1082 | |
1083 | QMimeDatabase db; |
1084 | QMimeType mtype = db.mimeTypeForData(data: m_sourceData); |
1085 | if (mtype.isValid()) { |
1086 | ext << mtype.suffixes(); |
1087 | } |
1088 | |
1089 | for (const QString &s: qAsConst(t&: ext)) { |
1090 | textureData = TextureLoadingHelper::loadTextureData(data: &buffer, suffix: s, allow3D: true, mirrored: m_mirrored); |
1091 | if (textureData && textureData->data().length() > 0) |
1092 | break; |
1093 | } |
1094 | } |
1095 | } else { |
1096 | textureData = TextureLoadingHelper::loadTextureData(url: m_url, allow3D: true, mirrored: 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(imageData: textureData); |
1111 | } |
1112 | |
1113 | return generatedData; |
1114 | } |
1115 | |
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 |
1129 | void TextureDownloadRequest::onCompleted() |
1130 | { |
1131 | if (cancelled() || !succeeded()) |
1132 | return; |
1133 | |
1134 | QRenderAspectPrivate* d_aspect = QRenderAspectPrivate::findPrivate(engine: m_engine); |
1135 | if (!d_aspect) |
1136 | return; |
1137 | |
1138 | Render::TextureManager *textureManager = d_aspect->m_nodeManagers->textureManager(); |
1139 | Render::Texture *texture = textureManager->lookupResource(id: m_texNodeId); |
1140 | if (texture == nullptr) |
1141 | return; |
1142 | |
1143 | QTextureFromSourceGeneratorPtr oldGenerator = qSharedPointerCast<QTextureFromSourceGenerator>(src: 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(flags: 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 | */ |
1170 | QTexture1D::QTexture1D(QNode *parent) |
1171 | : QAbstractTexture(Target1D, parent) |
1172 | { |
1173 | } |
1174 | |
1175 | /*! \internal */ |
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 | */ |
1198 | QTexture1DArray::QTexture1DArray(QNode *parent) |
1199 | : QAbstractTexture(Target1DArray, parent) |
1200 | { |
1201 | } |
1202 | |
1203 | /*! \internal */ |
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 | */ |
1226 | QTexture2D::QTexture2D(QNode *parent) |
1227 | : QAbstractTexture(Target2D, parent) |
1228 | { |
1229 | } |
1230 | |
1231 | /*! \internal */ |
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 | */ |
1254 | QTexture2DArray::QTexture2DArray(QNode *parent) |
1255 | : QAbstractTexture(Target2DArray, parent) |
1256 | { |
1257 | } |
1258 | |
1259 | /*! \internal */ |
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 | */ |
1282 | QTexture3D::QTexture3D(QNode *parent) |
1283 | : QAbstractTexture(Target3D, parent) |
1284 | { |
1285 | } |
1286 | |
1287 | /*! \internal */ |
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 | */ |
1310 | QTextureCubeMap::QTextureCubeMap(QNode *parent) |
1311 | : QAbstractTexture(TargetCubeMap, parent) |
1312 | { |
1313 | } |
1314 | |
1315 | /*! \internal */ |
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 | */ |
1338 | QTextureCubeMapArray::QTextureCubeMapArray(QNode *parent) |
1339 | : QAbstractTexture(TargetCubeMapArray, parent) |
1340 | { |
1341 | } |
1342 | |
1343 | /*! \internal */ |
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 | */ |
1366 | QTexture2DMultisample::QTexture2DMultisample(QNode *parent) |
1367 | : QAbstractTexture(Target2DMultisample, parent) |
1368 | { |
1369 | } |
1370 | |
1371 | /*! \internal */ |
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 | */ |
1394 | QTexture2DMultisampleArray::QTexture2DMultisampleArray(QNode *parent) |
1395 | : QAbstractTexture(Target2DMultisampleArray, parent) |
1396 | { |
1397 | } |
1398 | |
1399 | /*! \internal */ |
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 | */ |
1422 | QTextureRectangle::QTextureRectangle(QNode *parent) |
1423 | : QAbstractTexture(TargetRectangle, parent) |
1424 | { |
1425 | } |
1426 | |
1427 | /*! \internal */ |
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 | */ |
1450 | QTextureBuffer::QTextureBuffer(QNode *parent) |
1451 | : QAbstractTexture(TargetBuffer, parent) |
1452 | { |
1453 | } |
1454 | |
1455 | /*! \internal */ |
1456 | QTextureBuffer::~QTextureBuffer() |
1457 | { |
1458 | } |
1459 | |
1460 | QTextureLoaderPrivate::QTextureLoaderPrivate() |
1461 | : QAbstractTexturePrivate() |
1462 | , m_mirrored(true) |
1463 | { |
1464 | } |
1465 | |
1466 | void QTextureLoaderPrivate::setScene(Qt3DCore::QScene *scene) |
1467 | { |
1468 | QAbstractTexturePrivate::setScene(scene); |
1469 | updateGenerator(); |
1470 | } |
1471 | |
1472 | void QTextureLoaderPrivate::updateGenerator() |
1473 | { |
1474 | Q_Q(QTextureLoader); |
1475 | Qt3DCore::QAspectEngine *engine = m_scene ? m_scene->engine() : nullptr; |
1476 | setDataFunctor(QTextureFromSourceGeneratorPtr::create(arguments: q, arguments&: engine, arguments&: 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 | */ |
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(sender: this, signal: &QAbstractTexture::formatChanged, slot: regenerate); |
1523 | } |
1524 | |
1525 | /*! \internal */ |
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 | */ |
1540 | QUrl QTextureLoader::source() const |
1541 | { |
1542 | Q_D(const QTextureLoader); |
1543 | return d->m_source; |
1544 | } |
1545 | |
1546 | 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 | */ |
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(block: true); |
1568 | emit sourceChanged(source); |
1569 | blockNotifications(block: 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 | */ |
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(block: true); |
1626 | emit mirroredChanged(mirrored); |
1627 | blockNotifications(block: blocked); |
1628 | } |
1629 | } |
1630 | |
1631 | /* |
1632 | * Constructs a new QTextureFromSourceGenerator::QTextureFromSourceGenerator |
1633 | * instance with properties passed in via \a textureLoader |
1634 | * \param url |
1635 | */ |
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 | |
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 | */ |
1681 | bool QTextureFromSourceGenerator::operator ==(const QTextureGenerator &other) const |
1682 | { |
1683 | const QTextureFromSourceGenerator *otherFunctor = functor_cast<QTextureFromSourceGenerator>(other: &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 | |
1692 | QUrl QTextureFromSourceGenerator::url() const |
1693 | { |
1694 | return m_url; |
1695 | } |
1696 | |
1697 | 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 | |
1740 | QSharedGLTexture::QSharedGLTexture(Qt3DCore::QNode *parent) |
1741 | : QAbstractTexture(parent) |
1742 | { |
1743 | QAbstractTexturePrivate *d = static_cast<QAbstractTexturePrivate *>(Qt3DCore::QNodePrivate::get(q: this)); |
1744 | d->m_target = TargetAutomatic; |
1745 | } |
1746 | |
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 | */ |
1761 | int QSharedGLTexture::textureId() const |
1762 | { |
1763 | return static_cast<QAbstractTexturePrivate *>(d_ptr.get())->m_sharedTextureId; |
1764 | } |
1765 | |
1766 | void QSharedGLTexture::setTextureId(int id) |
1767 | { |
1768 | QAbstractTexturePrivate *d = static_cast<QAbstractTexturePrivate *>(Qt3DCore::QNodePrivate::get(q: this)); |
1769 | if (d->m_sharedTextureId != id) { |
1770 | d->m_sharedTextureId = id; |
1771 | emit textureIdChanged(textureId: id); |
1772 | } |
1773 | } |
1774 | |
1775 | } // namespace Qt3DRender |
1776 | |
1777 | QT_END_NAMESPACE |
1778 | |