{-# LANGUAGE DataKinds #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE NamedFieldPuns #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE PolyKinds #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeOperators #-} module MetaBrush.Asset.Brushes where -- base import Data.Kind ( Type ) import Data.Type.Equality ( (:~:)(Refl) ) -- superrecord import qualified SuperRecord -- text import Data.Text ( Text ) import qualified Data.Text as Text ( unpack ) -- MetaBrush import MetaBrush.Brush ( Brush(..) ) import MetaBrush.MetaParameter.AST ( BrushFunction, STypesI(..), eqTys ) import MetaBrush.MetaParameter.Driver ( SomeBrushFunction(..) , interpretBrush ) import MetaBrush.Unique ( UniqueSupply ) -------------------------------------------------------------------------------- circle :: forall circleBrushFields . ( circleBrushFields ~ '[ "r" SuperRecord.:= Double ] ) => UniqueSupply -> IO ( Brush circleBrushFields ) circle uniqueSupply = mkBrush @circleBrushFields uniqueSupply name code where name, code :: Text name = "Circle" code = "with\n\ \ r = 1\n\ \satisfying\n\ \ r > 0\n\ \define\n\ \ let c = kappa in\n\ \ [ (r,0) -- ( r , r*c) -- ( r*c, r ) -> ( 0, r)\n\ \ -- (-r*c, r ) -- (-r , r*c) -> (-r, 0)\n\ \ -- (-r ,-r*c) -- (-r*c,-r ) -> ( 0,-r)\n\ \ -- ( r*c,-r ) -- ( r ,-r*c) -> . ]" circleCW :: forall circleBrushFields . ( circleBrushFields ~ '[ "r" SuperRecord.:= Double ] ) => UniqueSupply -> IO ( Brush circleBrushFields ) circleCW uniqueSupply = mkBrush @circleBrushFields uniqueSupply name code where name, code :: Text name = "Circle CW" code = "with\n\ \ r = 1\n\ \satisfying\n\ \ r > 0\n\ \define\n\ \ let c = kappa in\n\ \ [ (r,0) -- ( r ,-r*c) -- ( r*c,-r ) -> ( 0,-r)\n\ \ -- (-r*c,-r ) -- (-r ,-r*c) -> (-r, 0)\n\ \ -- (-r , r*c) -- (-r*c, r ) -> ( 0, r)\n\ \ -- ( r*c, r ) -- ( r , r*c) -> . ]" {- rounded :: forall roundedBrushFields . ( roundedBrushFields ~ '[ ] ) -- TODO => UniqueSupply -> IO ( Brush roundedBrushFields ) rounded uniqueSupply = mkBrush @roundedBrushFields uniqueSupply name code where name, code :: Text name = "Rounded quadrilateral" code = "with\n\ \ tr = (1,-2)\n\ \ rt = (2,-1)\n\ \ br = (1,2)\n\ \ rb = (2,1)\n\ \ bl = (-1,2)\n\ \ lb = (-2,1)\n\ \ tl = (-1,-2)\n\ \ lt = (-2,-1)\n\ \define\n\ \ let c = kappa in\n\ \ [ tr -- lerp c tr ( project rt onto [ tl -> tr ] ) -- lerp c rt ( project tr onto [ rb -> rt ] ) -> rt\n\ \ -> rb\n\ \ -- lerp c rb ( project br onto [ rt -> rb ] ) -- lerp c br ( project rb onto [ bl -> br ] ) -> br\n\ \ -> bl\n\ \ -- lerp c bl ( project lb onto [ br -> bl ] ) -- lerp c lb ( project bl onto [ lt -> lb ] ) -> lb\n\ \ -> lt\n\ \ -- lerp c lt ( project tl onto [ lb -> lt ] ) -- lerp c tl ( project lt onto [ tr -> tl ] ) -> tl\n\ \ -> .]" -} -------------------------------------------------------------------------------- mkBrush :: forall ( givenBrushFields :: [ Type ] ) . STypesI givenBrushFields => UniqueSupply -> Text -> Text -> IO ( Brush givenBrushFields ) mkBrush uniqSupply brushName brushCode = do ( mbBrush, _ ) <- interpretBrush uniqSupply brushCode case mbBrush of Left err -> error ( "Could not interpret '" <> Text.unpack brushName <> "' brush:\n" <> show err ) Right ( SomeBrushFunction ( brushFunction :: BrushFunction inferredBrushFields ) ) -> case eqTys @givenBrushFields @inferredBrushFields of Just Refl -> pure ( BrushData { brushName, brushCode, brushFunction } ) Nothing -> error ( "Incorrect record type for '" <> Text.unpack brushName <> "' brush:\n\ \Expected: " <> show ( sTypesI @givenBrushFields ) <> "\n\ \ Actual: " <> show ( sTypesI @inferredBrushFields ) )