Texture.h#

Parent directory (texture)

The main class that represents an Image (Texture).

Includes#

  • PVRCore/Errors.h

  • PVRCore/texture/TextureHeader.h

  • cmath

Included By#

Namespaces#

Classes#

Enums#

Functions#

Typedefs#

Source Code#

#pragma once
#include "PVRCore/Errors.h"
#include "PVRCore/texture/TextureHeader.h"
#include <cmath>

namespace pvr {

enum class CubeFace : uint32_t
{
    PositiveX = 0,
    NegativeX,
    PositiveY,
    NegativeY,
    PositiveZ,
    NegativeZ
};

enum class ImageType
{
    Image1D,
    Image2D,
    Image3D,
    Unallocated,
    Unknown,
    Count = Image3D + 1
};

enum class ImageViewType
{
    ImageView1D,
    ImageView2D,
    ImageView3D,
    ImageView2DCube,
    ImageView1DArray,
    ImageView2DArray,
    ImageView2DCubeArray,
    ImageViewUnknown,
};

inline float growFloat(const uint32_t& value, const uint8_t& mantissaBits, const uint8_t& exponentBits, const uint8_t& exponentBias, const bool hasSign /*=true*/)
{
    // Union to avoid messy casting.
    union
    {
        float fVal;
        uint32_t uiVal;
    } intToFloat;

    // Float 32 constants.
    static const uint8_t f32expBias = 127;
    static const uint8_t f32signBits = 1;
    static const uint8_t f32expBits = 8;
    static const uint8_t f32manBits = 23;
    static const uint8_t f32totBits = 32;

    // Get the # of sign bits (always 1 or 0)
    uint8_t signBits = static_cast<uint8_t>(hasSign ? 1 : 0);

    // Work out the total bits
    uint8_t totalBits = static_cast<uint8_t>(mantissaBits + exponentBits + signBits);

    // Generate the masks for each bit.
    uint32_t signMask = static_cast<uint8_t>(((1 << signBits) - 1) << (exponentBits + mantissaBits));
    uint32_t expoMask = static_cast<uint8_t>(((1 << exponentBits) - 1) << mantissaBits);
    uint32_t mantMask = static_cast<uint8_t>(((1 << mantissaBits) - 1));

    // Get original exponent.
    uint32_t originalExponent = ((value & expoMask) >> (mantissaBits));
    bool originalIsNaN = (originalExponent == (uint32_t)((1 << exponentBits) - 1));

    // Bit shift and edit until
    uint32_t uSign = (value & signMask) << ((f32totBits - f32signBits) - (totalBits - signBits));
    uint32_t uExponent = (originalExponent - exponentBias + f32expBias) << f32manBits;
    uint32_t uMantissa = (value & mantMask) << (f32manBits - mantissaBits);

    // Make sure NaN/Infinity is preserved if original was NaN/Infinity.
    if (originalIsNaN) { uExponent = ((1 << f32expBits) - 1) << f32manBits; }

    // Assign the expanded values to the union
    intToFloat.uiVal = uSign | uExponent | uMantissa;

    // Return the expanded float
    return intToFloat.fVal;
}

inline ImageType imageViewTypeToImageBaseType(ImageViewType viewtype)
{
    switch (viewtype)
    {
    case ImageViewType::ImageView1D:
    case ImageViewType::ImageView1DArray: return ImageType::Image1D;

    case ImageViewType::ImageView2D:
    case ImageViewType::ImageView2DCube:
    case ImageViewType::ImageView2DArray:
    case ImageViewType::ImageView2DCubeArray: return ImageType::Image2D;

    case ImageViewType::ImageView3D: return ImageType::Image3D;

    default: return ImageType::Unallocated;
    }
}

inline void convertXYZToCubeUV(float x, float y, float z, CubeFace& face, float& u, float& v)
{
    float absX = fabs(x);
    float absY = fabs(y);
    float absZ = fabs(z);

    if (absX == 0.f && absY == 0.f && absZ == 0.f) { throw new std::runtime_error("Cannot convert the zero vector to a cubemap sample"); }

    int isXPositive = x > 0 ? 1 : 0;
    int isYPositive = y > 0 ? 1 : 0;
    int isZPositive = z > 0 ? 1 : 0;

    float maxAxis = 0.0f;
    float uc = 0.0f;
    float vc = 0.0f;

    // POSITIVE X
    if (isXPositive && absX >= absY && absX >= absZ)
    {
        // u (0 to 1) goes from +z to -z
        // v (0 to 1) goes from -y to +y
        maxAxis = absX;
        uc = -z;
        vc = -y;
        face = CubeFace::PositiveX;
    }
    // NEGATIVE X
    if (!isXPositive && absX >= absY && absX >= absZ)
    {
        // u (0 to 1) goes from -z to +z
        // v (0 to 1) goes from -y to +y
        maxAxis = absX;
        uc = z;
        vc = -y;
        face = CubeFace::NegativeX;
    }
    // POSITIVE Y
    if (isYPositive && absY >= absX && absY >= absZ)
    {
        // u (0 to 1) goes from -x to +x
        // v (0 to 1) goes from +z to -z
        maxAxis = absY;
        uc = x;
        vc = z;
        face = CubeFace::PositiveY;
    }
    // NEGATIVE Y
    if (!isYPositive && absY >= absX && absY >= absZ)
    {
        // u (0 to 1) goes from -x to +x
        // v (0 to 1) goes from -z to +z
        maxAxis = absY;
        uc = x;
        vc = +z;
        face = CubeFace::NegativeY;
    }
    // POSITIVE Z
    if (isZPositive && absZ >= absX && absZ >= absY)
    {
        // u (0 to 1) goes from -x to +x
        // v (0 to 1) goes from -y to +y
        maxAxis = absZ;
        uc = x;
        vc = -y;
        face = CubeFace::PositiveZ;
    }
    // NEGATIVE Z
    if (!isZPositive && absZ >= absX && absZ >= absY)
    {
        // u (0 to 1) goes from +x to -x
        // v (0 to 1) goes from -y to +y
        maxAxis = absZ;
        uc = -x;
        vc = -y;
        face = CubeFace::NegativeZ;
    }

    // Convert range from -1 to 1 to 0 to 1
    u = 0.5f * (uc / maxAxis + 1.0f);
    v = 0.5f * (vc / maxAxis + 1.0f);
}

struct ImageLayersSize
{
    uint16_t numArrayLevels;
    uint16_t numMipLevels;
    uint16_t numPlaneLevels;

