packages feed

aeson-tiled-0.0.2.0: src/Data/Tiled/GID.hs

{- | Global Tile IDs

https://doc.mapeditor.org/en/latest/reference/global-tile-ids/

-}

module Data.Tiled.GID where

import Data.Aeson (FromJSON(..), ToJSON(..))
import Data.Bits (Bits(..), (.&.))
import Data.Bool (bool)
import Data.Word (Word32)
import Foreign (Storable(..))
import GHC.Generics (Generic)

newtype GID = GID { getGID :: Word32 }
  deriving (Eq, Show, Generic)
  deriving newtype (FromJSON, ToJSON, Storable, Bits)

pattern FLIPPED_HORIZONTALLY_BIT :: Int
pattern FLIPPED_HORIZONTALLY_BIT = 32

pattern FLIPPED_VERTICALLY_BIT :: Int
pattern FLIPPED_VERTICALLY_BIT = 31

pattern ROTATED_60_BIT :: Int
pattern ROTATED_60_BIT = 30

pattern ROTATED_120_BIT :: Int
pattern ROTATED_120_BIT = 29

data Flags = Flags
  { flippedHorizontally :: Bool
  , flippedVertically   :: Bool
  , rotated60           :: Bool
  , rotated120          :: Bool
  } deriving (Eq, Show, Generic)

flags :: GID -> Flags
flags (GID bits) = Flags
  { flippedHorizontally = testBit bits FLIPPED_HORIZONTALLY_BIT
  , flippedVertically   = testBit bits FLIPPED_VERTICALLY_BIT
  , rotated60           = testBit bits ROTATED_60_BIT
  , rotated120          = testBit bits ROTATED_120_BIT
  }

flagBits :: Word32
flagBits =
  bit FLIPPED_HORIZONTALLY_BIT .|.
  bit FLIPPED_VERTICALLY_BIT .|.
  bit ROTATED_60_BIT .|.
  bit ROTATED_120_BIT

toLocal :: GID -> Int
toLocal (GID bits) = fromIntegral $ bits .&. complement flagBits

fromLocal :: Flags -> Int -> GID
fromLocal Flags{..} localId =
  GID . fromIntegral $
    localId
    .|. bool 0 FLIPPED_HORIZONTALLY_BIT flippedHorizontally
    .|. bool 0 FLIPPED_VERTICALLY_BIT   flippedVertically
    .|. bool 0 ROTATED_60_BIT           rotated60
    .|. bool 0 ROTATED_120_BIT          rotated120