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