mirror of
https://gitlab.com/sheaf/metabrush.git
synced 2024-11-05 14:53:37 +00:00
fix stroke cache issues
This commit is contained in:
parent
3886dca483
commit
f7a4b02e90
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
module Math.Bezier.Stroke
|
module Math.Bezier.Stroke
|
||||||
( Offset(..), Cusp(..)
|
( Offset(..), Cusp(..)
|
||||||
, CachedStroke(..), discardCache, invalidateCache
|
, CachedStroke(..), discardCache, newCache, invalidateCache
|
||||||
, computeStrokeOutline, joinWithBrush
|
, computeStrokeOutline, joinWithBrush
|
||||||
, withTangent
|
, withTangent
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ import Data.Semigroup
|
||||||
import GHC.Exts
|
import GHC.Exts
|
||||||
( newMutVar#, runRW# )
|
( newMutVar#, runRW# )
|
||||||
import GHC.STRef
|
import GHC.STRef
|
||||||
( STRef(..), readSTRef, writeSTRef )
|
( STRef(..), readSTRef, newSTRef, writeSTRef )
|
||||||
import GHC.Generics
|
import GHC.Generics
|
||||||
( Generic, Generic1, Generically(..) )
|
( Generic, Generic1, Generically(..) )
|
||||||
import GHC.TypeNats
|
import GHC.TypeNats
|
||||||
|
@ -201,6 +201,9 @@ invalidateCache = runRW# \ s ->
|
||||||
Lens.set ( typed @( CachedStroke RealWorld ) )
|
Lens.set ( typed @( CachedStroke RealWorld ) )
|
||||||
( CachedStroke $ STRef mutVar )
|
( CachedStroke $ STRef mutVar )
|
||||||
|
|
||||||
|
newCache :: forall s. ST s ( CachedStroke s )
|
||||||
|
newCache = CachedStroke <$> newSTRef Nothing
|
||||||
|
|
||||||
coords :: forall ptData. HasType ( ℝ 2 ) ptData => ptData -> ℝ 2
|
coords :: forall ptData. HasType ( ℝ 2 ) ptData => ptData -> ℝ 2
|
||||||
coords = Lens.view typed
|
coords = Lens.view typed
|
||||||
|
|
||||||
|
@ -250,7 +253,7 @@ computeStrokeOutline ::
|
||||||
, Module 𝕀 (T ( 𝕀ℝ nbUsedParams ) )
|
, Module 𝕀 (T ( 𝕀ℝ nbUsedParams ) )
|
||||||
|
|
||||||
-- Debugging.
|
-- Debugging.
|
||||||
, Show ptData, Show ( ℝ nbBrushParams )
|
, Show ptData, Show crvData, Show ( ℝ nbBrushParams )
|
||||||
|
|
||||||
)
|
)
|
||||||
=> RootSolvingAlgorithm
|
=> RootSolvingAlgorithm
|
||||||
|
@ -536,7 +539,7 @@ outlineFunction
|
||||||
, Representable 𝕀 ( 𝕀ℝ nbUsedParams )
|
, Representable 𝕀 ( 𝕀ℝ nbUsedParams )
|
||||||
|
|
||||||
-- Debugging.
|
-- Debugging.
|
||||||
, Show ptData, Show ( ℝ nbBrushParams )
|
, Show ptData, Show crvData, Show ( ℝ nbBrushParams )
|
||||||
)
|
)
|
||||||
=> RootSolvingAlgorithm
|
=> RootSolvingAlgorithm
|
||||||
-> Maybe ( RootIsolationOptions N 3 )
|
-> Maybe ( RootIsolationOptions N 3 )
|
||||||
|
|
|
@ -399,7 +399,7 @@ renderStrokeSpline
|
||||||
=> Colours -> Mode -> RenderMode
|
=> Colours -> Mode -> RenderMode
|
||||||
-> Set PointIndex -> Maybe HoverContext -> Zoom
|
-> Set PointIndex -> Maybe HoverContext -> Zoom
|
||||||
-> ( PointData pointData -> Compose Renders Cairo.Render () )
|
-> ( PointData pointData -> Compose Renders Cairo.Render () )
|
||||||
-> Spline clo CurveData ( PointData pointData )
|
-> Spline clo ( CurveData RealWorld ) ( PointData pointData )
|
||||||
-> Compose Renders Cairo.Render ()
|
-> Compose Renders Cairo.Render ()
|
||||||
renderStrokeSpline cols mode rdrMode selPts mbHover zoom renderSubcontent spline =
|
renderStrokeSpline cols mode rdrMode selPts mbHover zoom renderSubcontent spline =
|
||||||
bifoldSpline ( renderSplineCurve ( splineStart spline ) ) ( renderSplinePoint FirstPoint ) spline
|
bifoldSpline ( renderSplineCurve ( splineStart spline ) ) ( renderSplinePoint FirstPoint ) spline
|
||||||
|
@ -416,7 +416,7 @@ renderStrokeSpline cols mode rdrMode selPts mbHover zoom renderSubcontent spline
|
||||||
renderSplineCurve
|
renderSplineCurve
|
||||||
:: forall clo'
|
:: forall clo'
|
||||||
. SplineTypeI clo'
|
. SplineTypeI clo'
|
||||||
=> PointData pointData -> PointData pointData -> Curve clo' CurveData ( PointData pointData ) -> Compose Renders Cairo.Render ()
|
=> PointData pointData -> PointData pointData -> Curve clo' ( CurveData RealWorld ) ( PointData pointData ) -> Compose Renders Cairo.Render ()
|
||||||
renderSplineCurve start p0 ( LineTo np1 ( CurveData { curveIndex } ) )
|
renderSplineCurve start p0 ( LineTo np1 ( CurveData { curveIndex } ) )
|
||||||
= Compose blank
|
= Compose blank
|
||||||
{ renderPPts = when ( rdrMode == RenderingPath ) do
|
{ renderPPts = when ( rdrMode == RenderingPath ) do
|
||||||
|
@ -491,7 +491,7 @@ renderBrushShape cols mbHoverContext zoom brushFn brushWidgetElts pt =
|
||||||
*> renderBrushWidgetElements cols zoom mbHoverContext' brushWidgetElts
|
*> renderBrushWidgetElements cols zoom mbHoverContext' brushWidgetElts
|
||||||
*> toAll Cairo.restore
|
*> toAll Cairo.restore
|
||||||
where
|
where
|
||||||
noCurveData :: Spline Closed () ( ℝ 2 ) -> Spline Closed CurveData ( PointData () )
|
noCurveData :: Spline Closed () ( ℝ 2 ) -> Spline Closed ( CurveData RealWorld ) ( PointData () )
|
||||||
noCurveData =
|
noCurveData =
|
||||||
bimapSpline
|
bimapSpline
|
||||||
( \ _ -> bimapCurve ( \ _ -> CurveData 987654321 ( invalidateCache undefined ) ) ( \ _ p -> PointData p () ) )
|
( \ _ -> bimapCurve ( \ _ -> CurveData 987654321 ( invalidateCache undefined ) ) ( \ _ p -> PointData p () ) )
|
||||||
|
|
|
@ -22,6 +22,8 @@ import Control.Arrow
|
||||||
( second )
|
( second )
|
||||||
import Control.Monad
|
import Control.Monad
|
||||||
( guard, when )
|
( guard, when )
|
||||||
|
import Control.Monad.ST
|
||||||
|
( RealWorld )
|
||||||
import Data.Foldable
|
import Data.Foldable
|
||||||
( for_, traverse_ )
|
( for_, traverse_ )
|
||||||
import Data.Functor
|
import Data.Functor
|
||||||
|
@ -153,9 +155,9 @@ subdivide c doc@( Document { documentMetadata, documentContent }) =
|
||||||
subdivideCurve
|
subdivideCurve
|
||||||
:: T ( ℝ 2 )
|
:: T ( ℝ 2 )
|
||||||
-> PointData brushParams
|
-> PointData brushParams
|
||||||
-> Curve Open CurveData ( PointData brushParams )
|
-> Curve Open ( CurveData RealWorld ) ( PointData brushParams )
|
||||||
-> Writer [ ( Curve Open () (), Double ) ]
|
-> Writer [ ( Curve Open () (), Double ) ]
|
||||||
( Seq ( Curve Open CurveData ( PointData brushParams ) ) )
|
( Seq ( Curve Open ( CurveData RealWorld ) ( PointData brushParams ) ) )
|
||||||
subdivideCurve offset sp0 crv =
|
subdivideCurve offset sp0 crv =
|
||||||
case crv of
|
case crv of
|
||||||
LineTo ( NextPoint sp1 ) dat -> do
|
LineTo ( NextPoint sp1 ) dat -> do
|
||||||
|
@ -193,7 +195,7 @@ subdivide c doc@( Document { documentMetadata, documentContent }) =
|
||||||
( Quadratic.Bezier _ q1 subdiv, Quadratic.Bezier _ r1 _ ) -> do
|
( Quadratic.Bezier _ q1 subdiv, Quadratic.Bezier _ r1 _ ) -> do
|
||||||
Writer.tell [ ( stripData crv, t ) ]
|
Writer.tell [ ( stripData crv, t ) ]
|
||||||
let
|
let
|
||||||
bez_start, bez_end :: Curve Open CurveData ( PointData brushParams )
|
bez_start, bez_end :: Curve Open ( CurveData RealWorld ) ( PointData brushParams )
|
||||||
bez_start = Bezier2To q1 ( NextPoint subdiv ) ( invalidateCache dat )
|
bez_start = Bezier2To q1 ( NextPoint subdiv ) ( invalidateCache dat )
|
||||||
bez_end = Bezier2To r1 ( NextPoint sp2 ) ( invalidateCache dat )
|
bez_end = Bezier2To r1 ( NextPoint sp2 ) ( invalidateCache dat )
|
||||||
return ( bez_start Seq.:<| bez_end Seq.:<| Seq.Empty )
|
return ( bez_start Seq.:<| bez_end Seq.:<| Seq.Empty )
|
||||||
|
@ -213,7 +215,7 @@ subdivide c doc@( Document { documentMetadata, documentContent }) =
|
||||||
( Cubic.Bezier _ q1 q2 subdiv, Cubic.Bezier _ r1 r2 _ ) -> do
|
( Cubic.Bezier _ q1 q2 subdiv, Cubic.Bezier _ r1 r2 _ ) -> do
|
||||||
Writer.tell [ ( stripData crv, t ) ]
|
Writer.tell [ ( stripData crv, t ) ]
|
||||||
let
|
let
|
||||||
bez_start, bez_end :: Curve Open CurveData ( PointData brushParams )
|
bez_start, bez_end :: Curve Open ( CurveData RealWorld ) ( PointData brushParams )
|
||||||
bez_start = Bezier3To q1 q2 ( NextPoint subdiv ) ( invalidateCache dat )
|
bez_start = Bezier3To q1 q2 ( NextPoint subdiv ) ( invalidateCache dat )
|
||||||
bez_end = Bezier3To r1 r2 ( NextPoint sp3 ) ( invalidateCache dat )
|
bez_end = Bezier3To r1 r2 ( NextPoint sp3 ) ( invalidateCache dat )
|
||||||
return ( bez_start Seq.:<| bez_end Seq.:<| Seq.Empty )
|
return ( bez_start Seq.:<| bez_end Seq.:<| Seq.Empty )
|
||||||
|
@ -257,7 +259,7 @@ selectAt selMode c doc@( Document { documentContent, documentMetadata } ) =
|
||||||
return PreserveStroke
|
return PreserveStroke
|
||||||
|
|
||||||
selectSplineCurve :: SplineTypeI clo
|
selectSplineCurve :: SplineTypeI clo
|
||||||
=> Curve clo CurveData ( PointData ptData )
|
=> Curve clo ( CurveData RealWorld ) ( PointData ptData )
|
||||||
-> Except PointIndex ()
|
-> Except PointIndex ()
|
||||||
selectSplineCurve = \case
|
selectSplineCurve = \case
|
||||||
LineTo p1 ( CurveData { curveIndex } ) ->
|
LineTo p1 ( CurveData { curveIndex } ) ->
|
||||||
|
@ -311,7 +313,7 @@ dragMoveSelect c ( Document { documentContent, documentMetadata } ) =
|
||||||
=> Unique
|
=> Unique
|
||||||
-> PointData brushParams
|
-> PointData brushParams
|
||||||
-> Int
|
-> Int
|
||||||
-> PointData brushParams -> Curve clo' CurveData ( PointData brushParams )
|
-> PointData brushParams -> Curve clo' ( CurveData RealWorld ) ( PointData brushParams )
|
||||||
-> Except DragMoveSelect ()
|
-> Except DragMoveSelect ()
|
||||||
dragSelectSplineCurve uniq start i sp0 = \case
|
dragSelectSplineCurve uniq start i sp0 = \case
|
||||||
LineTo sp1 ( CurveData { curveIndex } ) -> do
|
LineTo sp1 ( CurveData { curveIndex } ) -> do
|
||||||
|
@ -442,7 +444,7 @@ selectRectangle selMode ( ℝ2 x0 y0 ) ( ℝ2 x1 y1 ) doc@( Document { documentC
|
||||||
return PreserveStroke
|
return PreserveStroke
|
||||||
|
|
||||||
selectRectSplineCurve :: SplineTypeI clo
|
selectRectSplineCurve :: SplineTypeI clo
|
||||||
=> Curve clo CurveData ( PointData ptData )
|
=> Curve clo ( CurveData RealWorld ) ( PointData ptData )
|
||||||
-> Writer ( Set PointIndex ) ()
|
-> Writer ( Set PointIndex ) ()
|
||||||
selectRectSplineCurve = \case
|
selectRectSplineCurve = \case
|
||||||
LineTo p1 ( CurveData { curveIndex } ) ->
|
LineTo p1 ( CurveData { curveIndex } ) ->
|
||||||
|
@ -495,7 +497,7 @@ translateSelection t doc@( Document { documentContent, documentMetadata } ) =
|
||||||
firstPointSel = FirstPoint `Set.member` strokeSelPts
|
firstPointSel = FirstPoint `Set.member` strokeSelPts
|
||||||
( spline', ( modPts, _ ) ) =
|
( spline', ( modPts, _ ) ) =
|
||||||
( `State.runState` ( mempty, False ) ) $
|
( `State.runState` ( mempty, False ) ) $
|
||||||
bitraverseSpline @_ @_ @CurveData @( PointData _ )
|
bitraverseSpline @_ @_ @( CurveData RealWorld ) @( PointData _ )
|
||||||
( \ _ -> updateSplineCurve firstPointSel strokeSelPts )
|
( \ _ -> updateSplineCurve firstPointSel strokeSelPts )
|
||||||
( \ pt -> do { ( NextPoint pt', _ ) <- updatePoint firstPointSel strokeSelPts FirstPoint ( NextPoint pt ) ; return pt' } )
|
( \ pt -> do { ( NextPoint pt', _ ) <- updatePoint firstPointSel strokeSelPts FirstPoint ( NextPoint pt ) ; return pt' } )
|
||||||
strokeSpline
|
strokeSpline
|
||||||
|
@ -511,15 +513,15 @@ translateSelection t doc@( Document { documentContent, documentMetadata } ) =
|
||||||
. SplineTypeI clo'
|
. SplineTypeI clo'
|
||||||
=> Bool
|
=> Bool
|
||||||
-> Set PointIndex
|
-> Set PointIndex
|
||||||
-> Curve clo' CurveData ( PointData brushParams )
|
-> Curve clo' ( CurveData RealWorld ) ( PointData brushParams )
|
||||||
-> State ( Set PointIndex, Bool )
|
-> State ( Set PointIndex, Bool )
|
||||||
( Curve clo' CurveData ( PointData brushParams ) )
|
( Curve clo' ( CurveData RealWorld ) ( PointData brushParams ) )
|
||||||
updateSplineCurve startPtSel strokeSelPts = \case
|
updateSplineCurve startPtSel strokeSelPts = \case
|
||||||
LineTo p1 dat@( CurveData { curveIndex } ) -> do
|
LineTo p1 dat@( CurveData { curveIndex } ) -> do
|
||||||
( _, sel0 ) <- State.get
|
( _, sel0 ) <- State.get
|
||||||
( p1', sel1 ) <- updatePoint startPtSel strokeSelPts ( PointIndex curveIndex PathPoint ) p1
|
( p1', sel1 ) <- updatePoint startPtSel strokeSelPts ( PointIndex curveIndex PathPoint ) p1
|
||||||
let
|
let
|
||||||
dat' :: CurveData
|
dat' :: ( CurveData RealWorld )
|
||||||
dat'
|
dat'
|
||||||
| sel0 || sel1
|
| sel0 || sel1
|
||||||
= invalidateCache dat
|
= invalidateCache dat
|
||||||
|
@ -532,7 +534,7 @@ translateSelection t doc@( Document { documentContent, documentMetadata } ) =
|
||||||
( NextPoint p1', sel1 ) <- updatePoint startPtSel strokeSelPts ( PointIndex curveIndex ( ControlPoint Bez2Cp )) ( NextPoint p1 )
|
( NextPoint p1', sel1 ) <- updatePoint startPtSel strokeSelPts ( PointIndex curveIndex ( ControlPoint Bez2Cp )) ( NextPoint p1 )
|
||||||
( p2', sel2 ) <- updatePoint startPtSel strokeSelPts ( PointIndex curveIndex PathPoint ) p2
|
( p2', sel2 ) <- updatePoint startPtSel strokeSelPts ( PointIndex curveIndex PathPoint ) p2
|
||||||
let
|
let
|
||||||
dat' :: CurveData
|
dat' :: ( CurveData RealWorld )
|
||||||
dat'
|
dat'
|
||||||
| sel0 || sel1 || sel2
|
| sel0 || sel1 || sel2
|
||||||
= invalidateCache dat
|
= invalidateCache dat
|
||||||
|
@ -546,7 +548,7 @@ translateSelection t doc@( Document { documentContent, documentMetadata } ) =
|
||||||
( NextPoint p2', sel2 ) <- updatePoint startPtSel strokeSelPts ( PointIndex curveIndex ( ControlPoint Bez3Cp2 )) ( NextPoint p2 )
|
( NextPoint p2', sel2 ) <- updatePoint startPtSel strokeSelPts ( PointIndex curveIndex ( ControlPoint Bez3Cp2 )) ( NextPoint p2 )
|
||||||
( p3', sel3 ) <- updatePoint startPtSel strokeSelPts ( PointIndex curveIndex PathPoint ) p3
|
( p3', sel3 ) <- updatePoint startPtSel strokeSelPts ( PointIndex curveIndex PathPoint ) p3
|
||||||
let
|
let
|
||||||
dat' :: CurveData
|
dat' :: ( CurveData RealWorld )
|
||||||
dat'
|
dat'
|
||||||
| sel0 || sel1 || sel2 || sel3
|
| sel0 || sel1 || sel2 || sel3
|
||||||
= invalidateCache dat
|
= invalidateCache dat
|
||||||
|
@ -644,9 +646,9 @@ deleteSelected doc@( Document { documentContent, documentMetadata } ) =
|
||||||
updateSplineCurve
|
updateSplineCurve
|
||||||
:: forall clo' hasStart. SplineTypeI clo'
|
:: forall clo' hasStart. SplineTypeI clo'
|
||||||
=> CurrentStart hasStart ( PointData brushParams )
|
=> CurrentStart hasStart ( PointData brushParams )
|
||||||
-> Curve clo' CurveData ( PointData brushParams )
|
-> Curve clo' ( CurveData RealWorld ) ( PointData brushParams )
|
||||||
-> Writer ( Set PointIndex )
|
-> Writer ( Set PointIndex )
|
||||||
( WitherResult hasStart clo' CurveData ( PointData brushParams ) )
|
( WitherResult hasStart clo' ( CurveData RealWorld ) ( PointData brushParams ) )
|
||||||
updateSplineCurve mbPrevPt crv = case crv of
|
updateSplineCurve mbPrevPt crv = case crv of
|
||||||
|
|
||||||
LineTo p1 ( CurveData { curveIndex } ) ->
|
LineTo p1 ( CurveData { curveIndex } ) ->
|
||||||
|
@ -789,9 +791,9 @@ dragUpdate _ p ( ClickedOnCurve { dragStrokeUnique, dragCurveIndex, dragCurvePa
|
||||||
|
|
||||||
updateCurve
|
updateCurve
|
||||||
:: PointData pointParams
|
:: PointData pointParams
|
||||||
-> Curve Open CurveData ( PointData pointParams )
|
-> Curve Open ( CurveData RealWorld ) ( PointData pointParams )
|
||||||
-> Writer ( Set PointIndex )
|
-> Writer ( Set PointIndex )
|
||||||
( Curve Open CurveData ( PointData pointParams ) )
|
( Curve Open ( CurveData RealWorld ) ( PointData pointParams ) )
|
||||||
updateCurve sp0 curve = case curve of
|
updateCurve sp0 curve = case curve of
|
||||||
LineTo ( NextPoint sp1 ) dat@( CurveData { curveIndex } ) -> do
|
LineTo ( NextPoint sp1 ) dat@( CurveData { curveIndex } ) -> do
|
||||||
let
|
let
|
||||||
|
@ -852,9 +854,9 @@ dragUpdate _ p ( ClickedOnCurve { dragStrokeUnique, dragCurveIndex, dragCurvePa
|
||||||
pure $ cubicDragCurve dat bez3
|
pure $ cubicDragCurve dat bez3
|
||||||
where
|
where
|
||||||
quadraticDragCurve
|
quadraticDragCurve
|
||||||
:: CurveData
|
:: ( CurveData RealWorld )
|
||||||
-> Quadratic.Bezier ( PointData pointParams )
|
-> Quadratic.Bezier ( PointData pointParams )
|
||||||
-> Curve Open CurveData ( PointData pointParams )
|
-> Curve Open ( CurveData RealWorld ) ( PointData pointParams )
|
||||||
quadraticDragCurve dat ( Quadratic.Bezier { Quadratic.p1 = sp1, Quadratic.p2 = sp2 } ) =
|
quadraticDragCurve dat ( Quadratic.Bezier { Quadratic.p1 = sp1, Quadratic.p2 = sp2 } ) =
|
||||||
let
|
let
|
||||||
cp :: ℝ 2
|
cp :: ℝ 2
|
||||||
|
@ -862,9 +864,9 @@ dragUpdate _ p ( ClickedOnCurve { dragStrokeUnique, dragCurveIndex, dragCurvePa
|
||||||
Quadratic.interpolate @( T ( ℝ 2 ) ) ( coords sp0 ) ( coords sp2 ) dragCurveParameter p
|
Quadratic.interpolate @( T ( ℝ 2 ) ) ( coords sp0 ) ( coords sp2 ) dragCurveParameter p
|
||||||
in Bezier2To ( set _coords cp sp1 ) ( NextPoint sp2 ) ( invalidateCache dat )
|
in Bezier2To ( set _coords cp sp1 ) ( NextPoint sp2 ) ( invalidateCache dat )
|
||||||
cubicDragCurve
|
cubicDragCurve
|
||||||
:: CurveData
|
:: ( CurveData RealWorld )
|
||||||
-> Cubic.Bezier ( PointData pointParams )
|
-> Cubic.Bezier ( PointData pointParams )
|
||||||
-> Curve Open CurveData ( PointData pointParams )
|
-> Curve Open ( CurveData RealWorld ) ( PointData pointParams )
|
||||||
cubicDragCurve dat ( Cubic.Bezier { Cubic.p1 = sp1, Cubic.p2 = sp2, Cubic.p3 = sp3 } ) =
|
cubicDragCurve dat ( Cubic.Bezier { Cubic.p1 = sp1, Cubic.p2 = sp2, Cubic.p3 = sp3 } ) =
|
||||||
let
|
let
|
||||||
cp1, cp2 :: ℝ 2
|
cp1, cp2 :: ℝ 2
|
||||||
|
@ -939,9 +941,9 @@ applyBrushWidgetAction pressingCtrl c mbPrevAction doc@( Document { documentCont
|
||||||
-> ( pointParams -> Record brushFields )
|
-> ( pointParams -> Record brushFields )
|
||||||
-> ( Record brushFields -> pointParams -> pointParams )
|
-> ( Record brushFields -> pointParams -> pointParams )
|
||||||
-> Unique
|
-> Unique
|
||||||
-> PointData pointParams -> Curve clo' CurveData ( PointData pointParams )
|
-> PointData pointParams -> Curve clo' ( CurveData RealWorld ) ( PointData pointParams )
|
||||||
-> State ( Maybe BrushWidgetActionState, Bool )
|
-> State ( Maybe BrushWidgetActionState, Bool )
|
||||||
( Curve clo' CurveData ( PointData pointParams ) )
|
( Curve clo' ( CurveData RealWorld ) ( PointData pointParams ) )
|
||||||
updateSplineCurve _start brush toBrushParams updatePointParams uniq _sp0 curve = do
|
updateSplineCurve _start brush toBrushParams updatePointParams uniq _sp0 curve = do
|
||||||
( mbAct, prevCurveAct ) <- State.get
|
( mbAct, prevCurveAct ) <- State.get
|
||||||
-- We can only perform a brush widget update if:
|
-- We can only perform a brush widget update if:
|
||||||
|
|
|
@ -12,7 +12,7 @@ module MetaBrush.Document.Serialise
|
||||||
import Control.Monad
|
import Control.Monad
|
||||||
( unless )
|
( unless )
|
||||||
import Control.Monad.ST
|
import Control.Monad.ST
|
||||||
( stToIO )
|
( RealWorld, stToIO )
|
||||||
import qualified Data.Bifunctor as Bifunctor
|
import qualified Data.Bifunctor as Bifunctor
|
||||||
( first )
|
( first )
|
||||||
import Data.Functor.Identity
|
import Data.Functor.Identity
|
||||||
|
@ -259,7 +259,7 @@ encodeStroke = JSON.Encoder.mapLikeObj
|
||||||
. mbEncodeBrush
|
. mbEncodeBrush
|
||||||
. JSON.Encoder.atKey' "spline" ( encodeSpline encodePointData ) strokeSpline
|
. JSON.Encoder.atKey' "spline" ( encodeSpline encodePointData ) strokeSpline
|
||||||
|
|
||||||
newCurveData :: MonadIO m => ( Integer -> m CurveData )
|
newCurveData :: MonadIO m => ( Integer -> m ( CurveData RealWorld ) )
|
||||||
newCurveData i = do
|
newCurveData i = do
|
||||||
noCache <- liftIO . stToIO $ CachedStroke <$> newSTRef Nothing
|
noCache <- liftIO . stToIO $ CachedStroke <$> newSTRef Nothing
|
||||||
return $
|
return $
|
||||||
|
|
|
@ -11,6 +11,8 @@ module MetaBrush.Draw
|
||||||
-- base
|
-- base
|
||||||
import Control.Monad
|
import Control.Monad
|
||||||
( when )
|
( when )
|
||||||
|
import Control.Monad.ST
|
||||||
|
( RealWorld, ST, runST )
|
||||||
import Data.Foldable
|
import Data.Foldable
|
||||||
( for_ )
|
( for_ )
|
||||||
import Data.Functor.Identity
|
import Data.Functor.Identity
|
||||||
|
@ -52,7 +54,7 @@ import Control.Monad.Trans.Reader
|
||||||
-- brush-strokes
|
-- brush-strokes
|
||||||
import Math.Bezier.Spline
|
import Math.Bezier.Spline
|
||||||
import Math.Bezier.Stroke
|
import Math.Bezier.Stroke
|
||||||
( invalidateCache )
|
( newCache )
|
||||||
import Math.Linear
|
import Math.Linear
|
||||||
( ℝ(..) )
|
( ℝ(..) )
|
||||||
|
|
||||||
|
@ -70,6 +72,9 @@ import MetaBrush.Stroke
|
||||||
import MetaBrush.Unique
|
import MetaBrush.Unique
|
||||||
( Unique, UniqueSupply, freshUnique )
|
( Unique, UniqueSupply, freshUnique )
|
||||||
|
|
||||||
|
import Unsafe.Coerce
|
||||||
|
( unsafeCoerce )
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
-- | A draw anchor, to continue drawing from one end of an existing stroke.
|
-- | A draw anchor, to continue drawing from one end of an existing stroke.
|
||||||
|
@ -216,48 +221,73 @@ addToAnchor :: DrawAnchor -> Spline Open () ( PointData () ) -> Document -> Docu
|
||||||
addToAnchor anchor newSpline doc@( Document { documentMetadata, documentContent = oldContent } ) =
|
addToAnchor anchor newSpline doc@( Document { documentMetadata, documentContent = oldContent } ) =
|
||||||
let
|
let
|
||||||
strokes' =
|
strokes' =
|
||||||
runIdentity $
|
runST $
|
||||||
forStrokeHierarchy
|
forStrokeHierarchy
|
||||||
( layerMetadata documentMetadata )
|
( layerMetadata documentMetadata )
|
||||||
( strokeHierarchy oldContent )
|
( strokeHierarchy oldContent )
|
||||||
( \ u s _ -> Identity $ updateStroke u s )
|
( \ u s _ -> updateStroke u s )
|
||||||
in doc { documentContent = oldContent { strokeHierarchy = strokes' } }
|
in doc { documentContent = oldContent { strokeHierarchy = strokes' } }
|
||||||
where
|
where
|
||||||
|
|
||||||
updateStroke :: Unique -> Stroke -> UpdateStroke
|
updateStroke :: forall s. Unique -> Stroke -> ST s UpdateStroke
|
||||||
updateStroke strokeUnique stroke
|
updateStroke strokeUnique stroke@( Stroke { strokeSpline = ( oldSpline :: StrokeSpline clo brushParams ) })
|
||||||
| strokeUnique == anchorStroke anchor
|
| strokeUnique == anchorStroke anchor
|
||||||
, let
|
, SOpen <- ssplineType @clo
|
||||||
updateSpline
|
, let prevSpline0 = co @RealWorld @s oldSpline
|
||||||
:: forall clo brushData
|
= do
|
||||||
. SplineTypeI clo
|
finalSpline <-
|
||||||
=> StrokeSpline clo brushData -> StrokeSpline clo brushData
|
if anchorIsAtEnd anchor
|
||||||
updateSpline prevSpline
|
then do
|
||||||
| SOpen <- ssplineType @clo
|
( i0, prevSpline ) <-
|
||||||
= if anchorIsAtEnd anchor
|
case splineCurves prevSpline0 of
|
||||||
then
|
OpenCurves ( prevCurves :|> lastCurve ) -> do
|
||||||
let
|
cache <- newCache
|
||||||
i0 = case splineCurves prevSpline of
|
-- Invalidate the point we are connecting to (stroke endpoint).
|
||||||
OpenCurves ( _ :|> lastCurve ) ->
|
let lastCurve' = set ( field' @"curveData" . field' @"cachedStroke" ) cache lastCurve
|
||||||
curveIndex ( curveData lastCurve ) + 1
|
return
|
||||||
_ -> 0
|
( curveIndex ( curveData lastCurve ) + 1
|
||||||
setBrushData :: PointData () -> PointData brushData
|
|
||||||
setBrushData = set ( field @"brushParams" ) ( brushParams ( splineEnd prevSpline ) )
|
, prevSpline0 { splineCurves =
|
||||||
setData = bimapSpline ( \ _ -> bimapCurve ( \ s -> CurveData i0 ( invalidateCache $ undefined s ) ) ( \ _ -> setBrushData ) ) setBrushData
|
OpenCurves ( prevCurves :|> lastCurve' ) }
|
||||||
in prevSpline <> setData newSpline
|
)
|
||||||
else
|
OpenCurves _ ->
|
||||||
let
|
return ( 0, prevSpline0 )
|
||||||
i0 = case splineCurves prevSpline of
|
newSpline' <- newCaches ( \ i -> i0 + fromIntegral i ) ( brushParams ( splineEnd prevSpline ) ) newSpline
|
||||||
OpenCurves ( firstCurve :<| _ ) ->
|
return $ prevSpline <> newSpline'
|
||||||
curveIndex ( curveData firstCurve ) - 1
|
else do
|
||||||
_ -> 0
|
( i0, prevSpline ) <-
|
||||||
setBrushData :: PointData () -> PointData brushData
|
case splineCurves prevSpline0 of
|
||||||
setBrushData = set ( field @"brushParams" ) ( brushParams ( splineStart prevSpline ) )
|
OpenCurves ( firstCurve :<| nextCurves ) -> do
|
||||||
setData = bimapSpline ( \ _ -> bimapCurve ( \ s -> CurveData i0 ( invalidateCache $ undefined s ) ) ( \ _ -> setBrushData ) ) setBrushData
|
cache <- newCache
|
||||||
in setData ( reverseSpline newSpline ) <> prevSpline
|
-- Invalidate the point we are connecting to (stroke endpoint).
|
||||||
| otherwise
|
let firstCurve' = set ( field' @"curveData" . field' @"cachedStroke" ) cache firstCurve
|
||||||
= assert False ( "addToAnchor: trying to add to closed spline " <> show strokeUnique )
|
return
|
||||||
prevSpline -- should never add to a closed spline
|
( curveIndex ( curveData firstCurve ) - 1
|
||||||
= UpdateStrokeTo $ overStrokeSpline updateSpline stroke
|
-- Invalidate the point we are connecting to (stroke endpoint).
|
||||||
|
, prevSpline0 { splineCurves = OpenCurves ( firstCurve' :<| nextCurves ) }
|
||||||
|
)
|
||||||
|
OpenCurves _ ->
|
||||||
|
return ( 0, prevSpline0 )
|
||||||
|
newSpline' <- newCaches ( \ i -> i0 - fromIntegral i - 1 ) ( brushParams ( splineStart prevSpline ) ) ( reverseSpline newSpline )
|
||||||
|
return $ newSpline' <> prevSpline
|
||||||
|
return $ UpdateStrokeTo ( stroke { strokeSpline = co @s @RealWorld finalSpline } )
|
||||||
| otherwise
|
| otherwise
|
||||||
= PreserveStroke
|
= return PreserveStroke
|
||||||
|
|
||||||
|
{-# NOINLINE co #-}
|
||||||
|
co :: forall s t brushParams. Spline Open ( CurveData s ) ( PointData brushParams ) -> Spline Open ( CurveData t ) ( PointData brushParams )
|
||||||
|
co = unsafeCoerce
|
||||||
|
|
||||||
|
newCaches :: ( Int -> Rational )
|
||||||
|
-> brushParams
|
||||||
|
-> Spline Open () ( PointData () )
|
||||||
|
-> ST s ( Spline Open ( CurveData s ) ( PointData brushParams ) )
|
||||||
|
newCaches mkCrvIx brushParams =
|
||||||
|
ibitraverseSpline
|
||||||
|
( \ i _ -> bitraverseCurve
|
||||||
|
( \ _ -> CurveData ( mkCrvIx i ) <$> newCache )
|
||||||
|
( \ _ -> return . setBrushData )
|
||||||
|
)
|
||||||
|
( return . setBrushData )
|
||||||
|
where
|
||||||
|
setBrushData = set ( field @"brushParams" ) brushParams
|
||||||
|
|
|
@ -99,20 +99,20 @@ data PointData params
|
||||||
deriving anyclass NFData
|
deriving anyclass NFData
|
||||||
|
|
||||||
-- | Data attached to each curve in a spline.
|
-- | Data attached to each curve in a spline.
|
||||||
data CurveData =
|
data CurveData s =
|
||||||
CurveData
|
CurveData
|
||||||
{ curveIndex :: !Rational
|
{ curveIndex :: !Rational
|
||||||
, cachedStroke :: !( CachedStroke RealWorld )
|
, cachedStroke :: !( CachedStroke s )
|
||||||
}
|
}
|
||||||
deriving stock Generic
|
deriving stock Generic
|
||||||
deriving anyclass NFData
|
deriving anyclass NFData
|
||||||
|
|
||||||
instance Show CurveData where
|
instance Show ( CurveData s ) where
|
||||||
show ( CurveData { curveIndex } ) = show curveIndex
|
show ( CurveData { curveIndex } ) = show curveIndex
|
||||||
instance Eq CurveData where
|
instance Eq ( CurveData s ) where
|
||||||
( CurveData { curveIndex = i1 } ) == ( CurveData { curveIndex = i2 } )
|
( CurveData { curveIndex = i1 } ) == ( CurveData { curveIndex = i2 } )
|
||||||
= i1 == i2
|
= i1 == i2
|
||||||
instance Ord CurveData where
|
instance Ord ( CurveData s ) where
|
||||||
compare ( CurveData { curveIndex = i1 } ) ( CurveData { curveIndex = i2 } )
|
compare ( CurveData { curveIndex = i1 } ) ( CurveData { curveIndex = i2 } )
|
||||||
= compare i1 i2
|
= compare i1 i2
|
||||||
|
|
||||||
|
@ -135,7 +135,7 @@ coords :: PointData brushParams -> ℝ 2
|
||||||
coords = view _coords
|
coords = view _coords
|
||||||
|
|
||||||
type StrokeSpline clo brushParams =
|
type StrokeSpline clo brushParams =
|
||||||
Spline clo CurveData ( PointData brushParams )
|
Spline clo ( CurveData RealWorld ) ( PointData brushParams )
|
||||||
|
|
||||||
data Stroke where
|
data Stroke where
|
||||||
Stroke
|
Stroke
|
||||||
|
|
Loading…
Reference in a new issue