packages feed

ktx-codec-0.0.2.1: src/Codec/Ktx2/Level.hs

module Codec.Ktx2.Level where

import Data.Binary (Binary(..))
import Data.Binary.Get (getWord64le)
import Data.Binary.Put (putWord64le)
import Data.ByteString (ByteString)
import Data.ByteString qualified as BS
import Data.List (mapAccumR)
import Data.Maybe (fromMaybe)
import Data.Vector (Vector)
import Data.Vector qualified as Vector
import Data.Word (Word64)
import GHC.Generics (Generic)

data Level = Level
  { byteOffset             :: Word64 -- ^ The offset from the start of the file of the first byte of image data for mip level. It is the offset of the first byte after any @mipPadding@.
  , byteLength             :: Word64 -- ^ The total size of the data for supercompressed mip level.
  , uncompressedByteLength :: Word64 -- ^ the number of bytes of pixel data in LOD level after reflation from supercompression. This includes all z slices, all faces, all rows (or rows of blocks) and all pixels (or blocks) in each row for the mipmap level. When @supercompressionScheme == 0@, @byteLength@ must have the same value as this. When @supercompressionScheme == 1@ (BasisLZ) the value must be 0.
  } deriving (Eq, Show, Generic)

instance Binary Level where
  get = do
    byteOffset <- getWord64le
    byteLength <- getWord64le
    uncompressedByteLength <- getWord64le
    pure Level{..}

  put Level{..} = do
    putWord64le byteOffset
    putWord64le byteLength
    putWord64le uncompressedByteLength

-- | Build a level index from level data.
--
-- Levels should be placed from largest (mip 0) to smallest.
index :: Word64 -> [(Maybe Word64, ByteString)] -> Vector Level
index startOffset = Vector.fromList . snd . mapAccumR mkIndex startOffset
  where
    mkIndex byteOffset (uncompressed, bytes) =
      ( byteOffset + byteLength
      , Level{..}
      )
      where
        byteLength = fromIntegral $ BS.length bytes
        uncompressedByteLength = fromMaybe byteLength uncompressed