module Resource.Image.Atlas
  ( Atlas(..)
  , fromTileSize
  , fromImageSize
  ) where

import RIO

import Geomancy (UVec2, Vec2, uvec2, withUVec2, vec2)

-- | Regular grid atlas
data Atlas = Atlas
  { Atlas -> UVec2
sizeTiles  :: UVec2
  , Atlas -> UVec2
sizePx     :: UVec2
  , Atlas -> UVec2
tileSizePx :: UVec2
  , Atlas -> UVec2
marginPx   :: UVec2
  , Atlas -> Vec2
uvScale    :: Vec2
  }
  deriving (Atlas -> Atlas -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: Atlas -> Atlas -> Bool
$c/= :: Atlas -> Atlas -> Bool
== :: Atlas -> Atlas -> Bool
$c== :: Atlas -> Atlas -> Bool
Eq, Int -> Atlas -> ShowS
[Atlas] -> ShowS
Atlas -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Atlas] -> ShowS
$cshowList :: [Atlas] -> ShowS
show :: Atlas -> String
$cshow :: Atlas -> String
showsPrec :: Int -> Atlas -> ShowS
$cshowsPrec :: Int -> Atlas -> ShowS
Show, forall x. Rep Atlas x -> Atlas
forall x. Atlas -> Rep Atlas x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep Atlas x -> Atlas
$cfrom :: forall x. Atlas -> Rep Atlas x
Generic)

fromTileSize :: UVec2 -> UVec2 -> UVec2 -> Atlas
fromTileSize :: UVec2 -> UVec2 -> UVec2 -> Atlas
fromTileSize UVec2
sizeTiles UVec2
tileSizePx UVec2
marginPx = Atlas{UVec2
Vec2
uvScale :: Vec2
sizePx :: UVec2
marginPx :: UVec2
tileSizePx :: UVec2
sizeTiles :: UVec2
$sel:uvScale:Atlas :: Vec2
$sel:marginPx:Atlas :: UVec2
$sel:tileSizePx:Atlas :: UVec2
$sel:sizePx:Atlas :: UVec2
$sel:sizeTiles:Atlas :: UVec2
..}
  where
    sizePx :: UVec2
sizePx = UVec2
sizeTiles forall a. Num a => a -> a -> a
* UVec2
tileSizePx forall a. Num a => a -> a -> a
+ (UVec2
sizeTiles forall a. Num a => a -> a -> a
- UVec2
1) forall a. Num a => a -> a -> a
* UVec2
marginPx
    uvScale :: Vec2
uvScale = UVec2 -> Vec2
fromU UVec2
tileSizePx forall a. Fractional a => a -> a -> a
/ UVec2 -> Vec2
fromU UVec2
sizePx

fromImageSize :: UVec2 -> UVec2 -> UVec2 -> Either UVec2 Atlas
fromImageSize :: UVec2 -> UVec2 -> UVec2 -> Either UVec2 Atlas
fromImageSize UVec2
sizePx UVec2
tileSizePx UVec2
marginPx =
  if UVec2
leftovers forall a. Eq a => a -> a -> Bool
== UVec2
totalMargins then
    forall a b. b -> Either a b
Right Atlas{UVec2
Vec2
uvScale :: Vec2
sizeTiles :: UVec2
marginPx :: UVec2
tileSizePx :: UVec2
sizePx :: UVec2
$sel:uvScale:Atlas :: Vec2
$sel:marginPx:Atlas :: UVec2
$sel:tileSizePx:Atlas :: UVec2
$sel:sizePx:Atlas :: UVec2
$sel:sizeTiles:Atlas :: UVec2
..}
  else
    forall a b. a -> Either a b
Left UVec2
leftovers
  where
    totalMargins :: UVec2
totalMargins = (UVec2
sizeTiles forall a. Num a => a -> a -> a
- UVec2
1) forall a. Num a => a -> a -> a
* UVec2
marginPx

    (UVec2
sizeTiles, UVec2
leftovers) =
      forall r. UVec2 -> (Word32 -> Word32 -> r) -> r
withUVec2 UVec2
sizePx \Word32
aw Word32
ah ->
      forall r. UVec2 -> (Word32 -> Word32 -> r) -> r
withUVec2 UVec2
tileSizePx \Word32
tw Word32
th ->
        let
          (Word32
w, Word32
wRem) = Word32
aw forall a. Integral a => a -> a -> (a, a)
`divMod` Word32
tw
          (Word32
h, Word32
hRem) = Word32
ah forall a. Integral a => a -> a -> (a, a)
`divMod` Word32
th
        in
          ( Word32 -> Word32 -> UVec2
uvec2 Word32
w Word32
h
          , Word32 -> Word32 -> UVec2
uvec2 Word32
wRem Word32
hRem
          )

    uvScale :: Vec2
uvScale = UVec2 -> Vec2
fromU UVec2
tileSizePx forall a. Fractional a => a -> a -> a
/ UVec2 -> Vec2
fromU UVec2
sizePx

fromU :: UVec2 -> Vec2
fromU :: UVec2 -> Vec2
fromU UVec2
u =
  forall r. UVec2 -> (Word32 -> Word32 -> r) -> r
withUVec2 UVec2
u \Word32
x Word32
y ->
    Float -> Float -> Vec2
vec2 (forall a b. (Integral a, Num b) => a -> b
fromIntegral Word32
x) (forall a b. (Integral a, Num b) => a -> b
fromIntegral Word32
y)