1/**
2 * Copyright (c) 2006-2023 LOVE Development Team
3 *
4 * This software is provided 'as-is', without any express or implied
5 * warranty. In no event will the authors be held liable for any damages
6 * arising from the use of this software.
7 *
8 * Permission is granted to anyone to use this software for any purpose,
9 * including commercial applications, and to alter it and redistribute it
10 * freely, subject to the following restrictions:
11 *
12 * 1. The origin of this software must not be misrepresented; you must not
13 * claim that you wrote the original software. If you use this software
14 * in a product, an acknowledgment in the product documentation would be
15 * appreciated but is not required.
16 * 2. Altered source versions must be plainly marked as such, and must not be
17 * misrepresented as being the original software.
18 * 3. This notice may not be removed or altered from any source distribution.
19 **/
20
21// LOVE
22#include "PVRHandler.h"
23#include "common/int.h"
24#include "common/Exception.h"
25
26// C++
27#include <algorithm>
28
29namespace love
30{
31namespace image
32{
33namespace magpie
34{
35
36namespace
37{
38
39// 'P' 'V' 'R' 3
40static const uint32 PVRTEX3_IDENT = 0x03525650;
41static const uint32 PVRTEX3_IDENT_REV = 0x50565203;
42
43#pragma pack(push, 4)
44struct PVRTexHeaderV3
45{
46 uint32 version; /// Version of the file header, used to identify it.
47 uint32 flags; /// Various format flags.
48 uint64 pixelFormat; /// The pixel format, 8cc value storing the 4 channel identifiers and their respective sizes.
49 uint32 colorSpace; /// The Color Space of the texture, currently either linear RGB or sRGB.
50 uint32 channelType; /// Variable type that the channel is stored in. Supports signed/unsigned int/short/byte or float for now.
51 uint32 height; /// Height of the texture.
52 uint32 width; /// Width of the texture.
53 uint32 depth; /// Depth of the texture. (Z-slices)
54 uint32 numSurfaces; /// Number of members in a Texture Array.
55 uint32 numFaces; /// Number of faces in a Cube Map. Maybe be a value other than 6.
56 uint32 numMipmaps; /// Number of MIP Maps in the texture - NB: Includes top level.
57 uint32 metaDataSize; /// Size of the accompanying meta data.
58};
59#pragma pack(pop)
60
61enum PVRV3PixelFormat
62{
63 ePVRTPF_PVRTCI_2bpp_RGB = 0,
64 ePVRTPF_PVRTCI_2bpp_RGBA,
65 ePVRTPF_PVRTCI_4bpp_RGB,
66 ePVRTPF_PVRTCI_4bpp_RGBA,
67 ePVRTPF_PVRTCII_2bpp = 4,
68 ePVRTPF_PVRTCII_4bpp,
69 ePVRTPF_ETC1 = 6,
70 ePVRTPF_DXT1 = 7,
71 ePVRTPF_DXT2,
72 ePVRTPF_DXT3,
73 ePVRTPF_DXT4,
74 ePVRTPF_DXT5,
75 ePVRTPF_BC4,
76 ePVRTPF_BC5,
77 ePVRTPF_BC6,
78 ePVRTPF_BC7,
79 ePVRTPF_ETC2_RGB = 22,
80 ePVRTPF_ETC2_RGBA,
81 ePVRTPF_ETC2_RGBA1,
82 ePVRTPF_EAC_R = 25,
83 ePVRTPF_EAC_RG,
84 ePVRTPF_ASTC_4x4 = 27,
85 ePVRTPF_ASTC_5x4,
86 ePVRTPF_ASTC_5x5,
87 ePVRTPF_ASTC_6x5,
88 ePVRTPF_ASTC_6x6,
89 ePVRTPF_ASTC_8x5,
90 ePVRTPF_ASTC_8x6,
91 ePVRTPF_ASTC_8x8,
92 ePVRTPF_ASTC_10x5,
93 ePVRTPF_ASTC_10x6,
94 ePVRTPF_ASTC_10x8,
95 ePVRTPF_ASTC_10x10,
96 ePVRTPF_ASTC_12x10,
97 ePVRTPF_ASTC_12x12,
98 ePVRTPF_UNKNOWN_FORMAT = 0x7F
99};
100
101enum PVRV3ChannelType
102{
103 ePVRTCT_UNORM8 = 0,
104 ePVRTCT_SNORM8,
105 ePVRTCT_UINT8,
106 ePVRTCT_SINT8,
107 ePVRTCT_UNORM16,
108 ePVRTCT_SNORM16,
109 ePVRTCT_UINT16,
110 ePVRTCT_SINT16,
111 ePVRTCT_UNORM32,
112 ePVRTCT_SNORM32,
113 ePVRTCT_UINT32,
114 ePVRTCT_SINT32,
115 ePVRTCT_FLOAT
116};
117
118// 'P' 'V' 'R' '!'
119static const uint32 PVRTEX2_IDENT = 0x21525650;
120static const uint32 PVRTEX2_IDENT_REV = 0x50565221;
121
122struct PVRTexHeaderV2
123{
124 uint32 headerSize;
125 uint32 height;
126 uint32 width;
127 uint32 numMipmaps;
128 uint32 flags;
129 uint32 dataSize;
130 uint32 bpp;
131 uint32 bitmaskRed;
132 uint32 bitmaskGreen;
133 uint32 bitmaskBlue;
134 uint32 bitmaskAlpha;
135 uint32 pvrTag;
136 uint32 numSurfaces;
137};
138
139// The legacy V2 pixel types we support.
140enum PVRPixelTypeV2
141{
142 PixelTypePVRTC2 = 0x18,
143 PixelTypePVRTC4,
144 PixelTypePVRTCII2 = 0x1C,
145 PixelTypePVRTCII4,
146 PixelTypeDXT1 = 0x20,
147 PixelTypeDXT3 = 0x22,
148 PixelTypeDXT5 = 0x24,
149 PixelTypeETC1 = 0x36
150};
151
152// Convert a V2 header to V3.
153void ConvertPVRHeader(PVRTexHeaderV2 header2, PVRTexHeaderV3 *header3)
154{
155 // If the header's endianness doesn't match our own, we swap everything.
156 if (header2.pvrTag == PVRTEX2_IDENT_REV)
157 {
158 // All of the struct's members are uint32 values, so we can do this.
159 uint32 *headerArray = (uint32 *) &header2;
160 for (size_t i = 0; i < sizeof(PVRTexHeaderV2) / sizeof(uint32); i++)
161 headerArray[i] = swapuint32(headerArray[i]);
162 }
163
164 memset(header3, 0, sizeof(PVRTexHeaderV3));
165
166 header3->version = PVRTEX3_IDENT;
167 header3->height = header2.height;
168 header3->width = header2.width;
169 header3->depth = 1;
170 header3->numSurfaces = header2.numSurfaces;
171 header3->numFaces = 1;
172 header3->numMipmaps = header2.numMipmaps;
173 header3->metaDataSize = 0;
174
175 switch ((PVRPixelTypeV2) (header2.flags & 0xFF))
176 {
177 case PixelTypePVRTC2:
178 header3->pixelFormat = ePVRTPF_PVRTCI_2bpp_RGBA;
179 break;
180 case PixelTypePVRTC4:
181 header3->pixelFormat = ePVRTPF_PVRTCI_4bpp_RGBA;
182 break;
183 case PixelTypePVRTCII2:
184 header3->pixelFormat = ePVRTPF_PVRTCII_2bpp;
185 break;
186 case PixelTypePVRTCII4:
187 header3->pixelFormat = ePVRTPF_PVRTCII_4bpp;
188 break;
189 case PixelTypeDXT1:
190 header3->pixelFormat = ePVRTPF_DXT1;
191 break;
192 case PixelTypeDXT3:
193 header3->pixelFormat = ePVRTPF_DXT3;
194 break;
195 case PixelTypeDXT5:
196 header3->pixelFormat = ePVRTPF_DXT5;
197 break;
198 case PixelTypeETC1:
199 header3->pixelFormat = ePVRTPF_ETC1;
200 break;
201 default:
202 header3->pixelFormat = ePVRTPF_UNKNOWN_FORMAT;
203 break;
204 }
205}
206
207static PixelFormat convertFormat(PVRV3PixelFormat format, PVRV3ChannelType channeltype)
208{
209 bool snorm = false;
210
211 switch (channeltype)
212 {
213 case ePVRTCT_SNORM8:
214 case ePVRTCT_SNORM16:
215 case ePVRTCT_SNORM32:
216 snorm = true;
217 break;
218 default:
219 break;
220 }
221
222 switch (format)
223 {
224 case ePVRTPF_PVRTCI_2bpp_RGB:
225 return PIXELFORMAT_PVR1_RGB2;
226 case ePVRTPF_PVRTCI_2bpp_RGBA:
227 return PIXELFORMAT_PVR1_RGBA2;
228 case ePVRTPF_PVRTCI_4bpp_RGB:
229 return PIXELFORMAT_PVR1_RGB4;
230 case ePVRTPF_PVRTCI_4bpp_RGBA:
231 return PIXELFORMAT_PVR1_RGBA4;
232 case ePVRTPF_ETC1:
233 return PIXELFORMAT_ETC1;
234 case ePVRTPF_DXT1:
235 return PIXELFORMAT_DXT1;
236 case ePVRTPF_DXT3:
237 return PIXELFORMAT_DXT3;
238 case ePVRTPF_DXT5:
239 return PIXELFORMAT_DXT5;
240 case ePVRTPF_BC4:
241 return snorm ? PIXELFORMAT_BC4s : PIXELFORMAT_BC4;
242 case ePVRTPF_BC5:
243 return snorm ? PIXELFORMAT_BC5s : PIXELFORMAT_BC5;
244 case ePVRTPF_BC6:
245 return snorm ? PIXELFORMAT_BC6Hs : PIXELFORMAT_BC6H;
246 case ePVRTPF_BC7:
247 return PIXELFORMAT_BC7;
248 case ePVRTPF_ETC2_RGB:
249 return PIXELFORMAT_ETC2_RGB;
250 case ePVRTPF_ETC2_RGBA:
251 return PIXELFORMAT_ETC2_RGBA;
252 case ePVRTPF_ETC2_RGBA1:
253 return PIXELFORMAT_ETC2_RGBA1;
254 case ePVRTPF_EAC_R:
255 return snorm ? PIXELFORMAT_EAC_Rs : PIXELFORMAT_EAC_R;
256 case ePVRTPF_EAC_RG:
257 return snorm ? PIXELFORMAT_EAC_RGs : PIXELFORMAT_EAC_RG;
258 case ePVRTPF_ASTC_4x4:
259 return PIXELFORMAT_ASTC_4x4;
260 case ePVRTPF_ASTC_5x4:
261 return PIXELFORMAT_ASTC_5x4;
262 case ePVRTPF_ASTC_5x5:
263 return PIXELFORMAT_ASTC_5x5;
264 case ePVRTPF_ASTC_6x5:
265 return PIXELFORMAT_ASTC_6x5;
266 case ePVRTPF_ASTC_6x6:
267 return PIXELFORMAT_ASTC_6x6;
268 case ePVRTPF_ASTC_8x5:
269 return PIXELFORMAT_ASTC_8x5;
270 case ePVRTPF_ASTC_8x6:
271 return PIXELFORMAT_ASTC_8x6;
272 case ePVRTPF_ASTC_8x8:
273 return PIXELFORMAT_ASTC_8x8;
274 case ePVRTPF_ASTC_10x5:
275 return PIXELFORMAT_ASTC_10x5;
276 case ePVRTPF_ASTC_10x6:
277 return PIXELFORMAT_ASTC_10x6;
278 case ePVRTPF_ASTC_10x8:
279 return PIXELFORMAT_ASTC_10x8;
280 case ePVRTPF_ASTC_10x10:
281 return PIXELFORMAT_ASTC_10x10;
282 case ePVRTPF_ASTC_12x10:
283 return PIXELFORMAT_ASTC_12x10;
284 case ePVRTPF_ASTC_12x12:
285 return PIXELFORMAT_ASTC_12x12;
286 default:
287 return PIXELFORMAT_UNKNOWN;
288 }
289}
290
291int getBitsPerPixel(uint64 pixelformat)
292{
293 // Uncompressed formats have their bits per pixel stored in the high bits.
294 if ((pixelformat & 0xFFFFFFFF) != pixelformat)
295 {
296 const uint8 *charformat = (const uint8 *) &pixelformat;
297 return charformat[4] + charformat[5] + charformat[6] + charformat[7];
298 }
299
300 switch (pixelformat)
301 {
302 case ePVRTPF_PVRTCI_2bpp_RGB:
303 case ePVRTPF_PVRTCI_2bpp_RGBA:
304 case ePVRTPF_PVRTCII_2bpp:
305 return 2;
306 case ePVRTPF_PVRTCI_4bpp_RGB:
307 case ePVRTPF_PVRTCI_4bpp_RGBA:
308 case ePVRTPF_PVRTCII_4bpp:
309 case ePVRTPF_ETC1:
310 case ePVRTPF_DXT1:
311 case ePVRTPF_BC4:
312 case ePVRTPF_ETC2_RGB:
313 case ePVRTPF_ETC2_RGBA1:
314 case ePVRTPF_EAC_R:
315 return 4;
316 case ePVRTPF_DXT2:
317 case ePVRTPF_DXT3:
318 case ePVRTPF_DXT4:
319 case ePVRTPF_DXT5:
320 case ePVRTPF_BC5:
321 case ePVRTPF_BC6:
322 case ePVRTPF_BC7:
323 case ePVRTPF_ETC2_RGBA:
324 case ePVRTPF_EAC_RG:
325 return 8;
326 default:
327 return 0;
328 }
329}
330
331void getFormatMinDimensions(uint64 pixelformat, int &minX, int &minY, int &minZ)
332{
333 minZ = 1;
334
335 switch (pixelformat)
336 {
337 case ePVRTPF_PVRTCI_2bpp_RGB:
338 case ePVRTPF_PVRTCI_2bpp_RGBA:
339 minX = 16;
340 minY = 8;
341 break;
342 case ePVRTPF_PVRTCI_4bpp_RGB:
343 case ePVRTPF_PVRTCI_4bpp_RGBA:
344 minX = minY = 8;
345 break;
346 case ePVRTPF_PVRTCII_2bpp:
347 minX = 8;
348 minY = 4;
349 break;
350 case ePVRTPF_PVRTCII_4bpp:
351 minX = minY = 4;
352 break;
353 case ePVRTPF_DXT1:
354 case ePVRTPF_DXT2:
355 case ePVRTPF_DXT3:
356 case ePVRTPF_DXT4:
357 case ePVRTPF_DXT5:
358 case ePVRTPF_BC4:
359 case ePVRTPF_BC5:
360 case ePVRTPF_BC6:
361 case ePVRTPF_BC7:
362 case ePVRTPF_ETC1:
363 case ePVRTPF_ETC2_RGB:
364 case ePVRTPF_ETC2_RGBA:
365 case ePVRTPF_ETC2_RGBA1:
366 case ePVRTPF_EAC_R:
367 case ePVRTPF_EAC_RG:
368 minX = minY = 4;
369 break;
370 case ePVRTPF_ASTC_4x4:
371 minX = 4;
372 minY = 4;
373 break;
374 case ePVRTPF_ASTC_5x4:
375 minX = 5;
376 minY = 4;
377 break;
378 case ePVRTPF_ASTC_5x5:
379 minX = 5;
380 minY = 5;
381 break;
382 case ePVRTPF_ASTC_6x5:
383 minX = 6;
384 minY = 5;
385 break;
386 case ePVRTPF_ASTC_6x6:
387 minX = 6;
388 minY = 6;
389 break;
390 case ePVRTPF_ASTC_8x5:
391 minX = 8;
392 minY = 5;
393 break;
394 case ePVRTPF_ASTC_8x6:
395 minX = 8;
396 minY = 6;
397 break;
398 case ePVRTPF_ASTC_8x8:
399 minX = 8;
400 minY = 8;
401 break;
402 case ePVRTPF_ASTC_10x5:
403 minX = 10;
404 minY = 5;
405 break;
406 case ePVRTPF_ASTC_10x6:
407 minX = 10;
408 minY = 6;
409 break;
410 case ePVRTPF_ASTC_10x8:
411 minX = 10;
412 minY = 8;
413 break;
414 case ePVRTPF_ASTC_10x10:
415 minX = 10;
416 minY = 10;
417 break;
418 case ePVRTPF_ASTC_12x10:
419 minX = 12;
420 minY = 10;
421 break;
422 case ePVRTPF_ASTC_12x12:
423 minX = 12;
424 minY = 12;
425 break;
426 default: // We don't handle all possible formats, but that's fine.
427 minX = minY = 1;
428 break;
429 }
430}
431
432size_t getMipLevelSize(const PVRTexHeaderV3 &header, int miplevel)
433{
434 int smallestwidth = 1;
435 int smallestheight = 1;
436 int smallestdepth = 1;
437 getFormatMinDimensions(header.pixelFormat, smallestwidth, smallestheight, smallestdepth);
438
439 int width = std::max((int) header.width >> miplevel, 1);
440 int height = std::max((int) header.height >> miplevel, 1);
441 int depth = std::max((int) header.depth >> miplevel, 1);
442
443 // Pad the dimensions.
444 width = ((width + smallestwidth - 1) / smallestwidth) * smallestwidth;
445 height = ((height + smallestheight - 1) / smallestheight) * smallestheight;
446 depth = ((depth + smallestdepth - 1) / smallestdepth) * smallestdepth;
447
448 if (header.pixelFormat >= ePVRTPF_ASTC_4x4 && header.pixelFormat <= ePVRTPF_ASTC_12x12)
449 return (width / smallestwidth) * (height / smallestheight) * (depth / smallestdepth) * (128 / 8);
450 else
451 return getBitsPerPixel(header.pixelFormat) * width * height * depth / 8;
452}
453
454} // Anonymous namespace.
455
456
457bool PVRHandler::canParseCompressed(Data *data)
458{
459 if (data->getSize() < sizeof(PVRTexHeaderV2) || data->getSize() < sizeof(PVRTexHeaderV3))
460 return false;
461
462 PVRTexHeaderV3 *header3 = (PVRTexHeaderV3 *) data->getData();
463
464 // Magic number (FourCC identifier.)
465 if (header3->version == PVRTEX3_IDENT || header3->version == PVRTEX3_IDENT_REV)
466 return true;
467
468 // Maybe it has a V2 header.
469 PVRTexHeaderV2 *header2 = (PVRTexHeaderV2 *) data->getData();
470
471 // FourCC identifier.
472 if (header2->pvrTag == PVRTEX2_IDENT || header2->pvrTag == PVRTEX2_IDENT_REV)
473 return true;
474
475 return false;
476}
477
478StrongRef<CompressedMemory> PVRHandler::parseCompressed(Data *filedata, std::vector<StrongRef<CompressedSlice>> &images, PixelFormat &format, bool &sRGB)
479{
480 if (!canParseCompressed(filedata))
481 throw love::Exception("Could not decode compressed data (not a PVR file?)");
482
483 PVRTexHeaderV3 header3 = *(PVRTexHeaderV3 *) filedata->getData();
484
485 // If the header isn't the V3 format, assume it's V2 and convert.
486 if (header3.version != PVRTEX3_IDENT && header3.version != PVRTEX3_IDENT_REV)
487 ConvertPVRHeader(*(PVRTexHeaderV2 *) filedata->getData(), &header3);
488
489 // If the header's endianness doesn't match our own, then we swap everything.
490 if (header3.version == PVRTEX3_IDENT_REV)
491 {
492 header3.version = PVRTEX3_IDENT;
493 header3.flags = swapuint32(header3.flags);
494 header3.pixelFormat = swapuint64(header3.pixelFormat);
495 header3.colorSpace = swapuint32(header3.colorSpace);
496 header3.channelType = swapuint32(header3.channelType);
497 header3.height = swapuint32(header3.height);
498 header3.width = swapuint32(header3.width);
499 header3.depth = swapuint32(header3.depth);
500 header3.numFaces = swapuint32(header3.numFaces);
501 header3.numMipmaps = swapuint32(header3.numMipmaps);
502 header3.metaDataSize = swapuint32(header3.metaDataSize);
503 }
504
505 if (header3.depth > 1)
506 throw love::Exception("Image depths greater than 1 in PVR files are unsupported.");
507
508 PVRV3PixelFormat pixelformat = (PVRV3PixelFormat) header3.pixelFormat;
509 PVRV3ChannelType channeltype = (PVRV3ChannelType) header3.channelType;
510
511 PixelFormat cformat = convertFormat(pixelformat, channeltype);
512
513 if (cformat == PIXELFORMAT_UNKNOWN)
514 throw love::Exception("Could not parse PVR file: unsupported image format.");
515
516 size_t totalsize = 0;
517
518 // Ignore faces and surfaces except the first ones (for now.)
519 for (int i = 0; i < (int) header3.numMipmaps; i++)
520 totalsize += getMipLevelSize(header3, i);
521
522 size_t fileoffset = sizeof(PVRTexHeaderV3) + header3.metaDataSize;
523
524 // Make sure the file actually holds this much data...
525 if (filedata->getSize() < fileoffset + totalsize)
526 throw love::Exception("Could not parse PVR file: invalid size calculation.");
527
528 StrongRef<CompressedMemory> memory;
529 memory.set(new CompressedMemory(totalsize), Acquire::NORETAIN);
530
531 size_t curoffset = 0;
532 const uint8 *filebytes = (uint8 *) filedata->getData() + fileoffset;
533
534 for (int i = 0; i < (int) header3.numMipmaps; i++)
535 {
536 size_t mipsize = getMipLevelSize(header3, i);
537
538 if (curoffset + mipsize > totalsize)
539 break; // Just in case.
540
541 int width = std::max((int) header3.width >> i, 1);
542 int height = std::max((int) header3.height >> i, 1);
543
544 memcpy(memory->data + curoffset, filebytes + curoffset, mipsize);
545
546 auto slice = new CompressedSlice(cformat, width, height, memory, curoffset, mipsize);
547 images.push_back(slice);
548 slice->release();
549
550 curoffset += mipsize;
551 }
552
553 format = cformat;
554 sRGB = (header3.colorSpace == 1);
555
556 return memory;
557}
558
559} // magpie
560} // image
561} // love
562