packages feed

ktx-codec-0.0.2.0: src/Codec/Ktx2/Header.hs

module Codec.Ktx2.Header where

import Data.Binary (Binary(..))
import Data.Binary.Get (getWord32le, getWord64le, getByteString)
import Data.Binary.Put (putByteString, putWord32le, putWord64le)
import Data.ByteString (ByteString)
import Data.ByteString qualified as BS
import Data.Word (Word32, Word64)
import GHC.Generics (Generic)

data Header = Header
  { vkFormat :: Word32 -- ^ Specifies the image format using Vulkan @VkFormat@ enum values. It can be any value defined in core Vulkan 1.2, future core versions or registered Vulkan extensions, except for values listed in Table 1, “Prohibited Formats” and any @*SCALED*@ or @*[2-9]PLANE*@ formats added in future.
  , typeSize :: Word32 -- ^ Specifies the size of the data type in bytes used to upload the data to a graphics API. When @typeSize@ is greater than 1, software on big-endian systems must endian convert all image data since it is little-endian. When format is @VK_FORMAT_UNDEFINED@, typeSize must equal 1.

  , pixelWidth  :: Word32
  , pixelHeight :: Word32
  , pixelDepth  :: Word32

  , layerCount :: Word32 -- ^ Specifies the number of array elements. If the texture is not an array texture, @layerCount@ must equal 0.
  , faceCount  :: Word32 -- ^ If @faceCount@ is equal to 6, @pixelHeight@ must be equal to @pixelWidth@, and @pixelDepth@ must be 0.
  , levelCount :: Word32 -- ^ Specifies the number of levels in the Mip Level Array and, by extension, the number of indices in the Level Index array. A KTX file does not need to contain a complete mipmap pyramid.

  , supercompressionScheme :: Word32 -- ^ Indicates if a supercompression scheme has been applied to the data in levelImages. It must be one of the values from Table 2, “Supercompression Schemes”. A value of 0 indicates no supercompression.

    -- Static index
  , dfdByteOffset :: Word32 -- ^ The offset from the start of the file of the @dfdTotalSize@ field of the Data Format Descriptor.
  , dfdByteLength :: Word32 -- ^ The total number of bytes in the Data Format Descriptor including the @dfdTotalSize@ field. @dfdByteLength@ must equal @dfdTotalSize@.
  , kvdByteOffset :: Word32 -- ^ An arbitrary number of key/value pairs may follow the Index. These can be used to encode any arbitrary data. The kvdByteOffset field gives the offset of this data, i.e. that of first key/value pair, from the start of the file. The value must be 0 when kvdByteLength = 0.
  , kvdByteLength :: Word32 -- ^ The total number of bytes of key/value data including all keyAndValueByteLength fields, all keyAndValue fields and all valuePadding fields.
  , sgdByteOffset :: Word64 -- ^ The offset from the start of the file of supercompressionGlobalData. The value must be 0 when sgdByteLength = 0.
  , sgdByteLength :: Word64 -- ^ The number of bytes of supercompressionGlobalData. For supercompression schemes for which no reference is provided in the Global Data Format column of Table 2, “Supercompression Schemes”. the value must be 0.
  } deriving (Eq, Show, Generic)

instance Binary Header where
  get = do
    identifier <- getByteString 12
    if identifier == canonicalIdentifier then
      pure ()
    else
      fail $ "KTX2 identifier mismatch: " <> show identifier

    vkFormat <- getWord32le
    typeSize <- getWord32le
    pixelWidth <- getWord32le
    pixelHeight <- getWord32le
    pixelDepth <- getWord32le
    layerCount <- getWord32le
    faceCount <- getWord32le
    levelCount <- getWord32le
    supercompressionScheme <- getWord32le

    dfdByteOffset <- getWord32le
    dfdByteLength <- getWord32le
    kvdByteOffset <- getWord32le
    kvdByteLength <- getWord32le
    sgdByteOffset <- getWord64le
    sgdByteLength <- getWord64le

    pure Header{..}

  put Header{..} = do
    putByteString canonicalIdentifier

    putWord32le vkFormat
    putWord32le typeSize
    putWord32le pixelWidth
    putWord32le pixelHeight
    putWord32le pixelDepth
    putWord32le layerCount
    putWord32le faceCount
    putWord32le levelCount
    putWord32le supercompressionScheme

    putWord32le dfdByteOffset
    putWord32le dfdByteLength
    putWord32le kvdByteOffset
    putWord32le kvdByteLength
    putWord64le sgdByteOffset
    putWord64le sgdByteLength

canonicalIdentifier :: ByteString
canonicalIdentifier = BS.pack
  [ 0xAB, 0x4B, 0x54, 0x58, 0x20, 0x32, 0x30 -- «KTX 20»
  , 0xBB, 0x0D, 0x0A, 0x1A, 0x0A             -- \r\n\x1A\n
  ]

pattern SC_NONE :: (Eq a, Num a) => a
pattern SC_NONE = 0

pattern SC_BASISLZ :: (Eq a, Num a) => a
pattern SC_BASISLZ = 1

pattern SC_ZSTANDARD :: (Eq a, Num a) => a
pattern SC_ZSTANDARD = 2

pattern SC_ZLIB :: (Eq a, Num a) => a
pattern SC_ZLIB = 3