    ImageLayersSize(uint16_t numArrayLevels = 1, uint8_t numMipLevels = 1, uint8_t numPlaneLevels = 1)
        : numArrayLevels(numArrayLevels), numMipLevels(numMipLevels), numPlaneLevels(numPlaneLevels)
    {}
};

struct ImageDataFormat
{
    PixelFormat format;
    VariableType dataType;
    ColorSpace colorSpace;

    explicit ImageDataFormat(const PixelFormat& format = PixelFormat::RGBA_8888(), VariableType dataType = VariableType::UnsignedByteNorm, ColorSpace colorSpace = ColorSpace::lRGB)
        : format(format), dataType(dataType), colorSpace(colorSpace)
    {}

    bool operator==(const ImageDataFormat& rhs) const { return (format == rhs.format && dataType == rhs.dataType && colorSpace == rhs.colorSpace); }

    bool operator!=(const ImageDataFormat& rhs) const { return !(*this == rhs); }
};

struct ImageStorageFormat : public ImageDataFormat
{
    uint8_t numMipMapLevels;
    uint8_t numSamples;
    uint8_t numPlanes;

    ImageStorageFormat(const PixelFormat& format = PixelFormat::RGBA_8888(), uint8_t numMipMapLevels = 1, ColorSpace colorSpace = ColorSpace::lRGB,
        VariableType dataType = VariableType::UnsignedByteNorm, uint8_t numSamples = 1, uint8_t numPlanes = 1)
        : ImageDataFormat(format, dataType, colorSpace), numMipMapLevels(numMipMapLevels), numSamples(numSamples), numPlanes(numPlanes)
    {}

    ImageStorageFormat(const ImageDataFormat& dataFmt, uint8_t numMipMapLevels = 1, uint8_t numSamples = 1, uint8_t numPlanes = 1)
        : ImageDataFormat(dataFmt), numMipMapLevels(numMipMapLevels), numSamples(numSamples), numPlanes(numPlanes)
    {}
};

template<typename T>
struct GenericExtent2D
{
    T width;
    T height;
    GenericExtent2D(T width = 0, T height = 0) : width(width), height(height) {}
};

template<typename Txy, typename Tz>
struct GenericExtent3D : public GenericExtent2D<Txy>
{
    Tz depth;

    GenericExtent3D() {}

    GenericExtent3D(Txy width, Txy height, Tz depth = 1) : GenericExtent2D<Txy>(width, height), depth(depth) {}

    GenericExtent3D(const GenericExtent2D<Txy>& extent2D, Tz depth = 1) : GenericExtent2D<Txy>(extent2D), depth(depth) {}
};

template<typename T>
struct GenericOffset2D
{
    T x;
    T y;

