packages feed

wgpu-hs-0.4.0.0: src-internal/WGPU/Internal/Sampler.hs

{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE RecordWildCards #-}
{-# OPTIONS_GHC -Wno-deferred-type-errors #-}

-- |
-- Module      : WGPU.Internal.Sampler
-- Description : Texture sampling.
module WGPU.Internal.Sampler
  ( -- * Types
    Sampler (..),
    AddressMode (..),
    FilterMode (..),
    SamplerDescriptor (..),

    -- * Functions
    createSampler,
  )
where

import Control.Monad.IO.Class (MonadIO, liftIO)
import Data.Text (Text)
import Data.Word (Word16)
import Foreign (nullPtr)
import Foreign.C (CFloat (CFloat))
import WGPU.Internal.Device (Device, deviceInst, wgpuDevice)
import WGPU.Internal.Instance (wgpuHsInstance)
import WGPU.Internal.Memory (ToRaw, evalContT, raw, rawPtr, showWithPtr)
import WGPU.Internal.Multipurpose (CompareFunction)
import WGPU.Raw.Generated.Enum.WGPUAddressMode (WGPUAddressMode)
import qualified WGPU.Raw.Generated.Enum.WGPUAddressMode as WGPUAddressMode
import qualified WGPU.Raw.Generated.Enum.WGPUAddressMode as WPUAddressMode
import WGPU.Raw.Generated.Enum.WGPUFilterMode (WGPUFilterMode)
import qualified WGPU.Raw.Generated.Enum.WGPUFilterMode as WGPUFilterMode
import qualified WGPU.Raw.Generated.Fun as RawFun
import WGPU.Raw.Generated.Struct.WGPUSamplerDescriptor (WGPUSamplerDescriptor)
import qualified WGPU.Raw.Generated.Struct.WGPUSamplerDescriptor as WGPUSamplerDescriptor
import WGPU.Raw.Types (WGPUSampler (WGPUSampler))

-------------------------------------------------------------------------------

-- | Handle to a 'Sampler'.
--
-- A 'Sampler' defines how a pipeline will sample from a 'TextureView'.
-- Samplers define image filters (include anisotropy) and address (wrapping)
-- modes, among other things.
newtype Sampler = Sampler {wgpuSampler :: WGPUSampler}

instance Show Sampler where
  show s =
    let Sampler (WGPUSampler ptr) = s
     in showWithPtr "Sampler" ptr

instance Eq Sampler where
  (==) s1 s2 =
    let Sampler (WGPUSampler s1_ptr) = s1
        Sampler (WGPUSampler s2_ptr) = s2
     in s1_ptr == s2_ptr

instance ToRaw Sampler WGPUSampler where
  raw = pure . wgpuSampler

-------------------------------------------------------------------------------

-- | How edges should be handled in texture addressing.
data AddressMode
  = AddressModeClampToEdge
  | AddressModeRepeat
  | AddressModeMirrorRepeat
  deriving (Eq, Show)

instance ToRaw AddressMode WGPUAddressMode where
  raw am =
    pure $ case am of
      AddressModeClampToEdge -> WPUAddressMode.ClampToEdge
      AddressModeRepeat -> WGPUAddressMode.Repeat
      AddressModeMirrorRepeat -> WGPUAddressMode.MirrorRepeat

-------------------------------------------------------------------------------

-- | Texel mixing mode when sampling between texels.
data FilterMode
  = FilterModeNearest
  | FilterModeLinear
  deriving (Eq, Show)

instance ToRaw FilterMode WGPUFilterMode where
  raw fm =
    pure $ case fm of
      FilterModeNearest -> WGPUFilterMode.Nearest
      FilterModeLinear -> WGPUFilterMode.Linear

-------------------------------------------------------------------------------

-- | Describes a 'Sampler'.
data SamplerDescriptor = SamplerDescriptor
  { samplerLabel :: !Text,
    addressModeU :: !AddressMode,
    addressModeV :: !AddressMode,
    addressModeW :: !AddressMode,
    magFilter :: !FilterMode,
    minFilter :: !FilterMode,
    mipmapFilter :: !FilterMode,
    lodMinClamp :: !Float,
    lodMaxClamp :: !Float,
    samplerCompare :: !CompareFunction,
    maxAnisotropy :: !Word16
  }
  deriving (Eq, Show)

instance ToRaw SamplerDescriptor WGPUSamplerDescriptor where
  raw SamplerDescriptor {..} = do
    label_ptr <- rawPtr samplerLabel
    n_addressModeU <- raw addressModeU
    n_addressModeV <- raw addressModeV
    n_addressModeW <- raw addressModeW
    n_magFilter <- raw magFilter
    n_minFilter <- raw minFilter
    n_mipmapFilter <- raw mipmapFilter
    n_compare <- raw samplerCompare
    pure $
      WGPUSamplerDescriptor.WGPUSamplerDescriptor
        { nextInChain = nullPtr,
          label = label_ptr,
          addressModeU = n_addressModeU,
          addressModeV = n_addressModeV,
          addressModeW = n_addressModeW,
          magFilter = n_magFilter,
          minFilter = n_minFilter,
          mipmapFilter = n_mipmapFilter,
          lodMinClamp = CFloat lodMinClamp,
          lodMaxClamp = CFloat lodMaxClamp,
          compare = n_compare,
          maxAnisotropy = maxAnisotropy
        }

-------------------------------------------------------------------------------

-- | Create a 'Sampler'.
createSampler ::
  MonadIO m =>
  -- | Device for which to create the sampler.
  Device ->
  -- | Description of the sampler to create.
  SamplerDescriptor ->
  -- | Action to create the sampler.
  m Sampler
createSampler device samplerDescriptor = liftIO . evalContT $ do
  let inst = deviceInst device
  samplerDescriptor_ptr <- rawPtr samplerDescriptor
  Sampler
    <$> RawFun.wgpuDeviceCreateSampler
      (wgpuHsInstance inst)
      (wgpuDevice device)
      samplerDescriptor_ptr