module Codec.GlTF.Material
  ( MaterialIx(..)
  , Material(..)
  , MaterialAlphaMode(..)
  , pattern OPAQUE
  , pattern MASK
  , pattern BLEND
  , MaterialNormal(..)
  , MaterialOcclusion(..)
  ) where

import Codec.GlTF.Prelude

import Codec.GlTF.PbrMetallicRoughness (PbrMetallicRoughness)
import Codec.GlTF.TextureInfo (TextureInfo, TextureInfo_)

newtype MaterialIx = MaterialIx { unMaterialIx :: Int }
  deriving (Eq, Ord, Show, FromJSON, ToJSON, Generic)

-- | The material appearance of a primitive.
data Material = Material
  { emissiveFactor :: (Float, Float, Float)
  , alphaMode      :: MaterialAlphaMode
  , alphaCutoff    :: Float
  , doubleSided    :: Bool

  , pbrMetallicRoughness :: Maybe PbrMetallicRoughness
  , normalTexture        :: Maybe (TextureInfo MaterialNormal)
  , occlusionTexture     :: Maybe (TextureInfo MaterialOcclusion)
  , emissiveTexture      :: Maybe (TextureInfo_)

  , name         :: Maybe Text
  , extensions   :: Maybe Object
  , extras       :: Maybe Value
  } deriving (Eq, Show, Generic)

instance FromJSON Material where
  parseJSON = withObject "Material" \o -> do
    emissiveFactor       <- o .:? "emissiveFactor" .!= (0, 0, 0)
    alphaMode            <- o .:? "alphaMode"      .!= OPAQUE
    alphaCutoff          <- o .:? "alphaCutoff"    .!= 0.5
    doubleSided          <- o .:? "doubleSided"    .!= False

    pbrMetallicRoughness <- o .:? "pbrMetallicRoughness"
    normalTexture        <- o .:? "normalTexture"
    occlusionTexture     <- o .:? "occlusionTexture"
    emissiveTexture      <- o .:? "emissiveTexture"

    name                 <- o .:? "name"
    extensions           <- o .:? "extensions"
    extras               <- o .:? "extras"
    pure Material{..}

instance ToJSON Material

-- | The alpha rendering mode of the material.
newtype MaterialAlphaMode = MaterialAlphaMode { unMaterialAlphaMode :: Text }
  deriving (Eq, Ord, Show, FromJSON, ToJSON, Generic)

pattern OPAQUE :: MaterialAlphaMode
pattern OPAQUE = MaterialAlphaMode "OPAQUE"

pattern MASK :: MaterialAlphaMode
pattern MASK = MaterialAlphaMode "MASK"

pattern BLEND :: MaterialAlphaMode
pattern BLEND = MaterialAlphaMode "BLEND"

data MaterialNormal = MaterialNormal
  { scale :: Float
    -- ^ The scalar multiplier applied to each normal vector of the normal texture.
  } deriving (Eq, Show, Generic)

instance FromJSON MaterialNormal where
  parseJSON = withObject "MaterialNormal" \o -> do
    scale <- o .:? "scale" .!= 1.0
    pure MaterialNormal{..}

instance ToJSON MaterialNormal

data MaterialOcclusion = MaterialOcclusion
  { strength :: Float
    -- ^ A scalar multiplier controlling the amount of occlusion applied. @[0.0-1.0]@
  } deriving (Eq, Show, Generic)

instance FromJSON MaterialOcclusion where
  parseJSON = withObject "MaterialOcclusion" \o -> do
    strength <- o .:? "strength" .!= 1.0
    pure MaterialOcclusion{..}

instance ToJSON MaterialOcclusion