    GenericOffset2D(T offsetX = 0, T offsetY = 0) : x(offsetX), y(offsetY) {}

    GenericOffset2D operator+(const GenericExtent2D<typename std::make_unsigned<T>::type>& rhs) const { return GenericOffset2D(*this) += rhs; }
    GenericOffset2D& operator+=(const GenericExtent2D<typename std::make_unsigned<T>::type>& rhs)
    {
        x += rhs.width;
        y += rhs.height;
        return *this;
    }
};

template<typename Txy, typename Tz>
struct GenericOffset3D : public GenericOffset2D<Txy>
{
    Tz z;

    GenericOffset3D(Txy offsetX = 0, Txy offsetY = 0, Tz offsetZ = 0) : GenericOffset2D<Txy>(offsetX, offsetY), z(offsetZ) {}

    GenericOffset3D operator+(const GenericExtent3D<typename std::make_unsigned<Txy>::type, typename std::make_unsigned<Tz>::type>& rhs) const
    {
        return GenericOffset3D(*this) += rhs;
    }
    GenericOffset3D& operator+=(const GenericExtent3D<typename std::make_unsigned<Txy>::type, typename std::make_unsigned<Tz>::type>& rhs)
    {
        GenericOffset2D<Txy>::x += rhs.width;
        GenericOffset2D<Txy>::y += rhs.height;
        z += rhs.height;
        return *this;
    }

    GenericOffset3D(const GenericOffset2D<Txy>& offsetXY, Tz offsetZ = 0) : GenericOffset2D<Txy>(offsetXY), z(offsetZ) {}
};

typedef GenericOffset2D<int32_t> Offset2D;
typedef GenericOffset3D<int32_t, int32_t> Offset3D;

typedef GenericExtent2D<uint32_t> Extent2D;
typedef GenericExtent3D<uint32_t, uint32_t> Extent3D;

enum class ImageAspectFlags : uint32_t
{
    Color = 0x1,
    Depth = 0x2,
    Stencil = 0x4,
    Metadata = 0x8,
    DepthAndStencil = Depth | Stencil,
};

inline ImageAspectFlags operator|(ImageAspectFlags lhs, ImageAspectFlags rhs)
{
    return static_cast<ImageAspectFlags>(static_cast<std::underlying_type<ImageAspectFlags>::type >(lhs) | static_cast<std::underlying_type<ImageAspectFlags>::type >(rhs));
}

inline void operator|=(ImageAspectFlags& lhs, ImageAspectFlags rhs)
{
    lhs = static_cast<ImageAspectFlags>(static_cast<std::underlying_type<ImageAspectFlags>::type >(lhs) | static_cast<std::underlying_type<ImageAspectFlags>::type >(rhs));
}

inline ImageAspectFlags operator&(ImageAspectFlags lhs, ImageAspectFlags rhs)
{
    return static_cast<ImageAspectFlags>(static_cast<std::underlying_type<ImageAspectFlags>::type >(lhs) & static_cast<std::underlying_type<ImageAspectFlags>::type >(rhs));
}

inline void operator&=(ImageAspectFlags& lhs, ImageAspectFlags rhs)
{
    lhs = static_cast<ImageAspectFlags>(static_cast<std::underlying_type<ImageAspectFlags>::type >(lhs) & static_cast<std::underlying_type<ImageAspectFlags>::type >(rhs));
}

struct ImageSubresource
{
    ImageAspectFlags aspect;
    uint16_t arrayLayerOffset;
    uint16_t mipLevelOffset;
    uint16_t planeOffset;

    ImageSubresource(ImageAspectFlags aspectFlags = ImageAspectFlags::Color, uint16_t mipLevelOffset = 0, uint16_t arrayLayerOffset = 0, uint16_t planeOffset = 0)
        : aspect(aspectFlags), arrayLayerOffset(arrayLayerOffset), mipLevelOffset(mipLevelOffset), planeOffset(planeOffset)
    {}
};

struct ImageSubresourceRange : public ImageLayersSize, public ImageSubresource
{
    ImageSubresourceRange() {}

    ImageSubresourceRange(const ImageLayersSize& layersSize, const ImageSubresource& baseLayers) : ImageLayersSize(layersSize), ImageSubresource(baseLayers) {}
};

struct ImageSubresourceLayers : public ImageSubresource
{
    uint16_t numArrayLayers;
    ImageSubresourceLayers() : numArrayLayers(1) {}
    ImageSubresourceLayers(ImageSubresource baseLayers, uint16_t numArrayLayers) : ImageSubresource(baseLayers), numArrayLayers(numArrayLayers) {}
};

struct ImageRange : public Extent3D, public Offset3D
{
    ImageRange() {}

