module NanoUI.Animatable
  ( Animatable (..)
  ) where

import Data.Word (Word8)
import NanoUI.Types (Color, V2 (..), clamp01, colorA, colorB, colorG, colorR, colorRGBA)

-- Float components for multi-component tweens. Extra components are dropped.
-- Short Color lists pad RGB with 0 and alpha with 1. Other types pad with 0.
class Animatable a where
  toComponents :: a -> [Float]
  fromComponents :: [Float] -> a

instance Animatable Float where
  toComponents :: Float -> [Float]
toComponents Float
v = [Float
v]
  fromComponents :: [Float] -> Float
fromComponents (Float
v : [Float]
_) = Float
v
  fromComponents [] = Float
0

instance Animatable Double where
  toComponents :: Double -> [Float]
toComponents Double
v = [Double -> Float
forall a b. (Real a, Fractional b) => a -> b
realToFrac Double
v]
  fromComponents :: [Float] -> Double
fromComponents (Float
v : [Float]
_) = Float -> Double
forall a b. (Real a, Fractional b) => a -> b
realToFrac Float
v
  fromComponents [] = Double
0

instance Animatable V2 where
  toComponents :: V2 -> [Float]
toComponents (V2 Float
x Float
y) = [Float
x, Float
y]
  fromComponents :: [Float] -> V2
fromComponents (Float
x : Float
y : [Float]
_) = Float -> Float -> V2
V2 Float
x Float
y
  fromComponents [Float
x] = Float -> Float -> V2
V2 Float
x Float
0
  fromComponents [] = Float -> Float -> V2
V2 Float
0 Float
0

instance Animatable Color where
  toComponents :: Color -> [Float]
toComponents Color
c =
    [Word8 -> Float
chan (Color -> Word8
colorR Color
c), Word8 -> Float
chan (Color -> Word8
colorG Color
c), Word8 -> Float
chan (Color -> Word8
colorB Color
c), Word8 -> Float
chan (Color -> Word8
colorA Color
c)]
  fromComponents :: [Float] -> Color
fromComponents (Float
r : Float
g : Float
b : Float
a : [Float]
_) =
    Word8 -> Word8 -> Word8 -> Word8 -> Color
colorRGBA (Float -> Word8
byte Float
r) (Float -> Word8
byte Float
g) (Float -> Word8
byte Float
b) (Float -> Word8
byte Float
a)
  fromComponents [Float]
xs = [Float] -> Color
forall a. Animatable a => [Float] -> a
fromComponents (Int -> [Float] -> [Float]
forall a. Int -> [a] -> [a]
take Int
3 ([Float]
xs [Float] -> [Float] -> [Float]
forall a. [a] -> [a] -> [a]
++ Float -> [Float]
forall a. a -> [a]
repeat Float
0) [Float] -> [Float] -> [Float]
forall a. [a] -> [a] -> [a]
++ [Float
1])

chan :: Word8 -> Float
chan :: Word8 -> Float
chan Word8
w = Word8 -> Float
forall a b. (Integral a, Num b) => a -> b
fromIntegral Word8
w Float -> Float -> Float
forall a. Fractional a => a -> a -> a
/ Float
255

byte :: Float -> Word8
byte :: Float -> Word8
byte Float
x = Int -> Word8
forall a b. (Integral a, Num b) => a -> b
fromIntegral (Float -> Int
forall b. Integral b => Float -> b
forall a b. (RealFrac a, Integral b) => a -> b
round (Float -> Float
clamp01 Float
x Float -> Float -> Float
forall a. Num a => a -> a -> a
* Float
255) :: Int)