packages feed

ktx-codec-0.0.2.1: src/Codec/Ktx2/DFD/Khronos/BasicV2.hs

module Codec.Ktx2.DFD.Khronos.BasicV2 where

import Data.Binary (Binary(..))
import Data.Binary.Get (Get, getWord8, getWord16le, getWord32le, runGetOrFail)
import Data.Binary.Put (PutM, putWord8, putWord16le, putWord32le, runPut)
import Data.ByteString qualified as BS
import Data.ByteString.Lazy qualified as BSL
import Data.ByteString.Lazy qualified as LBS
import Data.Vector (Vector)
import Data.Vector qualified as Vector
import Data.Word (Word8, Word16, Word32)
import GHC.Generics (Generic)

import Codec.Ktx2.DFD qualified as DFD

-- | Khronos
pattern VENDOR_ID :: (Eq a, Num a) => a
pattern VENDOR_ID = 0

-- | Basic DFD Block
pattern DESCRIPTOR_TYPE :: (Eq a, Num a) => a
pattern DESCRIPTOR_TYPE = 0

-- | KDF v1.3
pattern VERSION :: (Eq a, Num a) => a
pattern VERSION = 2

{- |
  A basic descriptor block is designed to encode common metadata associated with bulk data — especially image or texture data.

  While this descriptor holds more information about the data interpretation than is needed by many applications,
  a comprehensive encoding reduces the risk of metadata needed by different APIs being lost in translation.

  The format is described in terms of a repeating axis-aligned texel block composed of samples.
  Each sample contains a single channel of information with a single spatial offset within the texel block,
  and consists of an amount of contiguous data. This descriptor block consists of information about the interpretation
  of the texel block as a whole, supplemented by a description of a number of samples taken from one or more planes of contiguous memory.

  <https://registry.khronos.org/DataFormat/specs/1.3/dataformat.1.3.html>
-}
data BasicV2 = BasicV2
  { colorModel :: Word8
  , colorPrimaries :: Word8
  , transferFunction :: Word8
  , flags :: Word8

  , texelBlockDimension0 :: Word8
    {- ^
      The value held in each of these fields is one fewer than the size of the block in that dimension — 
      that is, a value of 0 represents a size of 1, a value of 1 represents a size of 2, etc.

      A texel block which covers fewer than four dimensions should have a size of 1 in each dimension
      that it lacks, and therefore the corresponding fields in the representation should be 0.
    -}
  , texelBlockDimension1 :: Word8
  , texelBlockDimension2 :: Word8
  , texelBlockDimension3 :: Word8

  , bytesPlane0 :: Word8
  , bytesPlane1 :: Word8
  , bytesPlane2 :: Word8
  , bytesPlane3 :: Word8
  , bytesPlane4 :: Word8
  , bytesPlane5 :: Word8
  , bytesPlane6 :: Word8
  , bytesPlane7 :: Word8

  , samples :: Vector Sample
  }
  deriving (Eq, Show, Generic)

getter :: Int -> Get BasicV2
getter numSamples = do
  colorModel <- getWord8
  colorPrimaries <- getWord8
  transferFunction <- getWord8
  flags <- getWord8

  texelBlockDimension0 <- fmap (+ 1) getWord8
  texelBlockDimension1 <- fmap (+ 1) getWord8
  texelBlockDimension2 <- fmap (+ 1) getWord8
  texelBlockDimension3 <- fmap (+ 1) getWord8

  bytesPlane0 <- getWord8
  bytesPlane1 <- getWord8
  bytesPlane2 <- getWord8
  bytesPlane3 <- getWord8
  bytesPlane4 <- getWord8
  bytesPlane5 <- getWord8
  bytesPlane6 <- getWord8
  bytesPlane7 <- getWord8

  samples <- Vector.replicateM numSamples get

  pure BasicV2{..}

putter :: BasicV2 -> PutM ()
putter BasicV2{..} = do
  putWord8 colorModel
  putWord8 colorPrimaries
  putWord8 transferFunction
  putWord8 flags

  putWord8 $ texelBlockDimension0 - 1
  putWord8 $ texelBlockDimension1 - 1
  putWord8 $ texelBlockDimension2 - 1
  putWord8 $ texelBlockDimension3 - 1

  putWord8 bytesPlane0
  putWord8 bytesPlane1
  putWord8 bytesPlane2
  putWord8 bytesPlane3
  putWord8 bytesPlane4
  putWord8 bytesPlane5
  putWord8 bytesPlane6
  putWord8 bytesPlane7

  Vector.mapM_ put samples

