diff options
author | Mauro Persano <mauro.persano@kdab.com> | 2016-01-12 10:49:20 -0200 |
---|---|---|
committer | Sean Harmer <sean.harmer@kdab.com> | 2016-01-16 15:52:31 +0000 |
commit | 634ac2a3c1a7bae9eef6476c37cd68209c28ae4f (patch) | |
tree | 270469aeac7988b3534918bedd2becf70cfb8e98 | |
parent | 43e55cd54635a5ef1eb09fe9cff701f7eb16cd7a (diff) |
Support for DDS textures
This commit adds support for DDS textures.
It also adds QTextureLoader, a generic texture provider without a
texture target. The actual texture target will be based on the
properties of the texture loaded from its "source" property.
Change-Id: If89cce7a55b3d82355f2da35588a091b7188f36c
Reviewed-by: Sean Harmer <sean.harmer@kdab.com>
40 files changed, 1153 insertions, 125 deletions
diff --git a/src/render/jobs/loadtexturedatajob.cpp b/src/render/jobs/loadtexturedatajob.cpp index 5f4a9801b..ec41924f6 100644 --- a/src/render/jobs/loadtexturedatajob.cpp +++ b/src/render/jobs/loadtexturedatajob.cpp @@ -55,6 +55,36 @@ LoadTextureDataJob::~LoadTextureDataJob() { } +static QPair<HTextureData, QTexImageData *> textureDataFromFunctor(TextureDataManager *textureDataManager, QTextureDataFunctorPtr functor) +{ + HTextureData textureDataHandle; + QTexImageData *data = Q_NULLPTR; + + QMutexLocker locker(textureDataManager->mutex()); + // We don't want to take the chance of having two jobs uploading the same functor + // because of sync issues + + textureDataHandle = textureDataManager->textureDataFromFunctor(functor); + + // Texture data handle isn't null == there's already a matching TextureData + if (!textureDataHandle.isNull()) { + data = textureDataManager->data(textureDataHandle); + } else { + QTexImageDataPtr dataPtr = functor->operator ()(); + if (dataPtr.isNull()) { + qCDebug(Jobs) << Q_FUNC_INFO << "Texture has no raw data"; + } else { + // Save the QTexImageDataPtr with it's functor as a key + textureDataHandle = textureDataManager->acquire(); + data = textureDataManager->data(textureDataHandle); + *data = *(dataPtr.data()); + textureDataManager->addTextureDataForFunctor(textureDataHandle, functor); + } + } + + return qMakePair(textureDataHandle, data); +} + void LoadTextureDataJob::run() { qCDebug(Jobs) << "Entering" << Q_FUNC_INFO << QThread::currentThread(); @@ -63,40 +93,41 @@ void LoadTextureDataJob::run() TextureDataManager *textureDataManager = m_manager->manager<QTexImageData, TextureDataManager>(); if (txt != Q_NULLPTR) { + if (txt->dataFunctor()) { + QTextureDataFunctorPtr functor = txt->dataFunctor(); + + QPair<HTextureData, QTexImageData *> handleData = textureDataFromFunctor(textureDataManager, functor); + + HTextureData textureDataHandle = handleData.first; + QTexImageData *data = handleData.second; + + if (txt->target() == QAbstractTextureProvider::TargetAutomatic) + txt->setTarget(static_cast<QAbstractTextureProvider::Target>(data->target())); + + if (!txt->isAutoMipMapGenerationEnabled()) + txt->setMipLevels(data->mipLevels()); + + txt->setSize(data->width(), data->height(), data->depth()); + txt->setFormat(static_cast<QAbstractTextureProvider::TextureFormat>(data->format())); + txt->setTextureDataHandle(textureDataHandle); + } + // Load update each TextureImage Q_FOREACH (HTextureImage texImgHandle, txt->textureImages()) { TextureImage *texImg = m_manager->textureImageManager()->data(texImgHandle); if (texImg != Q_NULLPTR && texImg->isDirty() && !texImg->dataFunctor().isNull()) { QTextureDataFunctorPtr functor = texImg->dataFunctor(); - HTextureData textureDataHandle; - QTexImageData *data = Q_NULLPTR; - - // scoped for locker - { - QMutexLocker locker(textureDataManager->mutex()); - // We don't want to take the chance of having two jobs uploading the same functor - // because of sync issues - textureDataHandle = textureDataManager->textureDataFromFunctor(functor); - - // Texture data handle isn't null == there's already a matching TextureData - if (!textureDataHandle.isNull()) { - data = textureDataManager->data(textureDataHandle); - } else { - QTexImageDataPtr dataPtr = functor->operator ()(); - if (dataPtr.isNull()) { - qCDebug(Jobs) << Q_FUNC_INFO << "Texture has no raw data"; - } else { - // Save the QTexImageDataPtr with it's functor as a key - textureDataHandle = textureDataManager->acquire(); - data = textureDataManager->data(textureDataHandle); - *data = *(dataPtr.data()); - textureDataManager->addTextureDataForFunctor(textureDataHandle, functor); - } - } - // Update HTextureImage Functor to release TextureData when needed - textureDataManager->assignFunctorToTextureImage(functor, texImgHandle); - } + QPair<HTextureData, QTexImageData *> handleData = textureDataFromFunctor(textureDataManager, functor); + + HTextureData textureDataHandle = handleData.first; + QTexImageData *data = handleData.second; + + // XXX released textureDataManager mutex, do we have a race here? + + // Update HTextureImage Functor to release TextureData when needed + TextureDataManager *textureDataManager = m_manager->manager<QTexImageData, TextureDataManager>(); + textureDataManager->assignFunctorToTextureImage(functor, texImgHandle); // Set texture size of texture if the first layer / level / face has a valid size // otherwise assume the size was set on the texture itself diff --git a/src/render/texture/qabstracttextureprovider.cpp b/src/render/texture/qabstracttextureprovider.cpp index ca9849771..c46e199b2 100644 --- a/src/render/texture/qabstracttextureprovider.cpp +++ b/src/render/texture/qabstracttextureprovider.cpp @@ -529,6 +529,12 @@ QAbstractTextureProvider::ComparisonMode QAbstractTextureProvider::comparisonMod return d->m_comparisonMode; } +QTextureDataFunctorPtr QAbstractTextureProvider::dataFunctor() const +{ + Q_D(const QAbstractTextureProvider); + return d->m_dataFunctor; +} + } // namespace Qt3DRender QT_END_NAMESPACE diff --git a/src/render/texture/qabstracttextureprovider.h b/src/render/texture/qabstracttextureprovider.h index 093d20864..c23b38275 100644 --- a/src/render/texture/qabstracttextureprovider.h +++ b/src/render/texture/qabstracttextureprovider.h @@ -48,6 +48,9 @@ namespace Qt3DRender { class QAbstractTextureProviderPrivate; class QTextureWrapMode; class QAbstractTextureImage; +class QTextureDataFunctor; + +typedef QSharedPointer<QTextureDataFunctor> QTextureDataFunctorPtr; class QT3DRENDERSHARED_EXPORT QAbstractTextureProvider : public Qt3DCore::QNode { @@ -78,6 +81,7 @@ public: Q_ENUM(Status) enum Target { + TargetAutomatic = 0, // Target will be determined by the Qt3D engine Target1D = 0x0DE0, // GL_TEXTURE_1D Target1DArray = 0x8C18, // GL_TEXTURE_1D_ARRAY Target2D = 0x0DE1, // GL_TEXTURE_2D @@ -288,6 +292,7 @@ public: int depth() const; int maximumLayers() const; bool isUnique() const; + QTextureDataFunctorPtr dataFunctor() const; public Q_SLOTS: void setFormat(TextureFormat format); diff --git a/src/render/texture/qabstracttextureprovider_p.h b/src/render/texture/qabstracttextureprovider_p.h index 47577bb87..b5e62b301 100644 --- a/src/render/texture/qabstracttextureprovider_p.h +++ b/src/render/texture/qabstracttextureprovider_p.h @@ -81,6 +81,8 @@ public : QList<QAbstractTextureImage *> m_textureImages; int m_maximumLayers; bool m_unique; + + QTextureDataFunctorPtr m_dataFunctor; }; } // QT3D diff --git a/src/render/texture/qtexturedata.cpp b/src/render/texture/qtexturedata.cpp index d6663a479..57f3535a0 100644 --- a/src/render/texture/qtexturedata.cpp +++ b/src/render/texture/qtexturedata.cpp @@ -45,13 +45,616 @@ QT_BEGIN_NAMESPACE namespace Qt3DRender { +namespace { + +struct DdsPixelFormat { + quint32 size; + quint32 flags; + quint32 fourCC; + quint32 rgbBitCount; + quint32 redMask; + quint32 greenMask; + quint32 blueMask; + quint32 alphaMask; +}; + +struct DdsHeader { + char magic[4]; + quint32 size; + quint32 flags; + quint32 height; + quint32 width; + quint32 pitchOrLinearSize; + quint32 depth; + quint32 mipmapCount; + quint32 reserved[11]; + DdsPixelFormat pixelFormat; + quint32 caps; + quint32 caps2; + quint32 caps3; + quint32 caps4; + quint32 reserved2; +}; + +struct DdsDX10Header { + quint32 format; + quint32 dimension; + quint32 miscFlag; + quint32 arraySize; + quint32 miscFlags2; +}; + +enum DdsFlags { + MipmapCountFlag = 0x20000, +}; + +enum PixelFormatFlag { + AlphaFlag = 0x1, + FourCCFlag = 0x4, + RGBFlag = 0x40, + RGBAFlag = RGBFlag | AlphaFlag, + YUVFlag = 0x200, + LuminanceFlag = 0x20000 +}; + +enum Caps2Flags { + CubemapFlag = 0x200, + CubemapPositiveXFlag = 0x400, + CubemapNegativeXFlag = 0x800, + CubemapPositiveYFlag = 0x1000, + CubemapNegativeYFlag = 0x2000, + CubemapPositiveZFlag = 0x4000, + CubemapNegativeZFlag = 0x8000, + AllCubemapFaceFlags = CubemapPositiveXFlag | + CubemapNegativeXFlag | + CubemapPositiveYFlag | + CubemapNegativeYFlag | + CubemapPositiveZFlag | + CubemapNegativeZFlag, + VolumeFlag = 0x200000 +}; + +enum DXGIFormat { + DXGI_FORMAT_UNKNOWN = 0, + DXGI_FORMAT_R32G32B32A32_TYPELESS = 1, + DXGI_FORMAT_R32G32B32A32_FLOAT = 2, + DXGI_FORMAT_R32G32B32A32_UINT = 3, + DXGI_FORMAT_R32G32B32A32_SINT = 4, + DXGI_FORMAT_R32G32B32_TYPELESS = 5, + DXGI_FORMAT_R32G32B32_FLOAT = 6, + DXGI_FORMAT_R32G32B32_UINT = 7, + DXGI_FORMAT_R32G32B32_SINT = 8, + DXGI_FORMAT_R16G16B16A16_TYPELESS = 9, + DXGI_FORMAT_R16G16B16A16_FLOAT = 10, + DXGI_FORMAT_R16G16B16A16_UNORM = 11, + DXGI_FORMAT_R16G16B16A16_UINT = 12, + DXGI_FORMAT_R16G16B16A16_SNORM = 13, + DXGI_FORMAT_R16G16B16A16_SINT = 14, + DXGI_FORMAT_R32G32_TYPELESS = 15, + DXGI_FORMAT_R32G32_FLOAT = 16, + DXGI_FORMAT_R32G32_UINT = 17, + DXGI_FORMAT_R32G32_SINT = 18, + DXGI_FORMAT_R32G8X24_TYPELESS = 19, + DXGI_FORMAT_D32_FLOAT_S8X24_UINT = 20, + DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS = 21, + DXGI_FORMAT_X32_TYPELESS_G8X24_UINT = 22, + DXGI_FORMAT_R10G10B10A2_TYPELESS = 23, + DXGI_FORMAT_R10G10B10A2_UNORM = 24, + DXGI_FORMAT_R10G10B10A2_UINT = 25, + DXGI_FORMAT_R11G11B10_FLOAT = 26, + DXGI_FORMAT_R8G8B8A8_TYPELESS = 27, + DXGI_FORMAT_R8G8B8A8_UNORM = 28, + DXGI_FORMAT_R8G8B8A8_UNORM_SRGB = 29, + DXGI_FORMAT_R8G8B8A8_UINT = 30, + DXGI_FORMAT_R8G8B8A8_SNORM = 31, + DXGI_FORMAT_R8G8B8A8_SINT = 32, + DXGI_FORMAT_R16G16_TYPELESS = 33, + DXGI_FORMAT_R16G16_FLOAT = 34, + DXGI_FORMAT_R16G16_UNORM = 35, + DXGI_FORMAT_R16G16_UINT = 36, + DXGI_FORMAT_R16G16_SNORM = 37, + DXGI_FORMAT_R16G16_SINT = 38, + DXGI_FORMAT_R32_TYPELESS = 39, + DXGI_FORMAT_D32_FLOAT = 40, + DXGI_FORMAT_R32_FLOAT = 41, + DXGI_FORMAT_R32_UINT = 42, + DXGI_FORMAT_R32_SINT = 43, + DXGI_FORMAT_R24G8_TYPELESS = 44, + DXGI_FORMAT_D24_UNORM_S8_UINT = 45, + DXGI_FORMAT_R24_UNORM_X8_TYPELESS = 46, + DXGI_FORMAT_X24_TYPELESS_G8_UINT = 47, + DXGI_FORMAT_R8G8_TYPELESS = 48, + DXGI_FORMAT_R8G8_UNORM = 49, + DXGI_FORMAT_R8G8_UINT = 50, + DXGI_FORMAT_R8G8_SNORM = 51, + DXGI_FORMAT_R8G8_SINT = 52, + DXGI_FORMAT_R16_TYPELESS = 53, + DXGI_FORMAT_R16_FLOAT = 54, + DXGI_FORMAT_D16_UNORM = 55, + DXGI_FORMAT_R16_UNORM = 56, + DXGI_FORMAT_R16_UINT = 57, + DXGI_FORMAT_R16_SNORM = 58, + DXGI_FORMAT_R16_SINT = 59, + DXGI_FORMAT_R8_TYPELESS = 60, + DXGI_FORMAT_R8_UNORM = 61, + DXGI_FORMAT_R8_UINT = 62, + DXGI_FORMAT_R8_SNORM = 63, + DXGI_FORMAT_R8_SINT = 64, + DXGI_FORMAT_A8_UNORM = 65, + DXGI_FORMAT_R1_UNORM = 66, + DXGI_FORMAT_R9G9B9E5_SHAREDEXP = 67, + DXGI_FORMAT_R8G8_B8G8_UNORM = 68, + DXGI_FORMAT_G8R8_G8B8_UNORM = 69, + DXGI_FORMAT_BC1_TYPELESS = 70, + DXGI_FORMAT_BC1_UNORM = 71, + DXGI_FORMAT_BC1_UNORM_SRGB = 72, + DXGI_FORMAT_BC2_TYPELESS = 73, + DXGI_FORMAT_BC2_UNORM = 74, + DXGI_FORMAT_BC2_UNORM_SRGB = 75, + DXGI_FORMAT_BC3_TYPELESS = 76, + DXGI_FORMAT_BC3_UNORM = 77, + DXGI_FORMAT_BC3_UNORM_SRGB = 78, + DXGI_FORMAT_BC4_TYPELESS = 79, + DXGI_FORMAT_BC4_UNORM = 80, + DXGI_FORMAT_BC4_SNORM = 81, + DXGI_FORMAT_BC5_TYPELESS = 82, + DXGI_FORMAT_BC5_UNORM = 83, + DXGI_FORMAT_BC5_SNORM = 84, + DXGI_FORMAT_B5G6R5_UNORM = 85, + DXGI_FORMAT_B5G5R5A1_UNORM = 86, + DXGI_FORMAT_B8G8R8A8_UNORM = 87, + DXGI_FORMAT_B8G8R8X8_UNORM = 88, + DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM = 89, + DXGI_FORMAT_B8G8R8A8_TYPELESS = 90, + DXGI_FORMAT_B8G8R8A8_UNORM_SRGB = 91, + DXGI_FORMAT_B8G8R8X8_TYPELESS = 92, + DXGI_FORMAT_B8G8R8X8_UNORM_SRGB = 93, + DXGI_FORMAT_BC6H_TYPELESS = 94, + DXGI_FORMAT_BC6H_UF16 = 95, + DXGI_FORMAT_BC6H_SF16 = 96, + DXGI_FORMAT_BC7_TYPELESS = 97, + DXGI_FORMAT_BC7_UNORM = 98, + DXGI_FORMAT_BC7_UNORM_SRGB = 99, + DXGI_FORMAT_AYUV = 100, + DXGI_FORMAT_Y410 = 101, + DXGI_FORMAT_Y416 = 102, + DXGI_FORMAT_NV12 = 103, + DXGI_FORMAT_P010 = 104, + DXGI_FORMAT_P016 = 105, + DXGI_FORMAT_420_OPAQUE = 106, + DXGI_FORMAT_YUY2 = 107, + DXGI_FORMAT_Y210 = 108, + DXGI_FORMAT_Y216 = 109, + DXGI_FORMAT_NV11 = 110, + DXGI_FORMAT_AI44 = 111, + DXGI_FORMAT_IA44 = 112, + DXGI_FORMAT_P8 = 113, + DXGI_FORMAT_A8P8 = 114, + DXGI_FORMAT_B4G4R4A4_UNORM = 115, + DXGI_FORMAT_P208 = 130, + DXGI_FORMAT_V208 = 131, + DXGI_FORMAT_V408 = 132, +}; + +template <int a, int b, int c, int d> +struct DdsFourCC +{ + static const quint32 value = a | (b << 8) | (c << 16) | (d << 24); +}; + +struct FormatInfo { + QOpenGLTexture::PixelFormat pixelFormat; + QOpenGLTexture::TextureFormat textureFormat; + QOpenGLTexture::PixelType pixelType; + int components; + bool compressed; +}; + +const struct RGBAFormat { + quint32 redMask; + quint32 greenMask; + quint32 blueMask; + quint32 alphaMask; + FormatInfo formatInfo; +} rgbaFormats[] = { + // unorm formats + { 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000, { QOpenGLTexture::RGBA, QOpenGLTexture::RGBA8_UNorm, QOpenGLTexture::UInt8, 4, false } }, + { 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000, { QOpenGLTexture::BGRA, QOpenGLTexture::RGBA8_UNorm, QOpenGLTexture::UInt8, 4, false } }, + { 0x000000ff, 0x0000ff00, 0x00ff0000, 0x00000000, { QOpenGLTexture::RGBA, QOpenGLTexture::RGBA8_UNorm, QOpenGLTexture::UInt8, 4, false } }, + { 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000, { QOpenGLTexture::BGRA, QOpenGLTexture::RGBA8_UNorm, QOpenGLTexture::UInt8, 4, false } }, + { 0x000000ff, 0x0000ff00, 0x00ff0000, 0x00000000, { QOpenGLTexture::RGB, QOpenGLTexture::RGB8_UNorm, QOpenGLTexture::UInt8, 3, false } }, + { 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000, { QOpenGLTexture::BGR, QOpenGLTexture::RGB8_UNorm, QOpenGLTexture::UInt8, 3, false } }, + + // packed formats + { 0x0000f800, 0x000007e0, 0x0000001f, 0x00000000, { QOpenGLTexture::RGB, QOpenGLTexture::R5G6B5, QOpenGLTexture::UInt16_R5G6B5, 2, false } }, + { 0x00007c00, 0x000003e0, 0x0000001f, 0x00008000, { QOpenGLTexture::RGBA, QOpenGLTexture::RGB5A1, QOpenGLTexture::UInt16_RGB5A1, 2, false } }, + { 0x00000f00, 0x000000f0, 0x0000000f, 0x0000f000, { QOpenGLTexture::RGBA, QOpenGLTexture::RGBA4, QOpenGLTexture::UInt16_RGBA4, 2, false } }, + { 0x000000e0, 0x0000001c, 0x00000003, 0x00000000, { QOpenGLTexture::RGB, QOpenGLTexture::RG3B2, QOpenGLTexture::UInt8_RG3B2, 1, false } }, + { 0x3ff00000, 0x000ffc00, 0x000003ff, 0xc0000000, { QOpenGLTexture::RGBA, QOpenGLTexture::RGB10A2, QOpenGLTexture::UInt32_RGB10A2, 4, false } }, + + // luminance alpha + { 0x000000ff, 0x000000ff, 0x000000ff, 0x00000000, { QOpenGLTexture::Red, QOpenGLTexture::R8_UNorm, QOpenGLTexture::UInt8, 1, false } }, + { 0x000000ff, 0x00000000, 0x00000000, 0x00000000, { QOpenGLTexture::Red, QOpenGLTexture::R8_UNorm, QOpenGLTexture::UInt8, 1, false } }, + { 0x000000ff, 0x000000ff, 0x000000ff, 0x0000ff00, { QOpenGLTexture::RG, QOpenGLTexture::RG8_UNorm, QOpenGLTexture::UInt8, 2, false } }, + { 0x000000ff, 0x00000000, 0x00000000, 0x0000ff00, { QOpenGLTexture::RG, QOpenGLTexture::RG8_UNorm, QOpenGLTexture::UInt8, 2, false } }, +}; + +const struct FourCCFormat { + quint32 fourCC; + FormatInfo formatInfo; +} fourCCFormats[] = { + { DdsFourCC<'D','X','T','1'>::value, { QOpenGLTexture::NoSourceFormat, QOpenGLTexture::RGBA_DXT1, QOpenGLTexture::NoPixelType, 8, true } }, + { DdsFourCC<'D','X','T','3'>::value, { QOpenGLTexture::NoSourceFormat, QOpenGLTexture::RGBA_DXT3, QOpenGLTexture::NoPixelType, 16, true } }, + { DdsFourCC<'D','X','T','5'>::value, { QOpenGLTexture::NoSourceFormat, QOpenGLTexture::RGBA_DXT5, QOpenGLTexture::NoPixelType, 16, true } }, + { DdsFourCC<'A','T','I','1'>::value, { QOpenGLTexture::NoSourceFormat, QOpenGLTexture::R_ATI1N_UNorm, QOpenGLTexture::NoPixelType, 8, true } }, + { DdsFourCC<'A','T','I','2'>::value, { QOpenGLTexture::NoSourceFormat, QOpenGLTexture::RG_ATI2N_UNorm, QOpenGLTexture::NoPixelType, 16, true } }, +}; + +const struct DX10Format { + DXGIFormat dxgiFormat; + FormatInfo formatInfo; +} dx10Formats[] = { + // unorm formats + { DXGI_FORMAT_R8_UNORM, { QOpenGLTexture::Red, QOpenGLTexture::R8_UNorm, QOpenGLTexture::UInt8, 1, false } }, + { DXGI_FORMAT_R8G8_UNORM, { QOpenGLTexture::RG, QOpenGLTexture::RG8_UNorm, QOpenGLTexture::UInt8, 2, false } }, + { DXGI_FORMAT_R8G8B8A8_UNORM, { QOpenGLTexture::RGBA, QOpenGLTexture::RGBA8_UNorm, QOpenGLTexture::UInt8, 4, false } }, + + { DXGI_FORMAT_R16_UNORM, { QOpenGLTexture::Red, QOpenGLTexture::R16_UNorm, QOpenGLTexture::UInt16, 2, false } }, + { DXGI_FORMAT_R16G16_UNORM, { QOpenGLTexture::RG, QOpenGLTexture::RG16_UNorm, QOpenGLTexture::UInt16, 4, false } }, + { DXGI_FORMAT_R16G16B16A16_UNORM, { QOpenGLTexture::RGBA, QOpenGLTexture::RGBA16_UNorm, QOpenGLTexture::UInt16, 8, false } }, + + // snorm formats + { DXGI_FORMAT_R8_SNORM, { QOpenGLTexture::Red, QOpenGLTexture::R8_SNorm, QOpenGLTexture::Int8, 1, false } }, + { DXGI_FORMAT_R8G8_SNORM, { QOpenGLTexture::RG, QOpenGLTexture::RG8_SNorm, QOpenGLTexture::Int8, 2, false } }, + { DXGI_FORMAT_R8G8B8A8_SNORM, { QOpenGLTexture::RGBA, QOpenGLTexture::RGBA8_SNorm, QOpenGLTexture::Int8, 4, false } }, + + { DXGI_FORMAT_R16_SNORM, { QOpenGLTexture::Red, QOpenGLTexture::R16_SNorm, QOpenGLTexture::Int16, 2, false } }, + { DXGI_FORMAT_R16G16_SNORM, { QOpenGLTexture::RG, QOpenGLTexture::RG16_SNorm, QOpenGLTexture::Int16, 4, false } }, + { DXGI_FORMAT_R16G16B16A16_SNORM, { QOpenGLTexture::RGBA, QOpenGLTexture::RGBA16_SNorm, QOpenGLTexture::Int16, 8, false } }, + + // unsigned integer formats + { DXGI_FORMAT_R8_UINT, { QOpenGLTexture::Red_Integer, QOpenGLTexture::R8U, QOpenGLTexture::UInt8, 1, false } }, + { DXGI_FORMAT_R8G8_UINT, { QOpenGLTexture::RG_Integer, QOpenGLTexture::RG8U, QOpenGLTexture::UInt8, 2, false } }, + { DXGI_FORMAT_R8G8B8A8_UINT, { QOpenGLTexture::RGBA_Integer, QOpenGLTexture::RGBA8U, QOpenGLTexture::UInt8, 4, false } }, + + { DXGI_FORMAT_R16_UINT, { QOpenGLTexture::Red_Integer, QOpenGLTexture::R16U, QOpenGLTexture::UInt16, 2, false } }, + { DXGI_FORMAT_R16G16_UINT, { QOpenGLTexture::RG_Integer, QOpenGLTexture::RG16U, QOpenGLTexture::UInt16, 4, false } }, + { DXGI_FORMAT_R16G16B16A16_UINT, { QOpenGLTexture::RGBA_Integer, QOpenGLTexture::RGBA16U, QOpenGLTexture::UInt16, 8, false } }, + + { DXGI_FORMAT_R32_UINT, { QOpenGLTexture::Red_Integer, QOpenGLTexture::R32U, QOpenGLTexture::UInt32, 4, false } }, + { DXGI_FORMAT_R32G32_UINT, { QOpenGLTexture::RG_Integer, QOpenGLTexture::RG32U, QOpenGLTexture::UInt32, 8, false } }, + { DXGI_FORMAT_R32G32B32_UINT, { QOpenGLTexture::RGB_Integer, QOpenGLTexture::RGB32U, QOpenGLTexture::UInt32, 12, false } }, + { DXGI_FORMAT_R32G32B32A32_UINT, { QOpenGLTexture::RGBA_Integer, QOpenGLTexture::RGBA32U, QOpenGLTexture::UInt32, 16, false } }, + + // signed integer formats + { DXGI_FORMAT_R8_SINT, { QOpenGLTexture::Red_Integer, QOpenGLTexture::R8I, QOpenGLTexture::Int8, 1, false } }, + { DXGI_FORMAT_R8G8_SINT, { QOpenGLTexture::RG_Integer, QOpenGLTexture::RG8I, QOpenGLTexture::Int8, 2, false } }, + { DXGI_FORMAT_R8G8B8A8_SINT, { QOpenGLTexture::RGBA_Integer, QOpenGLTexture::RGBA8I, QOpenGLTexture::Int8, 4, false } }, + + { DXGI_FORMAT_R16_SINT, { QOpenGLTexture::Red_Integer, QOpenGLTexture::R16I, QOpenGLTexture::Int16, 2, false } }, + { DXGI_FORMAT_R16G16_SINT, { QOpenGLTexture::RG_Integer, QOpenGLTexture::RG16I, QOpenGLTexture::Int16, 4, false } }, + { DXGI_FORMAT_R16G16B16A16_SINT, { QOpenGLTexture::RGBA_Integer, QOpenGLTexture::RGBA16I, QOpenGLTexture::Int16, 8, false } }, + + { DXGI_FORMAT_R32_SINT, { QOpenGLTexture::Red_Integer, QOpenGLTexture::R32I, QOpenGLTexture::Int32, 4, false } }, + { DXGI_FORMAT_R32G32_SINT, { QOpenGLTexture::RG_Integer, QOpenGLTexture::RG32I, QOpenGLTexture::Int32, 8, false } }, + { DXGI_FORMAT_R32G32B32_SINT, { QOpenGLTexture::RGB_Integer, QOpenGLTexture::RGB32I, QOpenGLTexture::Int32, 12, false } }, + { DXGI_FORMAT_R32G32B32A32_SINT, { QOpenGLTexture::RGBA_Integer, QOpenGLTexture::RGBA32I, QOpenGLTexture::Int32, 16, false } }, + + // floating formats + { DXGI_FORMAT_R16_FLOAT, { QOpenGLTexture::Red, QOpenGLTexture::R16F, QOpenGLTexture::Float16, 2, false } }, + { DXGI_FORMAT_R16G16_FLOAT, { QOpenGLTexture::RG, QOpenGLTexture::RG16F, QOpenGLTexture::Float16, 4, false } }, + { DXGI_FORMAT_R16G16B16A16_FLOAT, { QOpenGLTexture::RGBA, QOpenGLTexture::RGBA16F, QOpenGLTexture::Float16, 8, false } }, + + { DXGI_FORMAT_R32_FLOAT, { QOpenGLTexture::Red, QOpenGLTexture::R32F, QOpenGLTexture::Float32, 4, false } }, + { DXGI_FORMAT_R32G32_FLOAT, { QOpenGLTexture::RG, QOpenGLTexture::RG32F, QOpenGLTexture::Float32, 8, false } }, + { DXGI_FORMAT_R32G32B32_FLOAT, { QOpenGLTexture::RGB, QOpenGLTexture::RGB32F, QOpenGLTexture::Float32, 12, false } }, + { DXGI_FORMAT_R32G32B32A32_FLOAT, { QOpenGLTexture::RGBA, QOpenGLTexture::RGBA32F, QOpenGLTexture::Float32, 16, false } }, + + // sRGB formats + { DXGI_FORMAT_B8G8R8X8_UNORM_SRGB, { QOpenGLTexture::RGB, QOpenGLTexture::SRGB8, QOpenGLTexture::UInt8, 4, false } }, + { DXGI_FORMAT_R8G8B8A8_UNORM_SRGB, { QOpenGLTexture::RGBA, QOpenGLTexture::SRGB8_Alpha8, QOpenGLTexture::UInt8, 4, false } }, + + // packed formats + // { DXGI_FORMAT_R10G10B10A2_UNORM, { QOpenGLTexture::RGB10A2_UNORM, QOpenGLTexture::RGBA, QOpenGLTexture::UInt32_RGB10A2, 4, false } }, + { DXGI_FORMAT_R10G10B10A2_UINT, { QOpenGLTexture::RGBA_Integer, QOpenGLTexture::RGB10A2, QOpenGLTexture::UInt32_RGB10A2, 4, false } }, + { DXGI_FORMAT_R9G9B9E5_SHAREDEXP, { QOpenGLTexture::RGB, QOpenGLTexture::RGB9E5, QOpenGLTexture::UInt32_RGB9_E5, 4, false } }, + { DXGI_FORMAT_R11G11B10_FLOAT, { QOpenGLTexture::RGB, QOpenGLTexture::RG11B10F, QOpenGLTexture::UInt32_RG11B10F, 4, false } }, + { DXGI_FORMAT_B5G6R5_UNORM, { QOpenGLTexture::RGB, QOpenGLTexture::R5G6B5, QOpenGLTexture::UInt16_R5G6B5, 2, false } }, + { DXGI_FORMAT_B5G5R5A1_UNORM, { QOpenGLTexture::RGBA, QOpenGLTexture::RGB5A1, QOpenGLTexture::UInt16_RGB5A1, 2, false } }, + { DXGI_FORMAT_B4G4R4A4_UNORM, { QOpenGLTexture::RGBA, QOpenGLTexture::RGBA4, QOpenGLTexture::UInt16_RGBA4, 2, false } }, + + // swizzle formats + { DXGI_FORMAT_B8G8R8X8_UNORM, { QOpenGLTexture::BGRA, QOpenGLTexture::RGB8_UNorm, QOpenGLTexture::UInt8, 4, false } }, + { DXGI_FORMAT_B8G8R8A8_UNORM, { QOpenGLTexture::BGRA, QOpenGLTexture::RGBA8_UNorm, QOpenGLTexture::UInt8, 4, false } }, + { DXGI_FORMAT_B8G8R8X8_UNORM_SRGB, { QOpenGLTexture::BGRA, QOpenGLTexture::SRGB8, QOpenGLTexture::UInt8, 4, false } }, + { DXGI_FORMAT_B8G8R8A8_UNORM_SRGB, { QOpenGLTexture::BGRA, QOpenGLTexture::SRGB8_Alpha8, QOpenGLTexture::UInt8, 4, false } }, + + // luminance alpha formats + { DXGI_FORMAT_R8_UNORM, { QOpenGLTexture::Red, QOpenGLTexture::R8_UNorm, QOpenGLTexture::UInt8, 1, false } }, + { DXGI_FORMAT_R8G8_UNORM, { QOpenGLTexture::RG, QOpenGLTexture::RG8_UNorm, QOpenGLTexture::UInt8, 2, false } }, + { DXGI_FORMAT_R16_UNORM, { QOpenGLTexture::Red, QOpenGLTexture::R16_UNorm, QOpenGLTexture::UInt16, 2, false } }, + { DXGI_FORMAT_R16_UNORM, { QOpenGLTexture::RG, QOpenGLTexture::RG16_UNorm, QOpenGLTexture::UInt16, 4, false } }, + + // depth formats + { DXGI_FORMAT_D16_UNORM, { QOpenGLTexture::Depth, QOpenGLTexture::D16, QOpenGLTexture::NoPixelType, 2, false } }, + { DXGI_FORMAT_D24_UNORM_S8_UINT, { QOpenGLTexture::DepthStencil, QOpenGLTexture::D24S8, QOpenGLTexture::NoPixelType, 4, false } }, + { DXGI_FORMAT_D32_FLOAT, { QOpenGLTexture::Depth, QOpenGLTexture::D32F, QOpenGLTexture::NoPixelType, 4, false } }, + { DXGI_FORMAT_D32_FLOAT_S8X24_UINT, { QOpenGLTexture::DepthStencil, QOpenGLTexture::D32FS8X24, QOpenGLTexture::NoPixelType, 8, false } }, + + // compressed formats + { DXGI_FORMAT_BC1_UNORM, { QOpenGLTexture::NoSourceFormat, QOpenGLTexture::RGBA_DXT1, QOpenGLTexture::NoPixelType, 8, true } }, + { DXGI_FORMAT_BC2_UNORM, { QOpenGLTexture::NoSourceFormat, QOpenGLTexture::RGBA_DXT3, QOpenGLTexture::NoPixelType, 16, true } }, + { DXGI_FORMAT_BC3_UNORM, { QOpenGLTexture::NoSourceFormat, QOpenGLTexture::RGBA_DXT5, QOpenGLTexture::NoPixelType, 16, true } }, + { DXGI_FORMAT_BC4_UNORM, { QOpenGLTexture::NoSourceFormat, QOpenGLTexture::R_ATI1N_UNorm, QOpenGLTexture::NoPixelType, 8, true } }, + { DXGI_FORMAT_BC4_SNORM, { QOpenGLTexture::NoSourceFormat, QOpenGLTexture::R_ATI1N_SNorm, QOpenGLTexture::NoPixelType, 8, true } }, + { DXGI_FORMAT_BC5_UNORM, { QOpenGLTexture::NoSourceFormat, QOpenGLTexture::RG_ATI2N_UNorm, QOpenGLTexture::NoPixelType, 16, true } }, + { DXGI_FORMAT_BC5_SNORM, { QOpenGLTexture::NoSourceFormat, QOpenGLTexture::RG_ATI2N_SNorm, QOpenGLTexture::NoPixelType, 16, true } }, + { DXGI_FORMAT_BC6H_UF16, { QOpenGLTexture::NoSourceFormat, QOpenGLTexture::RGB_BP_UNSIGNED_FLOAT, QOpenGLTexture::NoPixelType, 16, true } }, + { DXGI_FORMAT_BC6H_SF16, { QOpenGLTexture::NoSourceFormat, QOpenGLTexture::RGB_BP_SIGNED_FLOAT, QOpenGLTexture::NoPixelType, 16, true } }, + { DXGI_FORMAT_BC7_UNORM, { QOpenGLTexture::NoSourceFormat, QOpenGLTexture::RGB_BP_UNorm, QOpenGLTexture::NoPixelType, 16, true } }, + + // compressed sRGB formats + { DXGI_FORMAT_BC1_UNORM_SRGB, { QOpenGLTexture::NoSourceFormat, QOpenGLTexture::SRGB_DXT1, QOpenGLTexture::NoPixelType, 8, true } }, + { DXGI_FORMAT_BC1_UNORM_SRGB, { QOpenGLTexture::NoSourceFormat, QOpenGLTexture::SRGB_Alpha_DXT1, QOpenGLTexture::NoPixelType, 8, true } }, + { DXGI_FORMAT_BC2_UNORM_SRGB, { QOpenGLTexture::NoSourceFormat, QOpenGLTexture::SRGB_Alpha_DXT3, QOpenGLTexture::NoPixelType, 16, true } }, + { DXGI_FORMAT_BC3_UNORM_SRGB, { QOpenGLTexture::NoSourceFormat, QOpenGLTexture::SRGB_Alpha_DXT5, QOpenGLTexture::NoPixelType, 16, true } }, + { DXGI_FORMAT_BC7_UNORM_SRGB, { QOpenGLTexture::NoSourceFormat, QOpenGLTexture::SRGB_BP_UNorm, QOpenGLTexture::NoPixelType, 16, true } }, +}; + +} // namespace + QTexImageDataPrivate::QTexImageDataPrivate() : m_width(-1) , m_height(-1) , m_depth(-1) - , m_isCompressed(false) + , m_layers(-1) + , m_faces(-1) + , m_mipLevels(-1) + , m_blockSize(-1) + , m_target(QOpenGLTexture::Target2D) , m_format(QOpenGLTexture::RGBA8_UNorm) + , m_pixelFormat(QOpenGLTexture::RGBA) + , m_pixelType(QOpenGLTexture::UInt8) + , m_isCompressed(false) +{ +} + +QByteArray QTexImageDataPrivate::data(int layer, int face, int mipmapLevel) const +{ + if (layer < 0 || layer >= m_layers || + face < 0 || face >= m_faces || + mipmapLevel < 0 || mipmapLevel >= m_mipLevels) + return QByteArray(); + + int offset = layer*layerSize() + face*faceSize(); + + for (int i = 0; i < mipmapLevel; i++) + offset += mipmapLevelSize(i); + + return QByteArray::fromRawData(m_data.constData() + offset, mipmapLevelSize(mipmapLevel)); +} + +void QTexImageDataPrivate::setData(const QByteArray &data, QOpenGLTexture::PixelFormat fmt, + QOpenGLTexture::PixelType ptype) +{ + m_isCompressed = false; + m_data = data; + m_layers = 1; + m_faces = 1; + m_mipLevels = 1; + m_target = QOpenGLTexture::Target2D; + m_pixelFormat = fmt; + m_pixelType = ptype; +} + +bool QTexImageDataPrivate::setCompressedFile(const QString &source) +{ + QString suffix = QFileInfo(source).suffix(); + + if (suffix == QStringLiteral("pkm")) + return setPkmFile(source); + else if (suffix == QStringLiteral("dds")) + return setDdsFile(source); + else + return false; +} + +bool QTexImageDataPrivate::setPkmFile(const QString &source) +{ + QFile f(source); + if (!f.open(QIODevice::ReadOnly)) { + qWarning() << "Failed to open" << source; + return false; + } + + // ETC1 in PKM, as generated by f.ex. Android's etc1tool + static const char pkmMagic[] = { 'P', 'K', 'M', ' ', '1', '0' }; + const int pkmHeaderSize = 6 + 2 + 4 * 2; + QByteArray header = f.read(pkmHeaderSize); + if (header.size() >= pkmHeaderSize && !qstrncmp(header.constData(), pkmMagic, 6)) { + m_format = QOpenGLTexture::RGB8_ETC1; // may get changed to RGB8_ETC2 later on + // get the extended (multiple of 4) width and height + m_width = qFromBigEndian(*(reinterpret_cast<const quint16 *>(header.constData() + 6 + 2))); + m_height = qFromBigEndian(*(reinterpret_cast<const quint16 *>(header.constData() + 6 + 2 + 2))); + m_depth = 1; + QByteArray data = f.readAll(); + if (data.size() < (m_width / 4) * (m_height / 4) * 8) + qWarning() << "Unexpected end of ETC1 data in" << source; + setData(data, QOpenGLTexture::RGBA, QOpenGLTexture::UInt8); + m_blockSize = 8; + m_isCompressed = true; + return true; + } + + return false; +} + +static int bitCount(quint32 n) +{ + int r = 0; + + for (; n; n >>= 1) + r += (n & 1); + + return r; +} + +bool QTexImageDataPrivate::setDdsFile(const QString &source) +{ + QFile f(source); + if (!f.open(QIODevice::ReadOnly)) { + qWarning() << "Failed to open" << source; + return false; + } + + DdsHeader header; + if (f.read(reinterpret_cast<char *>(&header), sizeof header) != sizeof header) + return false; + + if (qstrncmp(header.magic, "DDS ", 4) != 0) + return false; + + // dimensions + + m_width = qFromLittleEndian(header.width); + m_height = qFromLittleEndian(header.height); + + // mip levels + + if ((qFromLittleEndian(header.flags) & MipmapCountFlag) == MipmapCountFlag) + m_mipLevels = qFromLittleEndian(header.mipmapCount); + else + m_mipLevels = 1; + + // texture format + + m_layers = 1; + + const quint32 pixelFlags = qFromLittleEndian(header.pixelFormat.flags); + const quint32 fourCC = qFromLittleEndian(header.pixelFormat.fourCC); + + const FormatInfo *formatInfo = Q_NULLPTR; + + if ((pixelFlags & FourCCFlag) == FourCCFlag) { + if (fourCC == DdsFourCC<'D', 'X', '1', '0'>::value) { + // DX10 texture + + DdsDX10Header dx10Header; + if (f.read(reinterpret_cast<char *>(&dx10Header), sizeof dx10Header) != sizeof dx10Header) + return false; + + m_layers = qFromLittleEndian(dx10Header.arraySize); + + DXGIFormat format = static_cast<DXGIFormat>(qFromLittleEndian(dx10Header.format)); + + for (unsigned i = 0; i < sizeof dx10Formats/sizeof *dx10Formats; i++) { + if (dx10Formats[i].dxgiFormat == format) { + formatInfo = &dx10Formats[i].formatInfo; + break; + } + } + } else { + // compressed, FourCC texture + + for (unsigned i = 0; i < sizeof fourCCFormats/sizeof *fourCCFormats; i++) { + if (fourCCFormats[i].fourCC == fourCC) { + formatInfo = &fourCCFormats[i].formatInfo; + break; + } + } + } + } else { + // uncompressed texture + + m_pixelFormat = QOpenGLTexture::NoSourceFormat; + + const quint32 rgbBitCount = qFromLittleEndian(header.pixelFormat.rgbBitCount); + const quint32 redMask = qFromLittleEndian(header.pixelFormat.redMask); + const quint32 greenMask = qFromLittleEndian(header.pixelFormat.greenMask); + const quint32 blueMask = qFromLittleEndian(header.pixelFormat.blueMask); + const quint32 alphaMask = qFromLittleEndian(header.pixelFormat.alphaMask); + + for (unsigned i = 0; i < sizeof rgbaFormats/sizeof *rgbaFormats; i++) { + const RGBAFormat *info = &rgbaFormats[i]; + + if (info->formatInfo.components*8u == rgbBitCount && + info->redMask == redMask && info->greenMask == greenMask && + info->blueMask == blueMask && info->alphaMask == alphaMask) { + formatInfo = &info->formatInfo; + break; + } + } + } + + if (formatInfo == Q_NULLPTR) { + qWarning() << "Unrecognized pixel format in" << source; + return false; + } + + m_pixelFormat = formatInfo->pixelFormat; + m_format = formatInfo->textureFormat; + m_pixelType = formatInfo->pixelType; + m_blockSize = formatInfo->components; + m_isCompressed = formatInfo->compressed; + + // target + + // XXX should worry about Target1D? + + const quint32 caps2Flags = qFromLittleEndian(header.caps2); + + if ((caps2Flags & VolumeFlag) == VolumeFlag) { + m_target = QOpenGLTexture::Target3D; + m_depth = qFromLittleEndian(header.depth); + m_faces = 1; + } else if ((caps2Flags & CubemapFlag) == CubemapFlag) { + m_target = m_layers > 1 ? QOpenGLTexture::TargetCubeMapArray : QOpenGLTexture::TargetCubeMap; + m_depth = 1; + m_faces = bitCount(caps2Flags & AllCubemapFaceFlags); + } else { + m_target = m_layers > 1 ? QOpenGLTexture::Target2DArray : QOpenGLTexture::Target2D; + m_depth = 1; + m_faces = 1; + } + + // data + + m_data = f.readAll(); + + if (m_data.size() != m_layers*layerSize()) { + qWarning() << "Unexpected data size (got " << m_data.size() << ", expecting" << m_layers*layerSize() << ")"; + return false; + } + + return true; +} + +int QTexImageDataPrivate::layerSize() const { + return m_faces*faceSize(); +} + +int QTexImageDataPrivate::faceSize() const +{ + int size = 0; + + for (int i = 0; i < m_mipLevels; i++) + size += mipmapLevelSize(i); + + return size; +} + +// XXX check if this works for ETC1 compression +int QTexImageDataPrivate::mipmapLevelSize(int level) const +{ + int w = qMax(m_width >> level, 1); + int h = qMax(m_height >> level, 1); + int d = qMax(m_depth >> level, 1); + + if (m_isCompressed) + return ((w + 3) / 4) * ((h + 3) / 4) * m_blockSize * d; + else + return w * h * m_blockSize * d; } QTexImageData::QTexImageData() @@ -73,14 +676,7 @@ QTexImageData::~QTexImageData() QTexImageData &QTexImageData::operator=(const QTexImageData &other) { Q_D(QTexImageData); - d->m_width = other.d_ptr->m_width; - d->m_height = other.d_ptr->m_height; - d->m_depth = other.d_ptr->m_depth; - d->m_isCompressed = other.d_ptr->m_isCompressed; - d->m_pixelFormat = other.d_ptr->m_pixelFormat; - d->m_pixelType = other.d_ptr->m_pixelType; - d->m_data = other.d_ptr->m_data; - + *d = *other.d_ptr; return *this; } @@ -90,6 +686,10 @@ void QTexImageData::cleanup() d->m_width = -1; d->m_height = -1; d->m_depth = -1; + d->m_layers = -1; + d->m_faces = -1; + d->m_mipLevels = -1; + d->m_blockSize = 0; d->m_isCompressed = false; d->m_data.clear(); } @@ -118,6 +718,30 @@ int QTexImageData::depth() const return d->m_depth; } +int QTexImageData::layers() const +{ + Q_D(const QTexImageData); + return d->m_layers; +} + +int QTexImageData::mipLevels() const +{ + Q_D(const QTexImageData); + return d->m_mipLevels; +} + +int QTexImageData::faces() const +{ + Q_D(const QTexImageData); + return d->m_faces;; +} + +QOpenGLTexture::Target QTexImageData::target() const +{ + Q_D(const QTexImageData); + return d->m_target; +} + QOpenGLTexture::TextureFormat QTexImageData::format() const { Q_D(const QTexImageData); @@ -137,56 +761,26 @@ void QTexImageData::setImage(const QImage &image) QByteArray imageBytes((const char*) glImage.constBits(), glImage.byteCount()); setData(imageBytes, QOpenGLTexture::RGBA, QOpenGLTexture::UInt8); d->m_format = QOpenGLTexture::RGBA8_UNorm; + d->m_blockSize = 4; } void QTexImageData::setData(const QByteArray &data, QOpenGLTexture::PixelFormat fmt, QOpenGLTexture::PixelType ptype) { Q_D(QTexImageData); - d->m_isCompressed = false; - d->m_data = data; - d->m_pixelFormat = fmt; - d->m_pixelType = ptype; + d->setData(data, fmt, ptype); } bool QTexImageData::setCompressedFile(const QString &source) { Q_D(QTexImageData); - const bool isPkm = QFileInfo(source).suffix() == QStringLiteral("pkm"); - if (!isPkm) - return false; - - QFile f(source); - if (!f.open(QIODevice::ReadOnly)) { - qWarning() << "Failed to open" << source; - return false; - } - - // ETC1 in PKM, as generated by f.ex. Android's etc1tool - static const char pkmMagic[] = { 'P', 'K', 'M', ' ', '1', '0' }; - const int pkmHeaderSize = 6 + 2 + 4 * 2; - QByteArray header = f.read(pkmHeaderSize); - if (header.size() >= pkmHeaderSize && !qstrncmp(header.constData(), pkmMagic, 6)) { - d->m_format = QOpenGLTexture::RGB8_ETC1; // may get changed to RGB8_ETC2 later on - // get the extended (multiple of 4) width and height - d->m_width = qFromBigEndian(*(reinterpret_cast<const quint16 *>(header.constData() + 6 + 2))); - d->m_height = qFromBigEndian(*(reinterpret_cast<const quint16 *>(header.constData() + 6 + 2 + 2))); - d->m_depth = 1; - QByteArray data = f.readAll(); - if (data.size() < (d->m_width / 4) * (d->m_height / 4) * 8) - qWarning() << "Unexpected end of ETC1 data in" << source; - setData(data, QOpenGLTexture::RGBA, QOpenGLTexture::UInt8); - d->m_isCompressed = true; - return true; - } - - return false; + return d->setCompressedFile(source); } -QByteArray QTexImageData::data() const +QByteArray QTexImageData::data(int layer, int face, int mipmapLevel) const { Q_D(const QTexImageData); - return d->m_data; + return d->data(layer, face, mipmapLevel); } QOpenGLTexture::PixelFormat QTexImageData::pixelFormat() const diff --git a/src/render/texture/qtexturedata.h b/src/render/texture/qtexturedata.h index f87109743..d01a59ab0 100644 --- a/src/render/texture/qtexturedata.h +++ b/src/render/texture/qtexturedata.h @@ -63,6 +63,13 @@ public: int width() const; int height() const; int depth() const; + + int layers() const; + int mipLevels() const; + int faces() const; + + QOpenGLTexture::Target target() const; + QOpenGLTexture::TextureFormat format() const; void setImage(const QImage &); @@ -73,7 +80,7 @@ public: bool setCompressedFile(const QString &source); - QByteArray data() const; + QByteArray data(int layer = 0, int face = 0, int mipmapLevel = 0) const; QOpenGLTexture::PixelFormat pixelFormat() const; diff --git a/src/render/texture/qtexturedata_p.h b/src/render/texture/qtexturedata_p.h index 6bad6f036..3ad7486d5 100644 --- a/src/render/texture/qtexturedata_p.h +++ b/src/render/texture/qtexturedata_p.h @@ -59,15 +59,36 @@ class QTexImageDataPrivate public: QTexImageDataPrivate(); + void setData(const QByteArray &data, QOpenGLTexture::PixelFormat fmt, + QOpenGLTexture::PixelType ptype); + + bool setCompressedFile(const QString &source); + + QByteArray data(int layer, int face, int mipmapLevel) const; + int m_width; int m_height; int m_depth; + int m_layers; + int m_faces; + int m_mipLevels; + int m_blockSize; + + QOpenGLTexture::Target m_target; + QOpenGLTexture::TextureFormat m_format; QOpenGLTexture::PixelFormat m_pixelFormat; QOpenGLTexture::PixelType m_pixelType; bool m_isCompressed; QByteArray m_data; - QOpenGLTexture::TextureFormat m_format; + +private: + int layerSize() const; + int faceSize() const; + int mipmapLevelSize(int level) const; + + bool setPkmFile(const QString &source); + bool setDdsFile(const QString &source); }; } // namespace Qt3DRender diff --git a/src/render/texture/qtextureimage.cpp b/src/render/texture/qtextureimage.cpp index 6b4684742..5720143b4 100644 --- a/src/render/texture/qtextureimage.cpp +++ b/src/render/texture/qtextureimage.cpp @@ -35,14 +35,14 @@ ****************************************************************************/ #include "qtextureimage.h" +#include "qtextureimage_p.h" #include "qabstracttextureimage_p.h" -#include <Qt3DRender/private/qurlhelper_p.h> QT_BEGIN_NAMESPACE namespace Qt3DRender { -class QTextureImagePrivate: public QAbstractTextureImagePrivate +class QTextureImagePrivate : public QAbstractTextureImagePrivate { public: QTextureImagePrivate() @@ -54,52 +54,6 @@ public: QUrl m_source; }; -class QImageTextureDataFunctor : public QTextureDataFunctor -{ -public: - QImageTextureDataFunctor(const QUrl &url) - : QTextureDataFunctor() - , m_url(url) - {} - - // Will be executed from within a QAspectJob - QTexImageDataPtr operator ()() Q_DECL_FINAL - { - QTexImageDataPtr dataPtr; - if (m_url.isLocalFile() || m_url.scheme() == QStringLiteral("qrc") -#ifdef Q_OS_ANDROID - || m_url.scheme() == QStringLiteral("assets") -#endif - ) { - QString source = Qt3DRender::QUrlHelper::urlToLocalFileOrQrc(m_url); - dataPtr.reset(new QTexImageData()); - if (dataPtr->setCompressedFile(source)) - return dataPtr; - QImage img; - if (img.load(source)) { - dataPtr->setImage(img); - return dataPtr; - } - dataPtr.reset(); - qWarning() << "Failed to load image : " << source; - } else { - qWarning() << "implement loading from remote URLs"; - } - return dataPtr; - } - - bool operator ==(const QTextureDataFunctor &other) const Q_DECL_FINAL - { - const QImageTextureDataFunctor *otherFunctor = functor_cast<QImageTextureDataFunctor>(&other); - return (otherFunctor != Q_NULLPTR && otherFunctor->m_url == m_url); - } - - QT3D_FUNCTOR(QImageTextureDataFunctor) - -private: - QUrl m_url; -}; - /*! \class Qt3DRender::QTextureImage \inmodule Qt3DRender diff --git a/src/render/texture/qtextureimage_p.h b/src/render/texture/qtextureimage_p.h new file mode 100644 index 000000000..528c8c918 --- /dev/null +++ b/src/render/texture/qtextureimage_p.h @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3DRENDER_TEXTUREIMAGE_P_H +#define QT3DRENDER_TEXTUREIMAGE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qabstracttextureimage.h" +#include <Qt3DRender/private/qurlhelper_p.h> + +QT_BEGIN_NAMESPACE + +namespace Qt3DRender { + +class QImageTextureDataFunctor : public QTextureDataFunctor +{ +public: + QImageTextureDataFunctor(const QUrl &url) + : QTextureDataFunctor() + , m_url(url) + {} + + // Will be executed from within a QAspectJob + QTexImageDataPtr operator ()() Q_DECL_FINAL + { + QTexImageDataPtr dataPtr; + if (m_url.isLocalFile() || m_url.scheme() == QStringLiteral("qrc")) { + QString source = Qt3DRender::QUrlHelper::urlToLocalFileOrQrc(m_url); + dataPtr.reset(new QTexImageData()); + if (dataPtr->setCompressedFile(source)) + return dataPtr; + QImage img; + if (img.load(source)) { + dataPtr->setImage(img); + return dataPtr; + } + dataPtr.reset(); + qWarning() << "Failed to load image : " << source; + } else { + qWarning() << "implement loading from remote URLs"; + } + return dataPtr; + } + + bool operator ==(const QTextureDataFunctor &other) const Q_DECL_FINAL + { + const QImageTextureDataFunctor *otherFunctor = functor_cast<QImageTextureDataFunctor>(&other); + return (otherFunctor != Q_NULLPTR && otherFunctor->m_url == m_url); + } + + QT3D_FUNCTOR(QImageTextureDataFunctor) + +private: + QUrl m_url; +}; + +} // namespace Qt3DRender + +QT_END_NAMESPACE + +#endif // QT3DRENDER_TEXTUREIMAGE_P_H diff --git a/src/render/texture/qtextureproviders.cpp b/src/render/texture/qtextureproviders.cpp index ec5133138..48c7585f3 100644 --- a/src/render/texture/qtextureproviders.cpp +++ b/src/render/texture/qtextureproviders.cpp @@ -34,12 +34,27 @@ ** ****************************************************************************/ +#include "qtextureimage.h" +#include "qabstracttextureimage.h" +#include "qtextureimage_p.h" #include "qtextureproviders.h" +#include "qabstracttextureprovider_p.h" QT_BEGIN_NAMESPACE namespace Qt3DRender { +class QTextureLoaderPrivate : public QAbstractTextureProviderPrivate +{ +public: + QTextureLoaderPrivate() + : QAbstractTextureProviderPrivate() + { + } + + QUrl m_source; +}; + /*! \class Qt3DRender::QTexture1D \inmodule Qt3DRender @@ -251,6 +266,32 @@ QTextureBuffer::~QTextureBuffer() { } +QTextureLoader::QTextureLoader(QNode *parent) + : QAbstractTextureProvider(*new QTextureLoaderPrivate, parent) +{ + d_func()->m_target = TargetAutomatic; +} + +QTextureLoader::~QTextureLoader() +{ +} + +QUrl QTextureLoader::source() const +{ + Q_D(const QTextureLoader); + return d->m_source; +} + +void QTextureLoader::setSource(const QUrl& source) +{ + Q_D(QTextureLoader); + if (source != d->m_source) { + d->m_source = source; + d->m_dataFunctor.reset(new QImageTextureDataFunctor(source)); + emit sourceChanged(source); + } +} + } // namespace Qt3DRender QT_END_NAMESPACE diff --git a/src/render/texture/qtextureproviders.h b/src/render/texture/qtextureproviders.h index 17e4a62d5..e1d3b98cb 100644 --- a/src/render/texture/qtextureproviders.h +++ b/src/render/texture/qtextureproviders.h @@ -37,6 +37,7 @@ #ifndef QT3DRENDER_QTEXTUREPROVIDERS_H #define QT3DRENDER_QTEXTUREPROVIDERS_H +#include <QUrl> #include <Qt3DRender/qabstracttextureprovider.h> QT_BEGIN_NAMESPACE @@ -131,6 +132,29 @@ public: ~QTextureBuffer(); }; +class QTextureLoaderPrivate; + +class QT3DRENDERSHARED_EXPORT QTextureLoader : public QAbstractTextureProvider +{ + Q_OBJECT + Q_PROPERTY(QUrl source READ source WRITE setSource NOTIFY sourceChanged) + +public: + explicit QTextureLoader(Qt3DCore::QNode *parent = 0); + ~QTextureLoader(); + + QUrl source() const; + +public Q_SLOTS: + void setSource(const QUrl &source); + +Q_SIGNALS: + void sourceChanged(const QUrl &source); + +private: + Q_DECLARE_PRIVATE(QTextureLoader) +}; + } // namespace Qt3DRender QT_END_NAMESPACE diff --git a/src/render/texture/texture.cpp b/src/render/texture/texture.cpp index a411eedc5..41b011711 100644 --- a/src/render/texture/texture.cpp +++ b/src/render/texture/texture.cpp @@ -61,6 +61,7 @@ Texture::Texture() , m_height(1) , m_depth(1) , m_layers(1) + , m_mipLevels(1) , m_generateMipMaps(false) , m_target(QAbstractTextureProvider::Target2D) , m_format(QAbstractTextureProvider::RGBA8_UNorm) @@ -99,6 +100,7 @@ void Texture::cleanup() m_height = 1; m_depth = 1; m_layers = 1; + m_mipLevels = 1; m_generateMipMaps = false; m_target = QAbstractTextureProvider::Target2D; m_format = QAbstractTextureProvider::RGBA8_UNorm; @@ -119,6 +121,8 @@ void Texture::cleanup() m_textureManager = Q_NULLPTR; m_textureImageManager = Q_NULLPTR; m_textureDataManager = Q_NULLPTR; + m_dataFunctor.clear(); + m_textureDataHandle = HTextureData(); } // AspectThread @@ -145,6 +149,10 @@ void Texture::updateFromPeer(Qt3DCore::QNode *peer) m_comparisonMode = texture->comparisonMode(); m_layers = texture->maximumLayers(); m_unique = texture->isUnique(); + m_dataFunctor = texture->dataFunctor(); + + if (m_dataFunctor) + addToPendingTextureJobs(); } } @@ -230,6 +238,11 @@ QOpenGLTexture *Texture::buildGLTexture() return Q_NULLPTR; } + if (m_target == QAbstractTextureProvider::TargetAutomatic) { + qWarning() << Q_FUNC_INFO << "something went wrong, target shouldn't be automatic at this point"; + return Q_NULLPTR; + } + QOpenGLTexture* glTex = new QOpenGLTexture(static_cast<QOpenGLTexture::Target>(m_target)); if (m_format == QAbstractTextureProvider::Automatic) @@ -278,8 +291,14 @@ QOpenGLTexture *Texture::buildGLTexture() m_target == QAbstractTextureProvider::TargetCubeMapArray) glTex->setLayers(m_layers); - if (m_generateMipMaps) + if (m_generateMipMaps) { glTex->setMipLevels(glTex->maximumMipLevels()); + } else { + glTex->setAutoMipMapGenerationEnabled(false); + glTex->setMipBaseLevel(0); + glTex->setMipMaxLevel(m_mipLevels - 1); + glTex->setMipLevels(m_mipLevels); + } if (!glTex->create()) { qWarning() << Q_FUNC_INFO << "creating QOpenGLTexture failed"; @@ -297,6 +316,52 @@ QOpenGLTexture *Texture::buildGLTexture() } // RenderThread +void Texture::setToGLTexture(QTexImageData *imgData) +{ + Q_ASSERT(m_gl && m_gl->isCreated() && m_gl->isStorageAllocated()); + + const int layers = imgData->layers(); + const int faces = imgData->faces(); + const int mipLevels = m_generateMipMaps ? 1 : imgData->mipLevels(); + + for (int layer = 0; layer < layers; layer++) { + for (int face = 0; face < faces; face++) { + for (int level = 0; level < mipLevels; level++) { + // ensure we don't accidently cause a detach / copy of the raw bytes + const QByteArray &bytes(imgData->data(layer, face, level)); + + if (imgData->isCompressed()) { + m_gl->setCompressedData(level, + 0, + static_cast<QOpenGLTexture::CubeMapFace>(QOpenGLTexture::CubeMapPositiveX + face), + bytes.size(), + bytes.constData()); + } else { + QOpenGLPixelTransferOptions uploadOptions; + uploadOptions.setAlignment(1); + m_gl->setData(level, + 0, + static_cast<QOpenGLTexture::CubeMapFace>(QOpenGLTexture::CubeMapPositiveX + face), + imgData->pixelFormat(), + imgData->pixelType(), + bytes.constData(), + &uploadOptions); + } + } + } + } + + // FIXME : make this conditional on Qt version + // work-around issue in QOpenGLTexture DSA emulation which rasies + // an Invalid Enum error + if (QOpenGLContext *ctx = QOpenGLContext::currentContext()) { + int err = ctx->functions()->glGetError(); + if (err) + qWarning() << Q_FUNC_INFO << err; + } +} + +// RenderThread void Texture::setToGLTexture(TextureImage *rImg, QTexImageData *imgData) { Q_ASSERT(m_gl && m_gl->isCreated() && m_gl->isStorageAllocated()); @@ -352,7 +417,7 @@ void Texture::updateWrapAndFilters() void Texture::updateDNA() { - int key = m_width + m_height + m_depth + m_layers + + int key = m_width + m_height + m_depth + m_layers + m_mipLevels + (m_generateMipMaps ? 1 : 0) + static_cast<int>(m_target) + static_cast<int>(m_format) + @@ -386,6 +451,14 @@ bool Texture::isTextureReset() const return m_isDirty; } +void Texture::setTarget(QAbstractTextureProvider::Target target) +{ + if (target != m_target) { + m_target = target; + m_isDirty = true; + } +} + void Texture::setSize(int width, int height, int depth) { if (width != m_width) { @@ -410,6 +483,14 @@ void Texture::setFormat(QAbstractTextureProvider::TextureFormat format) } } +void Texture::setMipLevels(int mipLevels) +{ + if (mipLevels != m_mipLevels) { + m_mipLevels = mipLevels; + m_isDirty = true; + } +} + // ChangeArbiter/Aspect Thread void Texture::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) { @@ -527,6 +608,12 @@ void Texture::setTextureDataManager(TextureDataManager *manager) // RenderThread void Texture::updateAndLoadTextureImage() { + if (!m_textureDataHandle.isNull()) { + QTexImageData *data = m_textureDataManager->data(m_textureDataHandle); + if (data != Q_NULLPTR) + setToGLTexture(data); + } + QVector<TextureImageDNA> dnas; Q_FOREACH (HTextureImage t, m_textureImages) { TextureImage *img = m_textureImageManager->data(t); @@ -543,6 +630,7 @@ void Texture::updateAndLoadTextureImage() } } } + m_dataUploadRequired = false; } diff --git a/src/render/texture/texture_p.h b/src/render/texture/texture_p.h index 71fc3f3ec..a67e759dd 100644 --- a/src/render/texture/texture_p.h +++ b/src/render/texture/texture_p.h @@ -99,16 +99,24 @@ public: void requestTextureDataUpdate(); void addToPendingTextureJobs(); + void setTarget(QAbstractTextureProvider::Target target); void setSize(int width, int height, int depth); void setFormat(QAbstractTextureProvider::TextureFormat format); + void setMipLevels(int mipmapLevels); inline QVector<HTextureImage> textureImages() const { return m_textureImages; } inline QAbstractTextureProvider::TextureFormat format() const { return m_format; } + inline QAbstractTextureProvider::Target target() const { return m_target; } + inline bool isAutoMipMapGenerationEnabled() const { return m_generateMipMaps; } + + inline QTextureDataFunctorPtr dataFunctor() const { return m_dataFunctor; } + void setTextureDataHandle(HTextureData handle) { m_textureDataHandle = handle; } private: QOpenGLTexture *m_gl; QOpenGLTexture *buildGLTexture(); + void setToGLTexture(QTexImageData *imgData); void setToGLTexture(TextureImage *rImg, QTexImageData *imgData); void updateWrapAndFilters(); @@ -116,6 +124,7 @@ private: int m_height; int m_depth; int m_layers; + int m_mipLevels; bool m_generateMipMaps; QAbstractTextureProvider::Target m_target; QAbstractTextureProvider::TextureFormat m_format; @@ -128,6 +137,9 @@ private: QAbstractTextureProvider::ComparisonFunction m_comparisonFunction; QAbstractTextureProvider::ComparisonMode m_comparisonMode; + QTextureDataFunctorPtr m_dataFunctor; + HTextureData m_textureDataHandle; + QVector<HTextureImage> m_textureImages; bool m_isDirty; diff --git a/tests/auto/render/ddstextures/data/16x16x1-1-bc1-dx10.dds b/tests/auto/render/ddstextures/data/16x16x1-1-bc1-dx10.dds Binary files differnew file mode 100644 index 000000000..feacae8d1 --- /dev/null +++ b/tests/auto/render/ddstextures/data/16x16x1-1-bc1-dx10.dds diff --git a/tests/auto/render/ddstextures/data/16x16x1-1-bc1-nomips-dx10.dds b/tests/auto/render/ddstextures/data/16x16x1-1-bc1-nomips-dx10.dds Binary files differnew file mode 100644 index 000000000..40da98cde --- /dev/null +++ b/tests/auto/render/ddstextures/data/16x16x1-1-bc1-nomips-dx10.dds diff --git a/tests/auto/render/ddstextures/data/16x16x1-1-bc1-nomips.dds b/tests/auto/render/ddstextures/data/16x16x1-1-bc1-nomips.dds Binary files differnew file mode 100644 index 000000000..1dd3e1e91 --- /dev/null +++ b/tests/auto/render/ddstextures/data/16x16x1-1-bc1-nomips.dds diff --git a/tests/auto/render/ddstextures/data/16x16x1-1-bc1.dds b/tests/auto/render/ddstextures/data/16x16x1-1-bc1.dds Binary files differnew file mode 100644 index 000000000..e31f410d2 --- /dev/null +++ b/tests/auto/render/ddstextures/data/16x16x1-1-bc1.dds diff --git a/tests/auto/render/ddstextures/data/16x16x1-1-bc3-dx10.dds b/tests/auto/render/ddstextures/data/16x16x1-1-bc3-dx10.dds Binary files differnew file mode 100644 index 000000000..76c820f31 --- /dev/null +++ b/tests/auto/render/ddstextures/data/16x16x1-1-bc3-dx10.dds diff --git a/tests/auto/render/ddstextures/data/16x16x1-1-bc3-nomips-dx10.dds b/tests/auto/render/ddstextures/data/16x16x1-1-bc3-nomips-dx10.dds Binary files differnew file mode 100644 index 000000000..0a2964f12 --- /dev/null +++ b/tests/auto/render/ddstextures/data/16x16x1-1-bc3-nomips-dx10.dds diff --git a/tests/auto/render/ddstextures/data/16x16x1-1-bc3-nomips.dds b/tests/auto/render/ddstextures/data/16x16x1-1-bc3-nomips.dds Binary files differnew file mode 100644 index 000000000..c8c94d85f --- /dev/null +++ b/tests/auto/render/ddstextures/data/16x16x1-1-bc3-nomips.dds diff --git a/tests/auto/render/ddstextures/data/16x16x1-1-bc3.dds b/tests/auto/render/ddstextures/data/16x16x1-1-bc3.dds Binary files differnew file mode 100644 index 000000000..4a08d324a --- /dev/null +++ b/tests/auto/render/ddstextures/data/16x16x1-1-bc3.dds diff --git a/tests/auto/render/ddstextures/data/16x16x1-1-lumi-nomips.dds b/tests/auto/render/ddstextures/data/16x16x1-1-lumi-nomips.dds Binary files differnew file mode 100644 index 000000000..8fdd5e3e1 --- /dev/null +++ b/tests/auto/render/ddstextures/data/16x16x1-1-lumi-nomips.dds diff --git a/tests/auto/render/ddstextures/data/16x16x1-1-lumi.dds b/tests/auto/render/ddstextures/data/16x16x1-1-lumi.dds Binary files differnew file mode 100644 index 000000000..82ab57958 --- /dev/null +++ b/tests/auto/render/ddstextures/data/16x16x1-1-lumi.dds diff --git a/tests/auto/render/ddstextures/data/16x16x1-1-rgb-nomips.dds b/tests/auto/render/ddstextures/data/16x16x1-1-rgb-nomips.dds Binary files differnew file mode 100644 index 000000000..94d06c2c4 --- /dev/null +++ b/tests/auto/render/ddstextures/data/16x16x1-1-rgb-nomips.dds diff --git a/tests/auto/render/ddstextures/data/16x16x1-1-rgb.dds b/tests/auto/render/ddstextures/data/16x16x1-1-rgb.dds Binary files differnew file mode 100644 index 000000000..45635dd97 --- /dev/null +++ b/tests/auto/render/ddstextures/data/16x16x1-1-rgb.dds diff --git a/tests/auto/render/ddstextures/data/16x16x1-6-bc1-dx10.dds b/tests/auto/render/ddstextures/data/16x16x1-6-bc1-dx10.dds Binary files differnew file mode 100644 index 000000000..209b796f0 --- /dev/null +++ b/tests/auto/render/ddstextures/data/16x16x1-6-bc1-dx10.dds diff --git a/tests/auto/render/ddstextures/data/16x16x1-6-bc1-nomips-dx10.dds b/tests/auto/render/ddstextures/data/16x16x1-6-bc1-nomips-dx10.dds Binary files differnew file mode 100644 index 000000000..e79e29ab5 --- /dev/null +++ b/tests/auto/render/ddstextures/data/16x16x1-6-bc1-nomips-dx10.dds diff --git a/tests/auto/render/ddstextures/data/16x16x1-6-bc1-nomips.dds b/tests/auto/render/ddstextures/data/16x16x1-6-bc1-nomips.dds Binary files differnew file mode 100644 index 000000000..de6796d9f --- /dev/null +++ b/tests/auto/render/ddstextures/data/16x16x1-6-bc1-nomips.dds diff --git a/tests/auto/render/ddstextures/data/16x16x1-6-bc1.dds b/tests/auto/render/ddstextures/data/16x16x1-6-bc1.dds Binary files differnew file mode 100644 index 000000000..92b95ae73 --- /dev/null +++ b/tests/auto/render/ddstextures/data/16x16x1-6-bc1.dds diff --git a/tests/auto/render/ddstextures/data/16x16x1-6-bc3-dx10.dds b/tests/auto/render/ddstextures/data/16x16x1-6-bc3-dx10.dds Binary files differnew file mode 100644 index 000000000..f56fa09fd --- /dev/null +++ b/tests/auto/render/ddstextures/data/16x16x1-6-bc3-dx10.dds diff --git a/tests/auto/render/ddstextures/data/16x16x1-6-bc3-nomips-dx10.dds b/tests/auto/render/ddstextures/data/16x16x1-6-bc3-nomips-dx10.dds Binary files differnew file mode 100644 index 000000000..31e137553 --- /dev/null +++ b/tests/auto/render/ddstextures/data/16x16x1-6-bc3-nomips-dx10.dds diff --git a/tests/auto/render/ddstextures/data/16x16x1-6-bc3-nomips.dds b/tests/auto/render/ddstextures/data/16x16x1-6-bc3-nomips.dds Binary files differnew file mode 100644 index 000000000..644274601 --- /dev/null +++ b/tests/auto/render/ddstextures/data/16x16x1-6-bc3-nomips.dds diff --git a/tests/auto/render/ddstextures/data/16x16x1-6-bc3.dds b/tests/auto/render/ddstextures/data/16x16x1-6-bc3.dds Binary files differnew file mode 100644 index 000000000..144515bb0 --- /dev/null +++ b/tests/auto/render/ddstextures/data/16x16x1-6-bc3.dds diff --git a/tests/auto/render/ddstextures/data/16x16x1-6-lumi-nomips.dds b/tests/auto/render/ddstextures/data/16x16x1-6-lumi-nomips.dds Binary files differnew file mode 100644 index 000000000..baa884a36 --- /dev/null +++ b/tests/auto/render/ddstextures/data/16x16x1-6-lumi-nomips.dds diff --git a/tests/auto/render/ddstextures/data/16x16x1-6-lumi.dds b/tests/auto/render/ddstextures/data/16x16x1-6-lumi.dds Binary files differnew file mode 100644 index 000000000..1a4e6f46f --- /dev/null +++ b/tests/auto/render/ddstextures/data/16x16x1-6-lumi.dds diff --git a/tests/auto/render/ddstextures/data/16x16x1-6-rgb-nomips.dds b/tests/auto/render/ddstextures/data/16x16x1-6-rgb-nomips.dds Binary files differnew file mode 100644 index 000000000..318a0bd35 --- /dev/null +++ b/tests/auto/render/ddstextures/data/16x16x1-6-rgb-nomips.dds diff --git a/tests/auto/render/ddstextures/data/16x16x1-6-rgb.dds b/tests/auto/render/ddstextures/data/16x16x1-6-rgb.dds Binary files differnew file mode 100644 index 000000000..1f3c8f9cf --- /dev/null +++ b/tests/auto/render/ddstextures/data/16x16x1-6-rgb.dds diff --git a/tests/auto/render/ddstextures/ddstextures.pro b/tests/auto/render/ddstextures/ddstextures.pro new file mode 100644 index 000000000..e81fd80d8 --- /dev/null +++ b/tests/auto/render/ddstextures/ddstextures.pro @@ -0,0 +1,37 @@ +TEMPLATE = app + +TARGET = tst_ddstextures + +CONFIG += testcase + +SOURCES += tst_ddstextures.cpp + +OTHER_FILES = \ + data/16x16x1-1-bc1.dds \ + data/16x16x1-1-bc1-dx10.dds \ + data/16x16x1-1-bc1-nomips.dds \ + data/16x16x1-1-bc1-nomips-dx10.dds \ + data/16x16x1-1-bc3.dds \ + data/16x16x1-1-bc3-dx10.dds \ + data/16x16x1-1-bc3-nomips.dds \ + data/16x16x1-1-bc3-nomips-dx10.dds \ + data/16x16x1-1-lumi.dds \ + data/16x16x1-1-lumi-nomips.dds \ + data/16x16x1-1-rgb.dds \ + data/16x16x1-1-rgb-nomips.dds \ + data/16x16x1-6-bc1.dds \ + data/16x16x1-6-bc1-dx10.dds \ + data/16x16x1-6-bc1-nomips.dds \ + data/16x16x1-6-bc1-nomips-dx10.dds \ + data/16x16x1-6-bc3.dds \ + data/16x16x1-6-bc3-dx10.dds \ + data/16x16x1-6-bc3-nomips.dds \ + data/16x16x1-6-bc3-nomips-dx10.dds \ + data/16x16x1-6-lumi.dds \ + data/16x16x1-6-lumi-nomips.dds \ + data/16x16x1-6-rgb.dds \ + data/16x16x1-6-rgb-nomips.dds + +TESTDATA = data/* + +QT += core-private 3dcore 3dcore-private 3drender 3drender-private testlib diff --git a/tests/auto/render/ddstextures/tst_ddstextures.cpp b/tests/auto/render/ddstextures/tst_ddstextures.cpp new file mode 100644 index 000000000..55e9f7f5f --- /dev/null +++ b/tests/auto/render/ddstextures/tst_ddstextures.cpp @@ -0,0 +1,101 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see http://www.qt.io/terms-conditions. For further +** information use the contact form at http://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPLv3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/QTest> +#include <Qt3DRender/qtexturedata.h> + +class tst_DdsTextures : public QObject +{ + Q_OBJECT + +private slots: + void ddsImageData(); +}; + +void tst_DdsTextures::ddsImageData() +{ + const struct TextureInfo { + const char *source; + int width; + int height; + int depth; + int faces; + int mipmapLevels; + QOpenGLTexture::TextureFormat format; + } textures[] = { + { "data/16x16x1-1-lumi-nomips.dds", 16, 16, 1, 1, 1, QOpenGLTexture::R8_UNorm }, + { "data/16x16x1-1-lumi.dds", 16, 16, 1, 1, 5, QOpenGLTexture::R8_UNorm }, + { "data/16x16x1-1-rgb-nomips.dds", 16, 16, 1, 1, 1, QOpenGLTexture::RGBA8_UNorm }, + { "data/16x16x1-1-rgb.dds", 16, 16, 1, 1, 5, QOpenGLTexture::RGBA8_UNorm }, + { "data/16x16x1-1-bc1-nomips.dds", 16, 16, 1, 1, 1, QOpenGLTexture::RGBA_DXT1 }, + { "data/16x16x1-1-bc1.dds", 16, 16, 1, 1, 5, QOpenGLTexture::RGBA_DXT1 }, + { "data/16x16x1-1-bc3-nomips.dds", 16, 16, 1, 1, 1, QOpenGLTexture::RGBA_DXT5 }, + { "data/16x16x1-1-bc3.dds", 16, 16, 1, 1, 5, QOpenGLTexture::RGBA_DXT5 }, + { "data/16x16x1-1-bc1-nomips-dx10.dds", 16, 16, 1, 1, 1, QOpenGLTexture::RGBA_DXT1 }, + { "data/16x16x1-1-bc1-dx10.dds", 16, 16, 1, 1, 5, QOpenGLTexture::RGBA_DXT1 }, + { "data/16x16x1-1-bc3-nomips-dx10.dds", 16, 16, 1, 1, 1, QOpenGLTexture::RGBA_DXT5 }, + { "data/16x16x1-1-bc3-dx10.dds", 16, 16, 1, 1, 5, QOpenGLTexture::RGBA_DXT5 }, + { "data/16x16x1-6-lumi-nomips.dds", 16, 16, 1, 6, 1, QOpenGLTexture::R8_UNorm }, + { "data/16x16x1-6-lumi.dds", 16, 16, 1, 6, 5, QOpenGLTexture::R8_UNorm }, + { "data/16x16x1-6-rgb-nomips.dds", 16, 16, 1, 6, 1, QOpenGLTexture::RGBA8_UNorm }, + { "data/16x16x1-6-rgb.dds", 16, 16, 1, 6, 5, QOpenGLTexture::RGBA8_UNorm }, + { "data/16x16x1-6-bc1-nomips.dds", 16, 16, 1, 6, 1, QOpenGLTexture::RGBA_DXT1 }, + { "data/16x16x1-6-bc1.dds", 16, 16, 1, 6, 5, QOpenGLTexture::RGBA_DXT1 }, + { "data/16x16x1-6-bc3-nomips.dds", 16, 16, 1, 6, 1, QOpenGLTexture::RGBA_DXT5 }, + { "data/16x16x1-6-bc3.dds", 16, 16, 1, 6, 5, QOpenGLTexture::RGBA_DXT5 }, + { "data/16x16x1-6-bc1-nomips-dx10.dds", 16, 16, 1, 6, 1, QOpenGLTexture::RGBA_DXT1 }, + { "data/16x16x1-6-bc1-dx10.dds", 16, 16, 1, 6, 5, QOpenGLTexture::RGBA_DXT1 }, + { "data/16x16x1-6-bc3-nomips-dx10.dds", 16, 16, 1, 6, 1, QOpenGLTexture::RGBA_DXT5 }, + { "data/16x16x1-6-bc3-dx10.dds", 16, 16, 1, 6, 5, QOpenGLTexture::RGBA_DXT5 }, + }; + + for (unsigned i = 0; i < sizeof(textures)/sizeof(*textures); i++) { + const TextureInfo *texture = &textures[i]; + + Qt3DRender::QTexImageData data; + + QVERIFY(data.setCompressedFile(texture->source)); + QCOMPARE(data.width(), texture->width); + QCOMPARE(data.height(), texture->height); + QCOMPARE(data.faces(), texture->faces); + QCOMPARE(data.mipLevels(), texture->mipmapLevels); + QCOMPARE(data.format(), texture->format); + } +} + +QTEST_APPLESS_MAIN(tst_DdsTextures) + +#include "tst_ddstextures.moc" diff --git a/tests/auto/render/render.pro b/tests/auto/render/render.pro index 4b43a291d..34d6ef4f3 100644 --- a/tests/auto/render/render.pro +++ b/tests/auto/render/render.pro @@ -43,5 +43,6 @@ contains(QT_CONFIG, private_tests) { boundingvolumedebug \ qdefaultmeshes \ trianglesextractor \ - triangleboundingvolume + triangleboundingvolume \ + ddstextures } |