1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219
|
#include "TextureLoaderPvr.h"
#include "../../Main.h"
#include <Base/Memory.h>
using namespace Death::IO;
using namespace Death::Memory;
namespace nCine
{
TextureLoaderPvr::TextureLoaderPvr(std::unique_ptr<Stream> fileHandle)
: ITextureLoader(std::move(fileHandle))
{
Pvr3Header header;
if (!fileHandle_->IsValid()) {
return;
}
const bool headerRead = readHeader(header);
DEATH_ASSERT(headerRead, "PVR header cannot be read", );
const bool formatParsed = parseFormat(header);
DEATH_ASSERT(formatParsed, "PVR format cannot be parsed", );
hasLoaded_ = true;
}
bool TextureLoaderPvr::readHeader(Pvr3Header& header)
{
// PVR3 header is 52 bytes long
fileHandle_->Read(&header, 52);
// Checking for the header presence ("PVR"03)
DEATH_ASSERT(AsLE(header.version) == 0x03525650, "Invalid PVR3 signature", false);
headerSize_ = 52 + AsLE(header.metaDataSize);
width_ = AsLE(header.width);
height_ = AsLE(header.height);
mipMapCount_ = header.numMipmaps;
if (mipMapCount_ == 0) {
mipMapCount_ = 1;
}
return true;
}
bool TextureLoaderPvr::parseFormat(const Pvr3Header& header)
{
GLenum internalFormat = GL_RGB8; // to suppress uninitialized variable warning
uint64_t pixelFormat = AsLE(header.pixelFormat);
// Texture contains compressed data, most significant 4 bytes have been set to zero
if (pixelFormat < 0x0000000100000000ULL) {
LOGI("Compressed format: {}", pixelFormat);
// Parsing the pixel format
switch (pixelFormat) {
case FMT_DXT1:
internalFormat = GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
break;
case FMT_DXT3:
internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
break;
case FMT_DXT5:
internalFormat = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
break;
#if defined(WITH_OPENGLES)
case FMT_ETC1:
internalFormat = GL_ETC1_RGB8_OES;
break;
case FMT_PVRTC_2BPP_RGB:
internalFormat = GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG;
break;
case FMT_PVRTC_2BPP_RGBA:
internalFormat = GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG;
break;
case FMT_PVRTC_4BPP_RGB:
internalFormat = GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG;
break;
case FMT_PVRTC_4BPP_RGBA:
internalFormat = GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;
break;
case FMT_PVRTCII_2BPP:
case FMT_PVRTCII_4BPP:
LOGF("No support for PVRTC-II compression");
break;
case FMT_ETC2_RGB:
internalFormat = GL_COMPRESSED_RGB8_ETC2;
break;
case FMT_ETC2_RGBA:
internalFormat = GL_COMPRESSED_RGBA8_ETC2_EAC;
break;
case FMT_ETC2_RGB_A1:
internalFormat = GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2;
break;
case FMT_EAC_R11:
internalFormat = GL_COMPRESSED_R11_EAC;
break;
case FMT_EAC_RG11:
internalFormat = GL_COMPRESSED_RG11_EAC;
break;
# if (!defined(DEATH_TARGET_ANDROID) && defined(WITH_OPENGLES)) || (defined(DEATH_TARGET_ANDROID) && __ANDROID_API__ >= 21)
case FMT_ASTC_4x4:
internalFormat = GL_COMPRESSED_RGBA_ASTC_4x4_KHR;
break;
case FMT_ASTC_5x4:
internalFormat = GL_COMPRESSED_RGBA_ASTC_5x4_KHR;
break;
case FMT_ASTC_5x5:
internalFormat = GL_COMPRESSED_RGBA_ASTC_5x5_KHR;
break;
case FMT_ASTC_6x5:
internalFormat = GL_COMPRESSED_RGBA_ASTC_6x5_KHR;
break;
case FMT_ASTC_6x6:
internalFormat = GL_COMPRESSED_RGBA_ASTC_6x6_KHR;
break;
case FMT_ASTC_8x5:
internalFormat = GL_COMPRESSED_RGBA_ASTC_8x5_KHR;
break;
case FMT_ASTC_8x6:
internalFormat = GL_COMPRESSED_RGBA_ASTC_8x6_KHR;
break;
case FMT_ASTC_8x8:
internalFormat = GL_COMPRESSED_RGBA_ASTC_8x8_KHR;
break;
case FMT_ASTC_10x5:
internalFormat = GL_COMPRESSED_RGBA_ASTC_10x5_KHR;
break;
case FMT_ASTC_10x6:
internalFormat = GL_COMPRESSED_RGBA_ASTC_10x6_KHR;
break;
case FMT_ASTC_10x8:
internalFormat = GL_COMPRESSED_RGBA_ASTC_10x8_KHR;
break;
case FMT_ASTC_10x10:
internalFormat = GL_COMPRESSED_RGBA_ASTC_10x10_KHR;
break;
case FMT_ASTC_12x10:
internalFormat = GL_COMPRESSED_RGBA_ASTC_12x10_KHR;
break;
case FMT_ASTC_12x12:
internalFormat = GL_COMPRESSED_RGBA_ASTC_12x12_KHR;
break;
# endif
#endif
default:
LOGE("Unsupported PVR3 compressed format: 0x{:x}", pixelFormat);
return false;
}
loadPixels(internalFormat);
} else {
// Texture contains uncompressed data
GLenum type = GL_UNSIGNED_BYTE;
LOGI("Uncompressed format: {:c}{:c}{:c}{:c} ({}, {}, {}, {})",
reinterpret_cast<char*>(&pixelFormat)[0], reinterpret_cast<char*>(&pixelFormat)[1],
reinterpret_cast<char*>(&pixelFormat)[2], reinterpret_cast<char*>(&pixelFormat)[3],
reinterpret_cast<unsigned char*>(&pixelFormat)[4], reinterpret_cast<unsigned char*>(&pixelFormat)[5],
reinterpret_cast<unsigned char*>(&pixelFormat)[6], reinterpret_cast<unsigned char*>(&pixelFormat)[7]);
switch (pixelFormat) {
case FMT_BGRA_8888:
#if !defined(WITH_OPENGLES)
internalFormat = GL_BGRA;
#else
internalFormat = GL_BGRA_EXT;
#endif
break;
case FMT_RGBA_8888:
internalFormat = GL_RGBA8;
break;
case FMT_RGB_888:
internalFormat = GL_RGB8;
break;
case FMT_RGB_565:
internalFormat = GL_RGB565;
type = GL_UNSIGNED_SHORT_5_6_5;
break;
case FMT_RGBA_5551:
internalFormat = GL_RGB5_A1;
type = GL_UNSIGNED_SHORT_5_5_5_1;
break;
case FMT_RGBA_4444:
internalFormat = GL_RGBA4;
type = GL_UNSIGNED_SHORT_4_4_4_4;
break;
case FMT_LA_88:
internalFormat = GL_RG8;
break;
case FMT_L_8:
internalFormat = GL_R8;
break;
case FMT_A_8:
internalFormat = GL_R8;
break;
default:
LOGE("Unsupported PVR3 uncompressed format: 0x{:x}", pixelFormat);
return false;
}
loadPixels(internalFormat, type);
}
if (mipMapCount_ > 1) {
LOGI("MIP Maps: {}", mipMapCount_);
mipDataOffsets_ = std::make_unique<std::uint32_t[]>(mipMapCount_);
mipDataSizes_ = std::make_unique<std::uint32_t[]>(mipMapCount_);
std::uint32_t dataSizesSum = TextureFormat::calculateMipSizes(internalFormat, width_, height_, mipMapCount_, mipDataOffsets_.get(), mipDataSizes_.get());
if (dataSizesSum != dataSize_) {
LOGW("The sum of MIP maps size ({}) is different than texture total data ({})", dataSizesSum, dataSize_);
}
}
return true;
}
}
|