On 30 May 2010 23:08, Stéphane Ducasse <[email protected]> wrote: > cool post >
Yeah, these things are quite interesting. Except that not much people actually interested in it :) Here's another thing, which can be done right (if we want). Rome/OpenVG Paths is actually nothing else than a special kind of more general thing - shape. So, at very basis, we should have only two components for painting: shape and paint. And in fact we need to support only a single operation: fill the shape with given paint. (The path stroke could be seen as a special kind of fill) So the question is: Really. Why we should constrain ourselves with specific things from a very starting, by cutting out a most basic (and abstact ideas) behind? There are infinite number of ways, how one could define a shape. While paths is only a small, yet effective representation of shapes. In same way there are infinite number of ways how one could define a paint. Then this looks like a strong basis for building-up a powerful & flexible graphics engine :) > Stef > > On May 30, 2010, at 8:53 PM, Igor Stasenko wrote: > >> On 30 May 2010 17:26, Stéphane Ducasse <[email protected]> wrote: >>>> Hi, >>>> >>>> i found rome API very close to OpenVG. >>>> Still OpenVG is a bit superior :) >>>> So, i'm using it as a guide to model/implement Rome interfaces. >>> >>> Excellent! >>> >>>> So, here is my thoughts (i also having a draft class skeleton for them): >>> >>> frankly consider that we are working on Rome because we need something >>> to get access to Cairo/ whatever but we are newbie at the level. >>> Now the good point for us is that we are smart newbies :) >>> and ready to learn fast. >>> >>> So our first idea is >>> - make it work (romePluginCanvas) >>> - make all romeReferenceCanvas >>> >>> Get feedback, improve it improve it improve it >>> as well as make all the code use it make all the code use it . >>> >>> So thanks for your brainstorming/ideas/wishes >>> >>> >>>> Because, we could simply do: >>>> >>>> canvas fill: myPath with: myPaint >>>> >>>> instead of: >>>> >>>> canvas selectFill: myPaint. >>>> canvas fill: myPath. >>>> >>>> Because you anyways can't draw a paths without paints, i don't see why >>>> canvas should have a notion of 'current fill' or 'current paint'. >>>> I think that with paint's encapsulation, its not necessary. >>>> >>>> >>>> I'd like to hear your thoughts about it. >>> >>> No idea. Now at the back end level or "reference level" >>> is there a value to separate? >>> because like that you can do >>> >>>> canvas selectFill: myPaint. >>>> canvas fill: myPath. >>>> canvas fill: myPath.canvas fill: myPath.canvas fill: myPath.canvas fill: >>>> myPath.canvas fill: myPath.canvas fill: myPath.canvas fill: myPath. >>> >> >> Right. I considered that too, before proposing ;) >> Selecting a paint and then drawing multiple paths using it may look >> like having some value. >> >> But the point is, that in practice you barely will use such feature. >> >> For instance, lets take a morph: >> >> Morph>>romeDrawOn: aCanvas >> aCanvas >> selectFill: self fillStyle; >> selectPen: self borderStyle; >> drawRectangle: self bounds >> >> Do you seen how you can reuse a previously selected paints here? I don't. >> You can't reuse, because you don't know what was selected previously >> (and querying it will cost you more cycles >> than just selecting a right one). >> >> So, that's how you will use it in 99% of cases: >> >> select >> fill >> select >> fill.. >> >> But not >> >> select >> fill fill fill .. >> >> One more example. A Tiger demo, which i did in OpenVG binding. >> A Tiger takes it roots from an SVG file, so it is right to say, that >> it covers the use of SVG for drawings. >> In SVG, each particular path it having own stroke/fill parameters. >> There is no way how you can reuse a previously selected paints, >> because each unique fragment having own settings, >> and even if a whole scene (as big as Tiger) using similar paints >> multiple times, you still can't reuse them because you need to follow >> the order of drawing (iterating over a collection of paths, but not a >> collection of paints), otherwise you won't get what you expecting to >> see. >> >> You can reuse paints by creating them, and then caching , so it won't >> cost you a conversion, each time you using it. >> (For instance you can convert a GradientFillStyle to appropriate paint >> object, and cache it somewhere). >> But selecting the paint costs nothing, and buys nothing in terms of >> speed (at least in my implementation, and i suspect in every other ;) >> ). >> >> I think that 'selection' and 'binding' mechanism in those APIs serve >> only one purpose: to minimize the number of arguments >> for function calls and as a workaround of having no OO. >> But in smalltalk world, we having objects, which can represent any >> kind of our domain objects (paths, paints etc), >> and so, from OO perspective binding/selecting looks like a useless thing. >> >> A big downside of such selection mechanism can be illustrated by taking >> OpenGL. >> It is cool, when you having one window, one context, one texture and >> one pencil to rule them all. >> But in practice, you often need more than one canvas, window, texture etc. >> And this is where such 'selection' mechanism starts standing in your way. >> For instance, if you working with multiple GL contexts in squeak, the >> only way how to ensure that you _always_ >> working with right context is to prepend each api call with: >> makeCurrent(myContextHandle). >> by literally turning every gl function like: func(a, b, c) into >> func(context, a, b, c) >> otherwise, you can't ensure a correct behavior, when you working with >> multiple contexts in multiple processes, >> having high chances being interrupted by each other. >> >> This is where passing an extra argument(s) is preferable, because it >> tells directly, with what object you wanna work with and so it >> minimizes the chances to make a mess. :) >> >>> >>> Stef >>> >>> >>>> Paints: >>>> >>>> Paint is an object, which when applied to path, renders(draws) the >>>> path using paint's unique properties. >>>> >>>> I defined two methods in paint's base class: >>>> >>>> fillPath: aPath on: aCanvas >>>> >>>> self subclassResponsibility >>>> >>>> strokePath: aPath on: aCanvas >>>> >>>> self subclassResponsibility >>>> >>>> So, to draw a path, one should use a concrete paint to either fill it >>>> or stroke it (or both, if you want, but its handled by canvas and >>>> still will end up with separate fill & stroke requests to paint). >>>> >>>> I started from a quite basic things: >>>> >>>> NullPaint >>>> Paint which does not performs any drawing. >>>> Applying this paint to any path won't lead to any >>>> changes/processing. A simple OO approach to define 'nothing' :) >>>> >>>> SolidColorPaint >>>> instanceVariableNames: 'color' >>>> >>>> Paint with solid color. Most trivial thing which can be done :) >>>> >>>> RomePen >>>> instanceVariableNames: 'paint capStyle joinStyle width dash' >>>> >>>> A 'pen' paint is just encapsulating a set of properties, which is used >>>> for stroke. >>>> It is using another paint, which should handle the fills (in 'paint' >>>> ivar), while various stroke properties should be handled by itself. >>>> Filling with pen, will be the same as filling with its paint. While >>>> doing a stoke is different (includes path processing, given the values >>>> of pen's properties etc etc). >>>> I'm not sure with this part. Maybe stroke properties would be better >>>> to leave in canvas? Both OpenVG and Rome seems like following this >>>> road, >>>> but i don't quite like that stroke properties is global for canvas and >>>> lacking a proper encapsulation. >>>> >>>> CompositePaint >>>> Quite dumb thing. Holds a list of paints. When asked to fill or >>>> stroke the path, applies paints from own list. >>>> >>>> GradientPaint (abstract) >>>> LinearGradient >>>> RadialGradient >>>> etc.. >>>> paints which will use gradients for fills. Nothing fancy :) >>>> >>>> >>>> Canvas protocol: >>>> >>>> selectFill: anObject >>>> >>>> fill := anObject asRomePaintOn: self >>>> >>>> - selects a paint which will be used for fills. >>>> >>>> selectPen: anObject >>>> >>>> pen := anObject asRomePaintOn: self >>>> >>>> - selects a paint which will be used for stokes. >>>> >>>> >>>> stroke: anObject >>>> | path | >>>> path := anObject asRomePathOn: self. >>>> >>>> fill strokePath: path on: self. >>>> >>>> - stroke a path using currently selected 'pen' paint >>>> >>>> fill: anObject >>>> | path | >>>> path := anObject asRomePathOn: self. >>>> >>>> fill fillPath: path on: self. >>>> >>>> - fill path using paint for fills >>>> >>>> >>>> fillAndStroke: anObject >>>> | path | >>>> path := anObject asRomePathOn: self. >>>> >>>> fill fillPath: path on: self. >>>> pen strokePath: path on: self >>>> >>>> - fill and stroke path. >>>> >>>> And from that point, i wonder, do we need to have a paint's selection >>>> mechanisms at all? >>>> >>>> Because, we could simply do: >>>> >>>> canvas fill: myPath with: myPaint >>>> >>>> instead of: >>>> >>>> canvas selectFill: myPaint. >>>> canvas fill: myPath. >>>> >>>> Because you anyways can't draw a paths without paints, i don't see why >>>> canvas should have a notion of 'current fill' or 'current paint'. >>>> I think that with paint's encapsulation, its not necessary. >>>> >>>> >>>> I'd like to hear your thoughts about it. >>>> >>>> >>>> -- >>>> Best regards, >>>> Igor Stasenko AKA sig. >>>> >>>> _______________________________________________ >>>> Pharo-project mailing list >>>> [email protected] >>>> http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project >>> >>> >>> _______________________________________________ >>> Pharo-project mailing list >>> [email protected] >>> http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project >>> >> >> >> >> -- >> Best regards, >> Igor Stasenko AKA sig. >> >> _______________________________________________ >> Pharo-project mailing list >> [email protected] >> http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project > > > _______________________________________________ > Pharo-project mailing list > [email protected] > http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project > -- Best regards, Igor Stasenko AKA sig. _______________________________________________ Pharo-project mailing list [email protected] http://lists.gforge.inria.fr/cgi-bin/mailman/listinfo/pharo-project
