metabrush/src/app/MetaBrush/Asset/Brushes.hs

133 lines
4.5 KiB
Haskell
Raw Normal View History

2020-11-12 17:34:46 +00:00
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE ScopedTypeVariables #-}
2021-04-25 23:17:27 +00:00
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeOperators #-}
2020-11-12 17:34:46 +00:00
module MetaBrush.Asset.Brushes where
2021-04-25 23:17:27 +00:00
-- base
import Data.Kind
( Type )
import Data.Type.Equality
( (:~:)(Refl) )
-- superrecord
import qualified SuperRecord
2020-11-12 17:34:46 +00:00
-- text
import Data.Text
( Text )
import qualified Data.Text as Text
( unpack )
-- MetaBrush
import MetaBrush.Brush
2020-11-12 17:34:46 +00:00
( Brush(..) )
2021-04-25 23:17:27 +00:00
import MetaBrush.MetaParameter.AST
( BrushFunction, STypesI(..), eqTys
)
2020-11-12 17:34:46 +00:00
import MetaBrush.MetaParameter.Driver
2021-04-25 23:17:27 +00:00
( SomeBrushFunction(..)
, interpretBrush
)
2020-11-12 17:34:46 +00:00
import MetaBrush.Unique
( UniqueSupply )
--------------------------------------------------------------------------------
2021-04-25 23:17:27 +00:00
circle
:: forall circleBrushFields
. ( circleBrushFields ~ '[ "r" SuperRecord.:= Double ] )
=> UniqueSupply -> IO ( Brush circleBrushFields )
circle uniqueSupply = mkBrush @circleBrushFields uniqueSupply name code
where
2020-11-12 17:34:46 +00:00
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) -> . ]"
2021-05-13 20:07:49 +00:00
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) -> . ]"
2021-04-25 23:17:27 +00:00
{-
rounded
:: forall roundedBrushFields
. ( roundedBrushFields ~ '[ ] ) -- TODO
=> UniqueSupply -> IO ( Brush roundedBrushFields )
rounded uniqueSupply = mkBrush @roundedBrushFields uniqueSupply name code
where
2020-11-12 17:34:46 +00:00
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\
\ -> .]"
2021-04-25 23:17:27 +00:00
-}
2020-11-12 17:34:46 +00:00
--------------------------------------------------------------------------------
2021-04-25 23:17:27 +00:00
mkBrush
:: forall ( givenBrushFields :: [ Type ] )
. STypesI givenBrushFields
=> UniqueSupply -> Text -> Text
-> IO ( Brush givenBrushFields )
2020-11-12 17:34:46 +00:00
mkBrush uniqSupply brushName brushCode = do
( mbBrush, _ ) <- interpretBrush uniqSupply brushCode
case mbBrush of
2021-04-25 23:17:27 +00:00
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 )
)