data Sample = Sample
  { bitOffset :: Word16
  , bitLength :: Word8
  , channelType :: Word8

  , samplePosition0 :: Word8
  , samplePosition1 :: Word8
  , samplePosition2 :: Word8
  , samplePosition3 :: Word8

  , sampleLower :: Word32
  , sampleUpper :: Word32
  }
  deriving (Eq, Show, Generic)

instance Binary Sample where
  get = do
    bitOffset <- getWord16le
    bitLength <- fmap (+1) getWord8
    channelType <- getWord8

    samplePosition0 <- getWord8
    samplePosition1 <- getWord8
    samplePosition2 <- getWord8
    samplePosition3 <- getWord8

    sampleLower <- getWord32le
    sampleUpper <- getWord32le

    pure Sample{..}

  put Sample{..} = do
    putWord16le bitOffset
    putWord8 $ bitLength - 1
    putWord8 channelType

    putWord8 samplePosition0
    putWord8 samplePosition1
    putWord8 samplePosition2
    putWord8 samplePosition3

    putWord32le sampleLower
    putWord32le sampleUpper

fromBlock :: DFD.Block -> Maybe BasicV2
fromBlock DFD.Block{descriptorBlockSize, body} =
  case runGetOrFail (getter numSamples) (LBS.fromChunks [body]) of
    Left _err ->
      Nothing
    Right (_bytes, _offset, ok) ->
      Just ok
  where
    numSamples =
      div (fromIntegral descriptorBlockSize - 24) 16

toBlock :: BasicV2 -> DFD.Block
toBlock v2 =
  DFD.Block
    { descriptorType =
        DESCRIPTOR_TYPE
    , vendorId =
        VENDOR_ID
    , versionNumber =
        VERSION
    , descriptorBlockSize =
        fromIntegral $ BS.length body + 8
    , body =
        body
    }
  where
    body = BSL.toStrict . runPut $ putter v2

-- * Constructors

unspecified :: BasicV2
unspecified = BasicV2
  { colorModel = KHR_DF_MODEL_UNSPECIFIED
  , colorPrimaries = KHR_DF_PRIMARIES_UNSPECIFIED
  , transferFunction = KHR_DF_TRANSFER_LINEAR
  , flags = KHR_DF_FLAG_ALPHA_STRAIGHT
  , texelBlockDimension0 = 1
  , texelBlockDimension1 = 1
  , texelBlockDimension2 = 1
  , texelBlockDimension3 = 1
  , bytesPlane0 = 0
  , bytesPlane1 = 0
  , bytesPlane2 = 0
  , bytesPlane3 = 0
  , bytesPlane4 = 0
  , bytesPlane5 = 0
  , bytesPlane6 = 0
  , bytesPlane7 = 0
  , samples = mempty
  }

-- * Patterns

pattern KHR_DF_MODEL_UNSPECIFIED :: Word8
pattern KHR_DF_MODEL_UNSPECIFIED = 0

pattern KHR_DF_MODEL_RGBSDA :: Word8
pattern KHR_DF_MODEL_RGBSDA = 1

pattern KHR_DF_MODEL_YUVSDA :: Word8
pattern KHR_DF_MODEL_YUVSDA = 2

pattern KHR_DF_MODEL_YIQSDA :: Word8
pattern KHR_DF_MODEL_YIQSDA = 3

pattern KHR_DF_MODEL_LABSDA :: Word8
pattern KHR_DF_MODEL_LABSDA = 4

pattern KHR_DF_MODEL_CMYKA :: Word8
pattern KHR_DF_MODEL_CMYKA = 5

pattern KHR_DF_MODEL_XYZW :: Word8
pattern KHR_DF_MODEL_XYZW = 6

pattern KHR_DF_MODEL_HSVA_ANG :: Word8
pattern KHR_DF_MODEL_HSVA_ANG = 7

pattern KHR_DF_MODEL_HSLA_ANG :: Word8
pattern KHR_DF_MODEL_HSLA_ANG = 8

pattern KHR_DF_MODEL_HSVA_HEX :: Word8
pattern KHR_DF_MODEL_HSVA_HEX = 9

pattern KHR_DF_MODEL_HSLA_HEX :: Word8
pattern KHR_DF_MODEL_HSLA_HEX = 10

pattern KHR_DF_MODEL_YCGCOA :: Word8
pattern KHR_DF_MODEL_YCGCOA = 11