    ImageRange(const Extent3D& extents, const Offset3D& offset) : Extent3D(extents), Offset3D(offset) {}
};

struct ImageResolveRange
{
    Offset3D srcOffset;
    Offset3D dstOffset;
    Extent3D extent;
    ImageSubresourceLayers srcSubResource;
    ImageSubresourceLayers dstSubResource;

    ImageResolveRange() {}

    ImageResolveRange(const Offset3D& srcOffset0, const Offset3D& dstOffset0, const Extent3D& extent0, const ImageSubresourceLayers& srcSubResource = ImageSubresourceLayers(),
        const ImageSubresourceLayers& dstSubResource = ImageSubresourceLayers())
    {
        srcOffset = srcOffset0;
        dstOffset = dstOffset0;
        extent = extent0;
        this->srcSubResource = srcSubResource;
        this->dstSubResource = dstSubResource;
    }
};

struct CompressedImageDataFormat
{
    CompressedPixelFormat format;
};

struct ImageStorageFormatCompressed : public CompressedImageDataFormat
{
    int8_t numMipMapLevels;
};

enum class TextureFileFormat
{
    UNKNOWN = 0,
    KTX,
    DDX,
    PVR,
    TGA,
    BMP,
    DDS,
    JPEG
};

class Texture : public TextureHeader
{
public:
    Texture();

    Texture(const TextureHeader& sHeader, const unsigned char* pData = NULL);

    void initializeWithHeader(const TextureHeader& sHeader);

    const unsigned char* getDataPointer(uint32_t mipMapLevel = 0, uint32_t arrayMember = 0, uint32_t face = 0, uint32_t plane = 0) const;

    unsigned char* getDataPointer(uint32_t mipMapLevel = 0, uint32_t arrayMember = 0, uint32_t face = 0, uint32_t plane = 0);

    unsigned char* getPixelPointer(uint32_t x, uint32_t y, uint32_t z = 0, uint32_t mipMapLevel = 0, uint32_t arrayMember = 0, uint32_t face = 0, uint32_t plane = 0)
    {
        uint8_t pelsize = getPixelSize();
        size_t idx = (size_t)((size_t)x + (size_t)y * width + (size_t)z * width * height) * pelsize;
        return getDataPointer(mipMapLevel, arrayMember, face, plane) + idx;
    }

    unsigned char* getPixelPointerByUvw(float u, float v, float w = 0, uint32_t mipMapLevel = 0, uint32_t arrayMember = 0, CubeFace face = (CubeFace)0, uint32_t plane = 0)
    {
        uint32_t x = (u <= 0.f) ? 0 : (u >= 1.f) ? getWidth(mipMapLevel) - 1 : uint32_t(u * getWidth(mipMapLevel));
        uint32_t y = (v <= 0.f) ? 0 : (v >= 1.f) ? getHeight(mipMapLevel) - 1 : uint32_t(v * getHeight(mipMapLevel));
        uint32_t z = (w <= 0.f) ? 0 : (w >= 1.f) ? getDepth(mipMapLevel) - 1 : uint32_t(w * getDepth(mipMapLevel));

        return getPixelPointer(x, y, z, mipMapLevel, arrayMember, (uint32_t)face, plane);
    }

    unsigned char* getCubemapPixel(float x, float y, float z, uint32_t mipMapLevel = 0, uint32_t arrayMember = 0, uint32_t plane = 0)
    {
        CubeFace face;
        float u, v;
        convertXYZToCubeUV(x, y, z, face, u, v);
        return getPixelPointerByUvw(u, v, 0, mipMapLevel, arrayMember, face, plane);
    }

    uint8_t getPixelSize() const;

    ImageType getDimension() const { return getDepth() > 1 ? ImageType::Image3D : getHeight() > 1 ? ImageType::Image2D : ImageType::Image1D; }

    ImageLayersSize getLayersSize() const { return ImageLayersSize(static_cast<uint16_t>(getNumArrayMembers() * getNumFaces()), static_cast<uint8_t>(getNumMipMapLevels())); }

    Extent3D getDimensions(uint32_t miplevel = 0) const
    {
        return Extent3D(static_cast<uint16_t>(getWidth(miplevel)), static_cast<uint16_t>(getHeight(miplevel)), static_cast<uint16_t>(getDepth(miplevel)));
    }

    void addPaddingMetaData(uint32_t alignment);

private:
    std::vector<unsigned char> _pTextureData; // Pointer to texture data.
};

TextureFileFormat getTextureFormatFromFilename(const char* assetname);
} // namespace pvr