Add gradient support #9

Closed
fryguybob opened this Issue Aug 4, 2012 · 18 comments

Comments

Projects
None yet
4 participants
@fryguybob
Member

fryguybob commented Aug 4, 2012

(Imported from http://code.google.com/p/diagrams/issues/detail?id=21. Original issue from byor...@gmail.com on April 9, 2011, 12:10:27 AM UTC)

Many backends support gradients of various types. A module for describing gradients should be added to the standard library along with functions for setting the gradient attribute of a diagram.

@jeffreyrosenbluth

This comment has been minimized.

Show comment Hide comment
@jeffreyrosenbluth

jeffreyrosenbluth Oct 18, 2013

Member

I'd like to begin working on adding gradients to diagrams, I don't know if it will be ready by 1.0, but who knows. We have a number of design decisions to make before I start. Over the next view days I'll post some options to get a discussion started. If anyone knows of anyone previous discussion please let me know.

Member

jeffreyrosenbluth commented Oct 18, 2013

I'd like to begin working on adding gradients to diagrams, I don't know if it will be ready by 1.0, but who knows. We have a number of design decisions to make before I start. Over the next view days I'll post some options to get a discussion started. If anyone knows of anyone previous discussion please let me know.

@fryguybob

This comment has been minimized.

Show comment Hide comment
@fryguybob

fryguybob Oct 18, 2013

Member

I don't have much to add yet, but the pdf backend does have graident
support.

On Thu, Oct 17, 2013 at 9:28 PM, Jeffrey Rosenbluth <
notifications@github.com> wrote:

I'd like to begin working on adding gradients to diagrams, I don't know if
it will be ready by 1.0, but who knows. We have a number of design
decisions to make before I start. Over the next view days I'll post some
options to get a discussion started. If anyone knows of anyone previous
discussion please let me know.


Reply to this email directly or view it on GitHubhttps://github.com/diagrams/diagrams-lib/issues/9#issuecomment-26566447
.

Member

fryguybob commented Oct 18, 2013

I don't have much to add yet, but the pdf backend does have graident
support.

On Thu, Oct 17, 2013 at 9:28 PM, Jeffrey Rosenbluth <
notifications@github.com> wrote:

I'd like to begin working on adding gradients to diagrams, I don't know if
it will be ready by 1.0, but who knows. We have a number of design
decisions to make before I start. Over the next view days I'll post some
options to get a discussion started. If anyone knows of anyone previous
discussion please let me know.


Reply to this email directly or view it on GitHubhttps://github.com/diagrams/diagrams-lib/issues/9#issuecomment-26566447
.

@jeffreyrosenbluth

This comment has been minimized.

Show comment Hide comment
@jeffreyrosenbluth

jeffreyrosenbluth Oct 19, 2013

Member

As I see it the first bridge to cross is deciding between the following 2 options.

  1. Create new attributes for FillGradient, LineGradient, and eventually; FillPattern, and LinePattern. The disadvantage here is that we can't use the Last semigroup to help with things like d # fc red # fillGradient g.
  2. Expand the SomeColor type to something like Color | Gradient | Pattern. I'm not sure this is possible as I haven't tried to do it yet, but if it is it will save us from dealing with situations like above where a diagram can't have both a fill color and a gradient. The disadvantage is that even if it's doable, it may break existing code.
Member

jeffreyrosenbluth commented Oct 19, 2013

As I see it the first bridge to cross is deciding between the following 2 options.

  1. Create new attributes for FillGradient, LineGradient, and eventually; FillPattern, and LinePattern. The disadvantage here is that we can't use the Last semigroup to help with things like d # fc red # fillGradient g.
  2. Expand the SomeColor type to something like Color | Gradient | Pattern. I'm not sure this is possible as I haven't tried to do it yet, but if it is it will save us from dealing with situations like above where a diagram can't have both a fill color and a gradient. The disadvantage is that even if it's doable, it may break existing code.
@bergey

This comment has been minimized.

Show comment Hide comment
@bergey

bergey Oct 19, 2013

Member

I take it the Gradient type includes a color, possibly two colors?

I think user code that doesn't use gradients should still be able to write # fc red. I don't want to write # fill (Solid red). Either implementation could support that, I think; this way we don't break user code.

(2) will clearly break all the Backends. (1) also has clear behavior for Backends which do not support gradients. If you go with (2), I'd like documentation of how such Backends should fall back to solid color. For these reasons, I have a slight preference for (1).

Member

bergey commented Oct 19, 2013

I take it the Gradient type includes a color, possibly two colors?

I think user code that doesn't use gradients should still be able to write # fc red. I don't want to write # fill (Solid red). Either implementation could support that, I think; this way we don't break user code.

(2) will clearly break all the Backends. (1) also has clear behavior for Backends which do not support gradients. If you go with (2), I'd like documentation of how such Backends should fall back to solid color. For these reasons, I have a slight preference for (1).

@jeffreyrosenbluth

This comment has been minimized.

Show comment Hide comment
@jeffreyrosenbluth

jeffreyrosenbluth Oct 20, 2013

Member

Yes the Gradient type should include a list of stops and colors plus several other fields.

If we go with 1. we need to come up with a way to handle the case where an instance of type class HasStyle could contain both FillColor and FillGradient attributes. I don't think leaving it up to the backends to sort this out is a good idea. One way to handle this is to insure that this never happens. This could be accomplished by augmenting the data structure of attributes to carry a list of "similar attributes" so that we can check for example if a style has a FillColor attribute before adding a FillGradient attribute if FillColor is in FillGradient's similar attributes list. This is quite an invasive change however as all attribute semigroup definitions would need to change as will as the Style semigroup.

The advantage of 2. is this case could not occur. On the other hand gradients should be Transformable, but FillColor is not, this is a further complication to option 2, although I don't think making FillColor transformable where transformations have no effect is so bad.

In the end I think 2. is the cleaner solution, but as bergey points out it will break the backends.

Member

jeffreyrosenbluth commented Oct 20, 2013

Yes the Gradient type should include a list of stops and colors plus several other fields.

If we go with 1. we need to come up with a way to handle the case where an instance of type class HasStyle could contain both FillColor and FillGradient attributes. I don't think leaving it up to the backends to sort this out is a good idea. One way to handle this is to insure that this never happens. This could be accomplished by augmenting the data structure of attributes to carry a list of "similar attributes" so that we can check for example if a style has a FillColor attribute before adding a FillGradient attribute if FillColor is in FillGradient's similar attributes list. This is quite an invasive change however as all attribute semigroup definitions would need to change as will as the Style semigroup.

The advantage of 2. is this case could not occur. On the other hand gradients should be Transformable, but FillColor is not, this is a further complication to option 2, although I don't think making FillColor transformable where transformations have no effect is so bad.

In the end I think 2. is the cleaner solution, but as bergey points out it will break the backends.

@jeffreyrosenbluth

This comment has been minimized.

Show comment Hide comment
@jeffreyrosenbluth

jeffreyrosenbluth Oct 20, 2013

Member

The gradient data structure should look something like this

type GradientStop = (SomeColor, Double)
data SpreadMethod = GradPad | GradReflect | GradRepeat

data LinearGradient p  = LinearGradient { _lGradStops        :: [GradientStop]
                                        , _lGradStart        :: p
                                        , _lGradSEnd         :: p
                                        , _lGradSpreadMethod :: SpreadMethod }

data RadialGradient p  = RadialGradient { _rGradStops        :: [GradientStop]
                                        , _rGradRadius       :: Double
                                        , _rGradCenter       :: p
                                        , _rGradFocus        :: p
                                        , _rGradSpreadMethod :: SpreadMethod }

basically following SVG.

Member

jeffreyrosenbluth commented Oct 20, 2013

The gradient data structure should look something like this

type GradientStop = (SomeColor, Double)
data SpreadMethod = GradPad | GradReflect | GradRepeat

data LinearGradient p  = LinearGradient { _lGradStops        :: [GradientStop]
                                        , _lGradStart        :: p
                                        , _lGradSEnd         :: p
                                        , _lGradSpreadMethod :: SpreadMethod }

data RadialGradient p  = RadialGradient { _rGradStops        :: [GradientStop]
                                        , _rGradRadius       :: Double
                                        , _rGradCenter       :: p
                                        , _rGradFocus        :: p
                                        , _rGradSpreadMethod :: SpreadMethod }

basically following SVG.

@jeffreyrosenbluth

This comment has been minimized.

Show comment Hide comment
@jeffreyrosenbluth

jeffreyrosenbluth Oct 21, 2013

Member

I think option 2 would go something like this where I have begun to implement linear and radial gradients for stroking.
Filling would be similar. Then the backends would have to handle a LineTexture attribute and deal with the 3 cases.

data SomeColor = forall c. Color c => SomeColor c

type GradientStop = (SomeColor, Double)

data SpreadMethod = GradPad | GradReflect | GradRepeat

-- | Linear Gradient
data LGradient = forall p. AffineSpace p => LGradient
    { _lGradStops        :: [GradientStop]
    , _lGradStart        :: p
    , _lGradSEnd         :: p
    , _lGradSpreadMethod :: SpreadMethod }

makeLenses ''LGradient

-- | Radial Gradient
data RGradient = forall p. AffineSpace p => RGradient
    { _rGradStops        :: [GradientStop]
    , _rGradRadius       :: Double
    , _rGradCenter       :: p
    , _rGradFocus        :: p
    , _rGradSpreadMethod :: SpreadMethod }

makeLenses ''RGradient

data Texture = SC SomeColor | LG LGradient | RG RGradient
  deriving Typeable

newtype LineTexture = LineTexture (Last Texture)
  deriving (Typeable, Semigroup)
instance AttributeClass LineTexture

instance Default LineTexture where
    def = LineTexture (Last (SC (SomeColor (black :: Colour Double))))

getLineTexture :: LineTexture -> Texture
getLineTexture (LineTexture (Last t)) = t

lineTexture :: HasStyle a => Texture -> a -> a
lineTexture = applyAttr . LineTexture . Last

lineColor :: (Color c, HasStyle a) => c -> a -> a
lineColor c = lineTexture (SC (SomeColor c))
Member

jeffreyrosenbluth commented Oct 21, 2013

I think option 2 would go something like this where I have begun to implement linear and radial gradients for stroking.
Filling would be similar. Then the backends would have to handle a LineTexture attribute and deal with the 3 cases.

data SomeColor = forall c. Color c => SomeColor c

type GradientStop = (SomeColor, Double)

data SpreadMethod = GradPad | GradReflect | GradRepeat

-- | Linear Gradient
data LGradient = forall p. AffineSpace p => LGradient
    { _lGradStops        :: [GradientStop]
    , _lGradStart        :: p
    , _lGradSEnd         :: p
    , _lGradSpreadMethod :: SpreadMethod }

makeLenses ''LGradient

-- | Radial Gradient
data RGradient = forall p. AffineSpace p => RGradient
    { _rGradStops        :: [GradientStop]
    , _rGradRadius       :: Double
    , _rGradCenter       :: p
    , _rGradFocus        :: p
    , _rGradSpreadMethod :: SpreadMethod }

makeLenses ''RGradient

data Texture = SC SomeColor | LG LGradient | RG RGradient
  deriving Typeable

newtype LineTexture = LineTexture (Last Texture)
  deriving (Typeable, Semigroup)
instance AttributeClass LineTexture

instance Default LineTexture where
    def = LineTexture (Last (SC (SomeColor (black :: Colour Double))))

getLineTexture :: LineTexture -> Texture
getLineTexture (LineTexture (Last t)) = t

lineTexture :: HasStyle a => Texture -> a -> a
lineTexture = applyAttr . LineTexture . Last

lineColor :: (Color c, HasStyle a) => c -> a -> a
lineColor c = lineTexture (SC (SomeColor c))
@bergey

This comment has been minimized.

Show comment Hide comment
@bergey

bergey Oct 22, 2013

Member

I think your earlier version, polymorphic over the point type (or better, the vector space), was correct. Can you actually write a Transformable instance for RGradient with the forall?

I think it's simple enough to specify Backend behavior when there's both a FillColor and a Gradient. I'd expect: use the fc if there is no Gradient or if Gradient is Solid. Otherwise use the Gradient. Backends that don't support gradients can use FillColor always, just as they do now.

One downside is that to override a gradient we'll need to write # solid # fc newColor instead of just # fc newColor. Maybe that's annoying enough that we should roll FillColor into the Gradient type, instead. That means backends that cannot actually render gradients need to handle the gradient constructors anyway. Should they take the color from the first GradientStop?

Member

bergey commented Oct 22, 2013

I think your earlier version, polymorphic over the point type (or better, the vector space), was correct. Can you actually write a Transformable instance for RGradient with the forall?

I think it's simple enough to specify Backend behavior when there's both a FillColor and a Gradient. I'd expect: use the fc if there is no Gradient or if Gradient is Solid. Otherwise use the Gradient. Backends that don't support gradients can use FillColor always, just as they do now.

One downside is that to override a gradient we'll need to write # solid # fc newColor instead of just # fc newColor. Maybe that's annoying enough that we should roll FillColor into the Gradient type, instead. That means backends that cannot actually render gradients need to handle the gradient constructors anyway. Should they take the color from the first GradientStop?

@jeffreyrosenbluth

This comment has been minimized.

Show comment Hide comment
@jeffreyrosenbluth

jeffreyrosenbluth Oct 22, 2013

Member

The code above actually compiles when I drop it into Attributes.hs so I suspect you can write a Transformable instance with forall.

I guess letting the backends handle FillColor and Gradient is a reasonable choice, and you do make a good point about overriding gradients.

I'd like to hear what others think as well.

Member

jeffreyrosenbluth commented Oct 22, 2013

The code above actually compiles when I drop it into Attributes.hs so I suspect you can write a Transformable instance with forall.

I guess letting the backends handle FillColor and Gradient is a reasonable choice, and you do make a good point about overriding gradients.

I'd like to hear what others think as well.

@byorgey

This comment has been minimized.

Show comment Hide comment
@byorgey

byorgey Oct 22, 2013

Member

I agree with @bergey, data LGradient = forall p. AffineSpace p ... does not seem right. In particular that actually corresponds to an existentially quantified p. So if you have an LGradient and you project out e.g. the _lGradStart, it has some particular type but you have no idea which, and the only thing you can do with it is perform AffineSpace operations. It certainly compiles but it does not have the right semantics.

Member

byorgey commented Oct 22, 2013

I agree with @bergey, data LGradient = forall p. AffineSpace p ... does not seem right. In particular that actually corresponds to an existentially quantified p. So if you have an LGradient and you project out e.g. the _lGradStart, it has some particular type but you have no idea which, and the only thing you can do with it is perform AffineSpace operations. It certainly compiles but it does not have the right semantics.

@jeffreyrosenbluth

This comment has been minimized.

Show comment Hide comment
@jeffreyrosenbluth

jeffreyrosenbluth Oct 22, 2013

Member

hmm. The intent was for p to be existentially quantified. I'm not sure AffineSpace is enough but, we will only need a very limited set of operations on p. For example calculating the direction of the gradient _lGradEnd .-. lGradStart.

Member

jeffreyrosenbluth commented Oct 22, 2013

hmm. The intent was for p to be existentially quantified. I'm not sure AffineSpace is enough but, we will only need a very limited set of operations on p. For example calculating the direction of the gradient _lGradEnd .-. lGradStart.

@byorgey

This comment has been minimized.

Show comment Hide comment
@byorgey

byorgey Oct 22, 2013

Member

OK, maybe I just don't understand the semantics of LGradient (and RGradient). I will go read about gradients in SVG before commenting further.

Member

byorgey commented Oct 22, 2013

OK, maybe I just don't understand the semantics of LGradient (and RGradient). I will go read about gradients in SVG before commenting further.

@byorgey

This comment has been minimized.

Show comment Hide comment
@byorgey

byorgey Oct 22, 2013

Member

OK, I have read up on gradients and I understand a bit better now. I am still not convinced about the existential quantification. What is its purpose? Even if you do lGradEnd .-. lGradStart you end up with something of type Diff p but you still don't know what p is, so you cannot use it at all.

I would expect something like

data LGradient v = LGradient
    { _lGradStops        :: [GradientStop]
    , _lGradStart        :: Point v
    ...

That is, the type of a gradient has to tell you what vector space it lives in. Otherwise how would you know what its relationship is with other things that live in some vector space?

(Also, I have intentionally not given any thought to the questions about how to structure things with gradients and fill colors, breaking backends, etc.; I have enough things to think about at the moment, it doesn't seem pressing, and I trust the rest of you to think it through and come up with something reasonable.)

Member

byorgey commented Oct 22, 2013

OK, I have read up on gradients and I understand a bit better now. I am still not convinced about the existential quantification. What is its purpose? Even if you do lGradEnd .-. lGradStart you end up with something of type Diff p but you still don't know what p is, so you cannot use it at all.

I would expect something like

data LGradient v = LGradient
    { _lGradStops        :: [GradientStop]
    , _lGradStart        :: Point v
    ...

That is, the type of a gradient has to tell you what vector space it lives in. Otherwise how would you know what its relationship is with other things that live in some vector space?

(Also, I have intentionally not given any thought to the questions about how to structure things with gradients and fill colors, breaking backends, etc.; I have enough things to think about at the moment, it doesn't seem pressing, and I trust the rest of you to think it through and come up with something reasonable.)

@jeffreyrosenbluth

This comment has been minimized.

Show comment Hide comment
@jeffreyrosenbluth

jeffreyrosenbluth Oct 22, 2013

Member

Ah, I see where I went wrong.
What about the issue of using something like Texture to be the attribute, so that the semigroup handles sorting out FillColor vs LGradient and the backends have to handle Texture or leaving FillColor intact and creating a new gradient attribute and letting the backends sort out FillColor vs LGradient?

Oh, I didn't see the parenthetical to you comment, go ahead and disregard my last question?

Member

jeffreyrosenbluth commented Oct 22, 2013

Ah, I see where I went wrong.
What about the issue of using something like Texture to be the attribute, so that the semigroup handles sorting out FillColor vs LGradient and the backends have to handle Texture or leaving FillColor intact and creating a new gradient attribute and letting the backends sort out FillColor vs LGradient?

Oh, I didn't see the parenthetical to you comment, go ahead and disregard my last question?

@jeffreyrosenbluth

This comment has been minimized.

Show comment Hide comment
@jeffreyrosenbluth

jeffreyrosenbluth Oct 22, 2013

Member

@bergey Hard to say where the backends should take their color from is they don't support gradients. Depending on where the user assumes the light is coming from any of the stops could make the most sense. Perhaps the backend should just ignore gradients and us the default color - i.e. clear.

Member

jeffreyrosenbluth commented Oct 22, 2013

@bergey Hard to say where the backends should take their color from is they don't support gradients. Depending on where the user assumes the light is coming from any of the stops could make the most sense. Perhaps the backend should just ignore gradients and us the default color - i.e. clear.

@jeffreyrosenbluth

This comment has been minimized.

Show comment Hide comment
@jeffreyrosenbluth

jeffreyrosenbluth Oct 24, 2013

Member

Adding gradients for strokes might look something like this for R2.

  1. I'm not sure if this can be generalized for an arbitrary vector space v
  2. If we only implement gradients for R2, this code should probably be in TwoD. However it would be very strange to put the LineColor attribute which does not depend on a vector space in TwoD. Also gradients should be transformable and colors are not so making them transformable to be part of a Texture attribute is a bit of a hack.
  3. I'm thinking if we cant generalize this code to arbitrary v perhaps gradients should be a separate attribute.

thoughts?

class Color c where
  -- | Convert a color to its standard representation, AlphaColour
  toAlphaColour :: c -> AlphaColour Double

-- | An existential wrapper for instances of the 'Color' class.
data SomeColor = forall c. Color c => SomeColor c

type GradientStop = (SomeColor, Double)

data SpreadMethod = GradPad | GradReflect | GradRepeat

-- | Linear Gradient
data LGradient = LGradient
    { _lGradStops        :: [GradientStop]
    , _lGradStart        :: P2
    , _lGradSEnd         :: P2
    , _lGradSpreadMethod :: SpreadMethod }

makeLenses ''LGradient

-- | Radial Gradient
data RGradient = RGradient
    { _rGradStops        :: [GradientStop]
    , _rGradRadius       :: Double
    , _rGradCenter       :: P2
    , _rGradFocus        :: P2
    , _rGradSpreadMethod :: SpreadMethod }

makeLenses ''RGradient

data Texture = SC SomeColor | LG LGradient | RG RGradient
  deriving (Typeable)

newtype LineTexture = LineTexture (Last Texture)
  deriving (Typeable, Semigroup)
instance AttributeClass LineTexture

type instance V LineTexture = R2

instance Transformable LineTexture where
  transform t l@(LineTexture (Last (SC _))) = l
  -- XXX Need to handle linear and radial grandient transforms.
  transform t l@(LineTexture lt) = l

instance Default LineTexture where
    def = LineTexture (Last (SC (SomeColor (black :: Colour Double))))

getLineTexture :: LineTexture -> Texture
getLineTexture (LineTexture (Last t)) = t

lineTexture :: (HasStyle a, V a ~ R2) => Texture-> a -> a
lineTexture = applyTAttr . LineTexture . Last

lineColor :: (Color c, HasStyle a, V a ~ R2) => c -> a -> a
lineColor c = lineTexture (SC (SomeColor c))

-- | A synonym for 'lineColor', specialized to @'Colour' Double@
--   (i.e. opaque colors).
lc :: (HasStyle a, V a ~ R2) => Colour Double -> a -> a
lc = lineColor

-- | A synonym for 'lineColor', specialized to @'AlphaColour' Double@
--   (i.e. colors with transparency).
lcA :: (HasStyle a, V a ~ R2) => AlphaColour Double -> a -> a
lcA = lineColor

lineLGradient :: (HasStyle a, V a ~ R2) => LGradient -> a -> a
lineLGradient g = lineTexture (LG g)

lineRGradient :: (HasStyle a, V a ~ R2) => RGradient -> a -> a
lineRGradient g = lineTexture (RG g)
Member

jeffreyrosenbluth commented Oct 24, 2013

Adding gradients for strokes might look something like this for R2.

  1. I'm not sure if this can be generalized for an arbitrary vector space v
  2. If we only implement gradients for R2, this code should probably be in TwoD. However it would be very strange to put the LineColor attribute which does not depend on a vector space in TwoD. Also gradients should be transformable and colors are not so making them transformable to be part of a Texture attribute is a bit of a hack.
  3. I'm thinking if we cant generalize this code to arbitrary v perhaps gradients should be a separate attribute.

thoughts?

class Color c where
  -- | Convert a color to its standard representation, AlphaColour
  toAlphaColour :: c -> AlphaColour Double

-- | An existential wrapper for instances of the 'Color' class.
data SomeColor = forall c. Color c => SomeColor c

type GradientStop = (SomeColor, Double)

data SpreadMethod = GradPad | GradReflect | GradRepeat

-- | Linear Gradient
data LGradient = LGradient
    { _lGradStops        :: [GradientStop]
    , _lGradStart        :: P2
    , _lGradSEnd         :: P2
    , _lGradSpreadMethod :: SpreadMethod }

makeLenses ''LGradient

-- | Radial Gradient
data RGradient = RGradient
    { _rGradStops        :: [GradientStop]
    , _rGradRadius       :: Double
    , _rGradCenter       :: P2
    , _rGradFocus        :: P2
    , _rGradSpreadMethod :: SpreadMethod }

makeLenses ''RGradient

data Texture = SC SomeColor | LG LGradient | RG RGradient
  deriving (Typeable)

newtype LineTexture = LineTexture (Last Texture)
  deriving (Typeable, Semigroup)
instance AttributeClass LineTexture

type instance V LineTexture = R2

instance Transformable LineTexture where
  transform t l@(LineTexture (Last (SC _))) = l
  -- XXX Need to handle linear and radial grandient transforms.
  transform t l@(LineTexture lt) = l

instance Default LineTexture where
    def = LineTexture (Last (SC (SomeColor (black :: Colour Double))))

getLineTexture :: LineTexture -> Texture
getLineTexture (LineTexture (Last t)) = t

lineTexture :: (HasStyle a, V a ~ R2) => Texture-> a -> a
lineTexture = applyTAttr . LineTexture . Last

lineColor :: (Color c, HasStyle a, V a ~ R2) => c -> a -> a
lineColor c = lineTexture (SC (SomeColor c))

-- | A synonym for 'lineColor', specialized to @'Colour' Double@
--   (i.e. opaque colors).
lc :: (HasStyle a, V a ~ R2) => Colour Double -> a -> a
lc = lineColor

-- | A synonym for 'lineColor', specialized to @'AlphaColour' Double@
--   (i.e. colors with transparency).
lcA :: (HasStyle a, V a ~ R2) => AlphaColour Double -> a -> a
lcA = lineColor

lineLGradient :: (HasStyle a, V a ~ R2) => LGradient -> a -> a
lineLGradient g = lineTexture (LG g)

lineRGradient :: (HasStyle a, V a ~ R2) => RGradient -> a -> a
lineRGradient g = lineTexture (RG g)
@bergey

This comment has been minimized.

Show comment Hide comment
@bergey

bergey Oct 24, 2013

Member

I think you're right that the sort of textures and patterns we'd want to support in 3D are quite different from these. But the plan for 3D is to not use FillColor, and instead use new attributes that make sense under lighting (eg, diffuse, specular). So the situation I worried about where 3D backends have no plan to support gradients but need to handle gradient constructors isn't really a problem.

Member

bergey commented Oct 24, 2013

I think you're right that the sort of textures and patterns we'd want to support in 3D are quite different from these. But the plan for 3D is to not use FillColor, and instead use new attributes that make sense under lighting (eg, diffuse, specular). So the situation I worried about where 3D backends have no plan to support gradients but need to handle gradient constructors isn't really a problem.

@jeffreyrosenbluth

This comment has been minimized.

Show comment Hide comment

@bergey bergey referenced this issue Nov 13, 2013

Merged

Gradient #136

@bergey bergey closed this Apr 23, 2014

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment