module Rattletrap.Primitive.Vector where

import Rattletrap.Primitive.CompressedWord

import qualified Data.Binary.Bits.Get as BinaryBit
import qualified Data.Binary.Bits.Put as BinaryBit

data Vector = Vector
  { vectorBias :: Word
  , vectorX :: Int
  , vectorY :: Int
  , vectorZ :: Int
  } deriving (Eq, Ord, Show)

getVector :: BinaryBit.BitGet Vector
getVector = do
  bitSize <- getCompressedWord 19
  let limit = 2 ^ (compressedWordValue bitSize + 2)
  dx <- getCompressedWord limit
  dy <- getCompressedWord limit
  dz <- getCompressedWord limit
  let fromCompressedWord x = fromIntegral (compressedWordValue x)
  let bias = 2 ^ (fromCompressedWord bitSize + 1 :: Word)
  let x = fromCompressedWord dx - fromIntegral bias
  let y = fromCompressedWord dy - fromIntegral bias
  let z = fromCompressedWord dz - fromIntegral bias
  pure (Vector bias x y z)

putVector :: Vector -> BinaryBit.BitPut ()
putVector vector = do
  let bitSize =
        round (logBase (2 :: Float) (fromIntegral (vectorBias vector))) - 1
  putCompressedWord (CompressedWord 19 bitSize)
  let dx = fromIntegral (vectorX vector + fromIntegral (vectorBias vector))
  let dy = fromIntegral (vectorY vector + fromIntegral (vectorBias vector))
  let dz = fromIntegral (vectorZ vector + fromIntegral (vectorBias vector))
  let limit = 2 ^ (bitSize + 2)
  putCompressedWord (CompressedWord limit dx)
  putCompressedWord (CompressedWord limit dy)
  putCompressedWord (CompressedWord limit dz)