pattern KHR_DF_MODEL_YCCBCCRC :: Word8
pattern KHR_DF_MODEL_YCCBCCRC = 12

pattern KHR_DF_MODEL_ICTCP :: Word8
pattern KHR_DF_MODEL_ICTCP = 13

pattern KHR_DF_MODEL_CIEXYZ :: Word8
pattern KHR_DF_MODEL_CIEXYZ = 14

pattern KHR_DF_MODEL_CIEXYY :: Word8
pattern KHR_DF_MODEL_CIEXYY = 15

-- *** Compressed formats

pattern KHR_DF_MODEL_DXT1A :: Word8
pattern KHR_DF_MODEL_DXT1A = 128

pattern KHR_DF_MODEL_BC1A :: Word8
pattern KHR_DF_MODEL_BC1A = KHR_DF_MODEL_DXT1A

pattern KHR_DF_MODEL_DXT2 :: Word8
pattern KHR_DF_MODEL_DXT2 = 129

pattern KHR_DF_MODEL_DXT3 :: Word8
pattern KHR_DF_MODEL_DXT3 = KHR_DF_MODEL_DXT2

pattern KHR_DF_MODEL_BC2 :: Word8
pattern KHR_DF_MODEL_BC2 = KHR_DF_MODEL_DXT2

pattern KHR_DF_MODEL_DXT4 :: Word8
pattern KHR_DF_MODEL_DXT4 = 130

pattern KHR_DF_MODEL_DXT5 :: Word8
pattern KHR_DF_MODEL_DXT5 = KHR_DF_MODEL_DXT4

pattern KHR_DF_MODEL_BC3 :: Word8
pattern KHR_DF_MODEL_BC3 = KHR_DF_MODEL_DXT4

pattern KHR_DF_MODEL_BC4 :: Word8
pattern KHR_DF_MODEL_BC4 = 131

pattern KHR_DF_MODEL_BC5 :: Word8
pattern KHR_DF_MODEL_BC5 = 132

pattern KHR_DF_MODEL_BC6H :: Word8
pattern KHR_DF_MODEL_BC6H = 133

pattern KHR_DF_MODEL_BC7 :: Word8
pattern KHR_DF_MODEL_BC7 = 134


pattern KHR_DF_MODEL_ETC1 :: Word8
pattern KHR_DF_MODEL_ETC1 = 160

pattern KHR_DF_MODEL_ETC2 :: Word8
pattern KHR_DF_MODEL_ETC2 = 161

pattern KHR_DF_MODEL_ASTC2 :: Word8
pattern KHR_DF_MODEL_ASTC2 = 162

pattern KHR_DF_MODEL_ETC1S :: Word8
pattern KHR_DF_MODEL_ETC1S = 163

pattern KHR_DF_MODEL_PVRTC :: Word8
pattern KHR_DF_MODEL_PVRTC = 164

pattern KHR_DF_MODEL_PVRTC2 :: Word8
pattern KHR_DF_MODEL_PVRTC2 = 165

-- ** Color primaries

pattern KHR_DF_PRIMARIES_UNSPECIFIED :: Word8
pattern KHR_DF_PRIMARIES_UNSPECIFIED = 0

pattern KHR_DF_PRIMARIES_BT709 :: Word8
pattern KHR_DF_PRIMARIES_BT709 = 1

pattern KHR_DF_PRIMARIES_SRGB :: Word8
pattern KHR_DF_PRIMARIES_SRGB = KHR_DF_PRIMARIES_BT709

pattern KHR_DF_PRIMARIES_BT601_EBU :: Word8
pattern KHR_DF_PRIMARIES_BT601_EBU = 2

pattern KHR_DF_PRIMARIES_BT601_SMPTE :: Word8
pattern KHR_DF_PRIMARIES_BT601_SMPTE = 3

pattern KHR_DF_PRIMARIES_BT2020 :: Word8
pattern KHR_DF_PRIMARIES_BT2020 = 4

pattern KHR_DF_PRIMARIES_CIEXYZ :: Word8
pattern KHR_DF_PRIMARIES_CIEXYZ = 5

pattern KHR_DF_PRIMARIES_ACES :: Word8
pattern KHR_DF_PRIMARIES_ACES = 6

pattern KHR_DF_PRIMARIES_ACESCC :: Word8
pattern KHR_DF_PRIMARIES_ACESCC = 7

