{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE DataKinds #-}
module Util where

import Data.Bits

import qualified Data.Vector as V

import Data.Word (Word32)

import qualified Vulkan as Vk
import qualified Vulkan.CStruct.Extends as Vk
import qualified Vulkan.Zero as Vk

-- internal imports

import Types

getFrame :: EngineData -> Int -> FrameData
getFrame engineData frame =
  let frameVector = engineFrames engineData
  in
    frameVector V.! (frame `mod` V.length frameVector)

padUniformBufferSize
  :: Vk.DeviceSize
  -> Vk.PhysicalDeviceProperties
  -> Vk.DeviceSize
padUniformBufferSize origSize gpuProperties =
  let minUBOAlignment = Vk.minUniformBufferOffsetAlignment $ Vk.limits gpuProperties
      result =
        if minUBOAlignment > 0
        then (origSize + minUBOAlignment - 1) .&. complement (minUBOAlignment - 1)
        else origSize
  in
    -- trace ("padding result: " <> show result) result
    result

descriptorsetLayoutBinding
  :: Vk.DescriptorType
  -> Vk.ShaderStageFlags
  -> Word32
  -> Vk.DescriptorSetLayoutBinding
descriptorsetLayoutBinding type' stageFlags binding =
  Vk.zero
    { Vk.binding           = binding
    , Vk.descriptorCount   = 1
    , Vk.descriptorType    = type'
    , Vk.immutableSamplers = V.empty
    , Vk.stageFlags        = stageFlags
    }

writeDescriptorBuffer
  :: Vk.DescriptorType
  -> Vk.DescriptorSet
  -> Vk.DescriptorBufferInfo
  -> Word32
  -> Vk.SomeStruct Vk.WriteDescriptorSet
writeDescriptorBuffer type' dstSet dBufferInfo binding = Vk.SomeStruct $
  Vk.zero
    { Vk.dstBinding      = binding
    , Vk.dstSet          = dstSet
    , Vk.descriptorCount = 1
    , Vk.descriptorType  = type'
    , Vk.bufferInfo      = V.singleton dBufferInfo
    }

beginCommandBuffer
  :: Vk.CommandBufferUsageFlags
  -> Vk.CommandBufferBeginInfo '[]
beginCommandBuffer flags =
  Vk.zero
    { Vk.flags = flags
    }

createSubmitInfo
  :: Vk.CommandBuffer
  -> V.Vector (Vk.SomeStruct Vk.SubmitInfo)
createSubmitInfo cmd = V.singleton $ Vk.SomeStruct $
  Vk.zero
    { Vk.commandBuffers = V.singleton (Vk.commandBufferHandle cmd)
    }

samplerCreateInfo
  :: Vk.Filter
  -> Vk.SamplerAddressMode
  -> Vk.SamplerCreateInfo '[]
samplerCreateInfo filters addressMode =
  Vk.zero
    { Vk.magFilter = filters
    , Vk.minFilter = filters
    , Vk.addressModeU = addressMode
    , Vk.addressModeV = addressMode
    , Vk.addressModeW = addressMode
    }

writeDescriptorImage
  :: Vk.DescriptorType
  -> Vk.DescriptorSet
  -> Vk.DescriptorImageInfo
  -> Word32
  -> Vk.WriteDescriptorSet '[]
writeDescriptorImage type' set imageInfo binding =
  Vk.zero
    { Vk.dstBinding = binding
    , Vk.dstSet     = set
    , Vk.descriptorCount = 1
    , Vk.descriptorType  = type'
    , Vk.imageInfo       = V.singleton imageInfo
    }
