never executed always true always false
    1 {-|
    2 Module: Flaw.Graphics.Texture
    3 Description: Abstract texture things.
    4 License: MIT
    5 -}
    6 
    7 {-# LANGUAGE DeriveGeneric #-}
    8 
    9 module Flaw.Graphics.Texture
   10   ( TextureFormat(..)
   11   , PixelComponents(..)
   12   , PixelValueType(..)
   13   , PixelSize(..)
   14   , TextureCompression(..)
   15   , ColorSpace(..)
   16   , TextureInfo(..)
   17   , TextureMetrics(..)
   18   , TextureMipMetrics(..)
   19   , calcTextureMetrics
   20   , pixelSizeByteSize
   21   , compressed4x4BlockSize
   22   ) where
   23 
   24 import Data.Bits
   25 import qualified Data.Serialize as S
   26 import GHC.Generics(Generic)
   27 
   28 -- | Texture formats.
   29 data TextureFormat
   30   = UncompressedTextureFormat
   31     { textureFormatComponents :: !PixelComponents
   32     , textureFormatValueType :: !PixelValueType
   33     , textureFormatPixelSize :: !PixelSize
   34     , textureFormatColorSpace :: !ColorSpace
   35     }
   36   | CompressedTextureFormat
   37     { textureFormatCompression :: !TextureCompression
   38     , textureFormatColorSpace :: !ColorSpace
   39     }
   40   deriving (Eq, Generic, Show)
   41 
   42 instance S.Serialize TextureFormat
   43 
   44 -- | Pixel components for texture format.
   45 data PixelComponents
   46   = PixelR
   47   | PixelRG
   48   | PixelRGB
   49   | PixelRGBA
   50   deriving (Eq, Generic, Show)
   51 
   52 instance S.Serialize PixelComponents
   53 
   54 -- | Pixel value type.
   55 data PixelValueType
   56   = PixelUntyped
   57   | PixelUint
   58   | PixelFloat
   59   deriving (Eq, Generic, Show)
   60 
   61 instance S.Serialize PixelValueType
   62 
   63 -- | Pixel size.
   64 data PixelSize
   65   = Pixel8bit
   66   | Pixel16bit
   67   | Pixel24bit
   68   | Pixel32bit
   69   | Pixel64bit
   70   | Pixel96bit
   71   | Pixel128bit
   72   deriving (Eq, Ord, Generic, Show)
   73 
   74 instance S.Serialize PixelSize
   75 
   76 -- | Texture compression.
   77 -- Sizes in descriptions are given for 4x4 pixel blocks (obviously).
   78 data TextureCompression
   79   -- | RGB (64 bit, two 5:6:5 values and 4x4 2-bit lookup table).
   80   -- Another name: DXT1
   81   = TextureCompressionBC1
   82   -- | RGB (64 bit, two 5:6:5 values and 4x4 2-bit lookup table,
   83   -- with one of the colors in table replaced by transparent color).
   84   -- Another name: DXT1
   85   | TextureCompressionBC1Alpha
   86   -- | RGB (64 bit, same as in BC1) plus alpha (64 bit, i.e. 4 uncompressed bit per pixel)
   87   -- Another names: DXT2 - when color is premultiplied by alpha, DXT3 otherwise.
   88   | TextureCompressionBC2
   89   -- | RGB (64 bit, same as in BC1) plus alpha (64 bit, two 8-bit values plus 4x4 3-bit lookup table).
   90   -- Another names: DXT4 - when color is premultiplied by alpha, DXT5 otherwise.
   91   | TextureCompressionBC3
   92   -- | R (64 bit, two 8-bit values plus 4x4 3-bit lookup table).
   93   | TextureCompressionBC4
   94   -- | R signed (64 bit, two 8-bit values plus 4x4 3-bit lookup table).
   95   | TextureCompressionBC4Signed
   96   -- | RG (128 bit, simply two BC4 blocks)
   97   | TextureCompressionBC5
   98   -- | RG signed (128 bit, simply two BC4 blocks)
   99   | TextureCompressionBC5Signed
  100   deriving (Eq, Generic, Show)
  101 
  102 instance S.Serialize TextureCompression
  103 
  104 -- | Color space.
  105 data ColorSpace
  106   = LinearColorSpace
  107   | StandardColorSpace
  108   deriving (Eq, Generic, Show)
  109 
  110 instance S.Serialize ColorSpace
  111 
  112 -- | Texture information.
  113 {- Acceptable combinations:
  114 width height depth
  115 W     0      0      1D texture with width W
  116 W     1      0      2D texture Wx1
  117 W     H      0      2D texture WxH
  118 W     H      1      3D texture WxHx1
  119 W     H      L      3D texture WxHxL
  120 -}
  121 data TextureInfo = TextureInfo
  122   { textureWidth :: {-# UNPACK #-} !Int
  123   , textureHeight :: {-# UNPACK #-} !Int
  124   , textureDepth :: {-# UNPACK #-} !Int
  125   -- | Number of MIP levels, should be >= 1.
  126   , textureMips :: {-# UNPACK #-} !Int
  127   , textureFormat :: !TextureFormat
  128   -- | Number of textures in array.
  129   -- Zero means non-array.
  130   , textureCount :: {-# UNPACK #-} !Int
  131   } deriving (Generic, Show)
  132 
  133 instance S.Serialize TextureInfo
  134 
  135 -- | Various byte metrics of texture.
  136 data TextureMetrics = TextureMetrics
  137   {
  138   -- | Size of one image in array.
  139     textureImageSize :: {-# UNPACK #-} !Int
  140   -- | Byte offsets from the beginning of image to mip levels.
  141   , textureMipsMetrics :: [TextureMipMetrics]
  142   }
  143 
  144 -- | Various byte metrics of texture mip level.
  145 -- All numbers >= 1, like even for 1D texture height is 1,
  146 -- as opposite to 0 in TextureInfo.
  147 data TextureMipMetrics = TextureMipMetrics
  148   {
  149   -- | Number of pixels in a row.
  150     textureMipWidth :: {-# UNPACK #-} !Int
  151   -- | Number of lines. >= 1.
  152   , textureMipHeight :: {-# UNPACK #-} !Int
  153   -- | Number of slices. >= 1.
  154   , textureMipDepth :: {-# UNPACK #-} !Int
  155   -- | Byte length of one line.
  156   -- In case of compressed textures (4x4 blocks coded),
  157   -- it's a size of one line of 4x4 blocks.
  158   , textureMipLinePitch :: {-# UNPACK #-} !Int
  159   -- | Byte length of 2D slice.
  160   , textureMipSlicePitch :: {-# UNPACK #-} !Int
  161   -- | Byte offset to mip data from the beginning of an image.
  162   , textureMipOffset :: {-# UNPACK #-} !Int
  163   -- | Byte size of mip.
  164   , textureMipSize :: {-# UNPACK #-} !Int
  165   }
  166 
  167 -- | Calculate byte metrics for texture.
  168 calcTextureMetrics :: TextureInfo -> TextureMetrics
  169 calcTextureMetrics TextureInfo
  170   { textureWidth = width
  171   , textureHeight = height
  172   , textureDepth = depth
  173   , textureMips = mips
  174   , textureFormat = format
  175   } = tm where
  176   tm = TextureMetrics
  177     { textureImageSize = sum $ map textureMipSize mm
  178     , textureMipsMetrics = mm
  179     }
  180   mm = calcMipMetrics 0 0
  181   calcMipMetrics mip prevOffset = mipMetrics where
  182     mipMetrics = if mip >= mips then [] else TextureMipMetrics
  183       { textureMipWidth = mipWidth
  184       , textureMipHeight = mipHeight
  185       , textureMipDepth = mipDepth
  186       , textureMipLinePitch = mipLinePitch
  187       , textureMipSlicePitch = mipSlicePitch
  188       , textureMipOffset = prevOffset
  189       , textureMipSize = mipSize
  190       } : calcMipMetrics (mip + 1) nextOffset
  191     mipWidth = max 1 $ width `shiftR` mip
  192     mipHeight = max 1 $ height `shiftR` mip
  193     mipDepth = max 1 $ depth `shiftR` mip
  194     mipLinePitch = case format of
  195       UncompressedTextureFormat
  196         { textureFormatPixelSize = ps
  197         } -> mipWidth * pixelSizeByteSize ps
  198       CompressedTextureFormat
  199         { textureFormatCompression = c
  200         } -> ((mipWidth + 3) `shiftR` 2) * compressed4x4BlockSize c
  201     mipSlicePitch = case format of
  202       UncompressedTextureFormat {} -> mipHeight * mipLinePitch
  203       CompressedTextureFormat {} -> ((mipHeight + 3) `shiftR` 2) * mipLinePitch
  204     mipSize = mipDepth * mipSlicePitch
  205     nextOffset = prevOffset + mipSize
  206 
  207 -- | Convert PixelSize to actual number of bytes.
  208 pixelSizeByteSize :: PixelSize -> Int
  209 pixelSizeByteSize ps = case ps of
  210   Pixel8bit -> 1
  211   Pixel16bit -> 2
  212   Pixel24bit -> 3
  213   Pixel32bit -> 4
  214   Pixel64bit -> 8
  215   Pixel96bit -> 12
  216   Pixel128bit -> 16
  217 
  218 -- | Get size of 4x4 compressed pixel block.
  219 compressed4x4BlockSize :: TextureCompression -> Int
  220 compressed4x4BlockSize c = case c of
  221   TextureCompressionBC1 -> 8
  222   TextureCompressionBC1Alpha -> 8
  223   TextureCompressionBC2 -> 16
  224   TextureCompressionBC3 -> 16
  225   TextureCompressionBC4 -> 8
  226   TextureCompressionBC4Signed -> 8
  227   TextureCompressionBC5 -> 16
  228   TextureCompressionBC5Signed -> 16