pattern KHR_DF_PRIMARIES_NTSC1953 :: Word8
pattern KHR_DF_PRIMARIES_NTSC1953 = 8

pattern KHR_DF_PRIMARIES_PAL525 :: Word8
pattern KHR_DF_PRIMARIES_PAL525 = 9

pattern KHR_DF_PRIMARIES_DISPLAYP3 :: Word8
pattern KHR_DF_PRIMARIES_DISPLAYP3 = 10

pattern KHR_DF_PRIMARIES_ADOBERGB :: Word8
pattern KHR_DF_PRIMARIES_ADOBERGB = 11

-- ** Transfer functions

pattern KHR_DF_TRANSFER_UNSPECIFIED :: Word8
pattern KHR_DF_TRANSFER_UNSPECIFIED = 0

pattern KHR_DF_TRANSFER_LINEAR :: Word8
pattern KHR_DF_TRANSFER_LINEAR = 1

pattern KHR_DF_TRANSFER_SRGB :: Word8
pattern KHR_DF_TRANSFER_SRGB = 2

pattern KHR_DF_TRANSFER_ITU :: Word8
pattern KHR_DF_TRANSFER_ITU = 3

pattern KHR_DF_TRANSFER_NTSC :: Word8
pattern KHR_DF_TRANSFER_NTSC = 4

pattern KHR_DF_TRANSFER_SLOG :: Word8
pattern KHR_DF_TRANSFER_SLOG = 5

pattern KHR_DF_TRANSFER_SLOG2 :: Word8
pattern KHR_DF_TRANSFER_SLOG2 = 6

pattern KHR_DF_TRANSFER_BT1886 :: Word8
pattern KHR_DF_TRANSFER_BT1886 = 7

pattern KHR_DF_TRANSFER_HLG_OETF :: Word8
pattern KHR_DF_TRANSFER_HLG_OETF = 8

pattern KHR_DF_TRANSFER_HLG_EOTF :: Word8
pattern KHR_DF_TRANSFER_HLG_EOTF = 9

pattern KHR_DF_TRANSFER_PQ_EOTF :: Word8
pattern KHR_DF_TRANSFER_PQ_EOTF = 10

pattern KHR_DF_TRANSFER_PQ_OETF :: Word8
pattern KHR_DF_TRANSFER_PQ_OETF = 11

pattern KHR_DF_TRANSFER_DCIP3 :: Word8
pattern KHR_DF_TRANSFER_DCIP3 = 12

pattern KHR_DF_TRANSFER_PAL_OETF :: Word8
pattern KHR_DF_TRANSFER_PAL_OETF = 13

pattern KHR_DF_TRANSFER_PAL625_EOTF :: Word8
pattern KHR_DF_TRANSFER_PAL625_EOTF = 14

pattern KHR_DF_TRANSFER_ST240 :: Word8
pattern KHR_DF_TRANSFER_ST240 = 15

pattern KHR_DF_TRANSFER_ACESCC :: Word8
pattern KHR_DF_TRANSFER_ACESCC = 16

pattern KHR_DF_TRANSFER_ACESCCT :: Word8
pattern KHR_DF_TRANSFER_ACESCCT = 17

pattern KHR_DF_TRANSFER_ADOBERGB :: Word8
pattern KHR_DF_TRANSFER_ADOBERGB = 18

-- ** Flags

pattern KHR_DF_FLAG_ALPHA_STRAIGHT :: Word8
pattern KHR_DF_FLAG_ALPHA_STRAIGHT = 0

pattern KHR_DF_FLAG_ALPHA_PREMULTIPLIED :: Word8
pattern KHR_DF_FLAG_ALPHA_PREMULTIPLIED = 1

-- ** Samples

pattern KHR_DF_SAMPLE_DATATYPE_FLOAT :: (Eq a, Num a) => a
pattern KHR_DF_SAMPLE_DATATYPE_FLOAT = 0x80

pattern KHR_DF_SAMPLE_DATATYPE_SIGNED :: (Eq a, Num a) => a
pattern KHR_DF_SAMPLE_DATATYPE_SIGNED = 0x40

pattern KHR_DF_SAMPLE_DATATYPE_EXPONENT :: (Eq a, Num a) => a
pattern KHR_DF_SAMPLE_DATATYPE_EXPONENT = 0x20

pattern KHR_DF_SAMPLE_DATATYPE_LINEAR :: (Eq a, Num a) => a
pattern KHR_DF_SAMPLE_DATATYPE_LINEAR = 0x10