On 6 April 2016 at 10:35, Nicolai Hess <[email protected]> wrote:

>
>
> 2016-04-05 16:31 GMT+02:00 Igor Stasenko <[email protected]>:
>
>>
>>
>> On 5 April 2016 at 17:27, Igor Stasenko <[email protected]> wrote:
>>
>>>
>>>
>>> On 5 April 2016 at 16:29, Aliaksei Syrel <[email protected]> wrote:
>>>
>>>> Now let's take a look at this code:
>>>>
>>>> drawOnSpartaCanvas: aCanvas
>>>>
>>>>> aCanvas
>>>>>   clipPreserveBy: self shape during: [
>>>>>   aCanvas paintGroup: [
>>>>> aCanvas setPaint: self shape fillPaint.
>>>>> aCanvas fillPreserve.
>>>>> aCanvas paintMode source.
>>>>> aCanvas setStrokePaint: self shape strokePaint.
>>>>> aCanvas stroke ] ]
>>>>
>>>>
>>>> You may be curious why it is so ugly :) Make it work - make it right -
>>>> make it fast. We are on the first etappe, because I invested zero time in
>>>> rendering stuff.
>>>>
>>>> What you see is the minimal amount of cairo primitive calls that are
>>>> needed to render not overlapping fill and stroke. Clipping is needed to
>>>> make sure that stroke does not get rendered outside of a path. Group is
>>>> needed to have transparent target in order to make source paint mode work
>>>> as expected. Compared to image_surface group, it in this case allows to
>>>> preserve clip and current cairo state which is pushed to stack during
>>>> push_group and restored during pop_group_to_source. fillPreserve allows to
>>>> reuse the same path as used for clipping before saving cpu time on loading
>>>> path.
>>>>
>>>> Yes, i understand that. You are forced to do that. And it is ugly not
>>> because of all you listed above, it ugly because you could just use a
>>> cascade:
>>>
>>> aCanvas setPaint: self shape fillPaint;
>>>   fillPreserve;
>>>    paintMode source;
>>>    setStrokePaint: self shape strokePaint;
>>> stroke
>>>
>>> (something like that)
>>> but yeah.. that can wait .. since it is still work in progress. I agree.
>>>
>>>
>>>> It is implemented in canvas specific method after dispatch though
>>>> canvas, so we are allowed to use canvas specific api, for example groups.
>>>>
>>>> How to model stroke, fillPreserve and paintModein terms of Athens?
>>>>
>>>>
>>> A good question. And i don't have an answer to it , ready for you.
>>> 1. Stroke can be expressed as a special kind of paint. And that how its
>>> done in Athens.
>>>
>>> 2. What fillPreserve is, is can't find it in source code? Some
>>> hot-swapping and preserving context state , i guess.
>>>
>>> 3. As for paint mode, it is already in Athens, so why you asking? You
>>> don't like how it is done or what?
>>>
>>>
>> or maybe you meant how to group those operation and express them as
>> command group?
>> I have no simple answer here. Because this is root points of the core of
>> graphics engine. From one side, you want such things be exposed to user,
>> and from other you want a higher dimension concepts/operations to be
>> allowed by combining those.
>> There's no simple way. I would just stop at this level, letting user to
>> decide how he wants to play with those pieces to achieve results he wants.
>>
>
>
> Grouping and Context save/restore are good additions - I think.
>
> But it is true, that we should care about the api of Athens and not just
> add things that happens to be possible, because we use cairo as a backend.
>
> I made some fixes for AthensBalloon (not all are integrated yet, some
> parts are just experimental and needs more tests), the idea is to have
> AthensBalloon at least not crash or throwing  errors, even if not all
> features are supported.
>

Much, much, much appreciated. The whole point of existence of Balloon
backend for Athens was to use it as a proving ground that Athens can stay
backend neutral, and its API allows to stay it like that.
>From that perspective, any feature that offered by any backend should find
its way via API, but not thrown into play just because we can.
As i mentioned before, if we would be making Cairo wrapper, then there no
reason to call it Athens. It could be something like 'CairoPharo'.

And i kept mentioned over and over again on all presentations related to
Athens, that it is not Cairo.

But at the moment, no one cares about non-cairo-athens. All users just
> directly use AthensCairoCanvas/AthensCairoSurface.
> I had a bug report for discussion about how to make some kind of factory
> that would create the appropriate Athens backend.
>
> Is there still some interest on AthensBalloon or to make athens more
> independent from cairo?
>
>
>

It always been. But didn't have much time to make that happen.
For instance, i dream to make an OpenGL backend for Athens.. but i had no
chance to put my hands on that topic so far.


>
>>
>>
>>>
>>>> Cheers,
>>>> Alex
>>>>
>>>> On Tue, Apr 5, 2016 at 3:15 PM, Aliaksei Syrel <[email protected]>
>>>> wrote:
>>>>
>>>>> Hello Igor
>>>>>
>>>>> Thanks for extensive design explanation and effort!
>>>>> Issues you mentioned in previous emails are important and need to be
>>>>> addressed :)
>>>>> fill(), stroke() fillPreserve() strokePreserve() need to disappear in
>>>>> the end. We will come back to them later.
>>>>>
>>>>> Let me tell a few words about Sparta.
>>>>> Sparta implements Athens interface api (excluding some experimental
>>>>> stuff to test possible performance boost in a few places) and does not 
>>>>> have
>>>>> task to remove Athens style and abstractions. Ideally Sparta will be
>>>>> AthensCairo for bloc. I'm looking forward for your help :)
>>>>>
>>>>> Here are some aspects in AthensCairo that Sparta tries to address in
>>>>> first place:
>>>>>
>>>>>    - *Clipping in local coordinates*. It is critical in Bloc. You
>>>>>    implemented AthensCairo to have vector based rendering in Morphic and 
>>>>> Pharo
>>>>>    in general. Morphic lives in global coordinates, so your choice to 
>>>>> clip in
>>>>>    global coordinate is perfect! At the same time global clipping in bloc 
>>>>> adds
>>>>>    complexity. Sparta clips always in local coordinates (user space in 
>>>>> cairo
>>>>>    terminology).
>>>>>    - *Clip by arbitrary path*. Athens and AthenCairo expect to see
>>>>>    aRectangle as clipping region - your wise choice for morphic. In bloc I
>>>>>    would have clipping by arbitrary path. clipBy:during: gets aPath.
>>>>>    Rectangle/Color is polymorphic with path/paint in Sparta
>>>>>    - *Support of groups*. (maybe user-level aspect? like shadows)
>>>>>    Groups are powerful in cairo (do they exist outside of cairo?) and 
>>>>> allow to
>>>>>    draw both transparent fill and stroke without overlapping using only 
>>>>> one
>>>>>    path. On class side of BlElement there are examples (exampleCircle) 
>>>>> that
>>>>>    show such behavior.
>>>>>    - *Do not maintain and set pathTransformation before each
>>>>>    render-dependent action.* Questionable but what if Canvas will not
>>>>>    maintain current state of pathTransform? Instead all transformations 
>>>>> can be
>>>>>    directly applied on cairo_t using native calls. If there is a need to 
>>>>> get
>>>>>    actual matrix we can ask cairo directly. From my perspective it 
>>>>> simplifies
>>>>>    transformation stuff a little bit.
>>>>>    - *Benefit from cairo_save and cairo_restore.* AthensCairo
>>>>>    maintains state manually by setting transformation matrix and clip. 
>>>>> Instead
>>>>>    we could save and restore state without caring about clip/matrix which
>>>>>    simplifies code. Check SpartaCanvas>>#clipBy:during:
>>>>>
>>>>>
>>>>> Cheers,
>>>>> Alex
>>>>>
>>>>> On Tue, Apr 5, 2016 at 2:12 PM, Igor Stasenko <[email protected]>
>>>>> wrote:
>>>>>
>>>>>>
>>>>>> Couple more words about that fill() function abstraction.
>>>>>> Now you probably understand why there's no notion of stroke operation
>>>>>> in Athens.
>>>>>> Because instead of introducing it that way, by adding new kind of a
>>>>>> function
>>>>>> stroke(shape,paint)
>>>>>> from our perspective, it falls into our more generic fill() function,
>>>>>> except that
>>>>>> instead of literally filling the shape we deciding to paint a stroke:
>>>>>> fill(shape, strokePaint).
>>>>>>
>>>>>> As i said, there's nothing that tells that fill() function must
>>>>>> affect only areas enclosed by the shape.
>>>>>> For instance, you could imagine, that i'm in contrary, may want to
>>>>>> fill everything , but the area(s) enclosed by given shape. And that still
>>>>>> can be represented as invocation of our generic fill() function, except
>>>>>> that we will use a different kind of paint, that will fill everything
>>>>>> outside designated region, i.e.:
>>>>>> fill(shape, fillOutsidePaint)
>>>>>>
>>>>>>
>>>>>>
>>>>>> On 5 April 2016 at 14:33, Igor Stasenko <[email protected]> wrote:
>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> On 5 April 2016 at 04:00, Ben Coman <[email protected]> wrote:
>>>>>>>
>>>>>>>> On Tue, Apr 5, 2016 at 2:51 AM, Igor Stasenko <[email protected]>
>>>>>>>> wrote:
>>>>>>>> >
>>>>>>>> > Some more bashing today.. (don't take it personal, i may be wrong)
>>>>>>>> >
>>>>>>>> > BlPath hierarchy.. and BlShape.
>>>>>>>> >
>>>>>>>> > Why you redefining what is shape and what is path?
>>>>>>>> > Of course, you are free to do it in Bloc..
>>>>>>>> > But in terms of Athens, all of BlPath are actually - shapes..
>>>>>>>> > And BlShape is some kind of encapsulation of shape, paints and
>>>>>>>> transform.
>>>>>>>> > It is a dumb state holder without any extra logic.
>>>>>>>> >
>>>>>>>> > My rule of thumb: do not produce dumb state holders. They has to
>>>>>>>> be smart,
>>>>>>>> > else it makes no sense in creating separate entity and
>>>>>>>> designating it as
>>>>>>>> > something else than any other bunch of data thrown into single
>>>>>>>> clump,
>>>>>>>> > sitting there deaf, blind, dead and silent until someone else
>>>>>>>> will grab it
>>>>>>>> > somewhere
>>>>>>>> > and start using it for own purpose.
>>>>>>>> >
>>>>>>>> > Sure, i could understand, why you potentially may want such
>>>>>>>> object(s)
>>>>>>>> > around,
>>>>>>>> > but it is not shape anymore and i wouldn't call it like that.
>>>>>>>> Because shape
>>>>>>>> > are shape, and has nothing to do with paints and transform,
>>>>>>>> > it don't knows and don't cares whether it will be filled or
>>>>>>>> stroked or both,
>>>>>>>> >  and how many times, and if there will be single paint or
>>>>>>>> thousand.
>>>>>>>> > Such kind of properties is simply orthogonal to what shape
>>>>>>>> existing for,
>>>>>>>> > because it exists only to define geometry.
>>>>>>>> >
>>>>>>>> > I think all of that came from not understanding the roles of
>>>>>>>> objects and how
>>>>>>>> > they interact in Athens.
>>>>>>>>
>>>>>>>> Can you point us to documentation that describes Athen's
>>>>>>>> architecture
>>>>>>>> for these interactions?
>>>>>>>> (sorry I haven't checked class comments, but I'm looking to start
>>>>>>>> with
>>>>>>>> something at higher level anyway)
>>>>>>>>
>>>>>>>
>>>>>>> No, i can't point it out. And you are right , this is nobody else's
>>>>>>> fault than my own. I feel ashamed. Sure how i could demand that people
>>>>>>> understand the concepts, if i didn't explained then anywhere (or if i 
>>>>>>> did,
>>>>>>> it is not in easily reachable place).
>>>>>>>
>>>>>>> So, lets fix that. I will write it down here, and you can pick it up
>>>>>>> and find suitable place for it.
>>>>>>>
>>>>>>> ----------
>>>>>>> Basic abstractions behind Athens.
>>>>>>>
>>>>>>> Since Athens is about drawing graphics, we need a media where all
>>>>>>> drawing operations will appear. We call that media a surface.
>>>>>>> The surface is abstract. It can have set dimensions, or don't.  We
>>>>>>> don't define if it representing some kind of physical surface (like 
>>>>>>> part of
>>>>>>> the display screen), or how it storing the data inside. We leaving an
>>>>>>> introduction of such details to concrete surface implementation.
>>>>>>> All that matters is that surface is a final target of all our
>>>>>>> drawing operations.
>>>>>>> Therefore, in Athens, a surface is usually a starting point where
>>>>>>> all begins from, and you doing so by creating a specific surface.
>>>>>>> It is surface's responsibility then, to provide user a means how he
>>>>>>> can draw on it, and therefore there is a number of factory methods, that
>>>>>>> allowing you to create a canvas, paints and shapes. All those three are
>>>>>>> specific implementation of AthensCanvas, AthensPaint and AthensShape
>>>>>>> protocols, suitable to be used with specific surface implementation that
>>>>>>> you using.
>>>>>>>
>>>>>>> Canvas.
>>>>>>> Canvas represents a basic drawing context. We don't allow a direct
>>>>>>> operations with surface, but instead we provide a context, that contains
>>>>>>> and carries all information that represents a current stage of drawing
>>>>>>> operations.
>>>>>>> This includes things like, current coordinate transformation(s),
>>>>>>> currently selected paint and shape, and paint mode.
>>>>>>>
>>>>>>> In order to obtain canvas, one must use #drawDuring: message sent to
>>>>>>> surface with block as argument. The given block receives an instance of
>>>>>>> AthensCanvas as a single parameter. We intentionally enclosing all 
>>>>>>> possible
>>>>>>> drawing operations within a block to make sure that when we leave, we 
>>>>>>> can
>>>>>>> safely release all resources that was allocated, required to hold the
>>>>>>> drawing context state. By exposing it in such form, we also making sure
>>>>>>> that nothing can alter the surface outside a given block. That way, it
>>>>>>> gives users a definitive answer, whether he finished drawing operations 
>>>>>>> or
>>>>>>> not, and if it safe to operate with surface for things like saving it to
>>>>>>> file, or using it as a source for more complex operations, like acting 
>>>>>>> as a
>>>>>>> paint to fill area(s) inside another surface etc.
>>>>>>>
>>>>>>> Paints and shapes.
>>>>>>> A starting point is answering a question, how we can represent a
>>>>>>> simplest, elementary drawing operation on a surface without putting too
>>>>>>> much constraints.
>>>>>>> We doing so by postulating that any elementary drawing operation can
>>>>>>> be expressed by a function:
>>>>>>>
>>>>>>> fill(paint, shape)
>>>>>>>
>>>>>>> Please, note that 'fill' here is not a literally fill given shape
>>>>>>> with given paint. We call it 'fill' for simplicity reason. It can 
>>>>>>> anything
>>>>>>> that altering the surface, but always taking into account given 
>>>>>>> parameters:
>>>>>>> paint and shape.
>>>>>>>
>>>>>>> Then, from that perspective we can clearly say what are the roles
>>>>>>> and responsibility of shapes and paints.
>>>>>>>
>>>>>>> The shape defines the affected region, its geometry and location,
>>>>>>> while paint defines how that region will be altered.
>>>>>>> In this way, most of more complex operations can be expressed as a
>>>>>>> series of such function invocations by using various paints and shapes.
>>>>>>>
>>>>>>> Such representation also gives us a minimal set of roles, a building
>>>>>>> bricks, that we need to introduce in order to represent any kind of 
>>>>>>> drawing
>>>>>>> operation we may need, as well as a minimal functionality in order to
>>>>>>> implement such function(s). And therefore a minimal protocol(s), that 
>>>>>>> all
>>>>>>> paints and shapes should implement.
>>>>>>>
>>>>>>> Since there potentially infinite number of various paint kinds and
>>>>>>> shape kinds, we cannot make a single function that will implement all
>>>>>>> possible permutations in order to fill shape with concrete paint.
>>>>>>> To solve that we introducing a straight dispatch mechanism, where we
>>>>>>> delegate the responsibility of implementing a concrete case, first to
>>>>>>> shape, and then to paint.
>>>>>>>
>>>>>>> The API representing this function in canvas by #draw protocol.
>>>>>>> It takes currently selected paint and currently selected shape and
>>>>>>> starting dispatch:
>>>>>>>
>>>>>>> draw
>>>>>>> "Fill the currently selected shape with currently selected paint"
>>>>>>> ^ shape paintFillsUsing: paint on: self
>>>>>>>
>>>>>>> So, first it goes to the shape, by sending #paintFillsUsing:on: ,
>>>>>>> then shape dispatching it further to paint by sending appropriate
>>>>>>> message
>>>>>>> (be it #athensFillPath:on: or #athensFillRectangle:on: or anything
>>>>>>> else, if you want to introduce new kind of shape representation and
>>>>>>> implement it accordingly).
>>>>>>> Such dispatch gives us an ability to easily extend the framework by
>>>>>>> introducing new kind of shapes and paints , by implementing new kind of
>>>>>>> fill() functions for them.
>>>>>>>
>>>>>>> -----------
>>>>>>>
>>>>>>> I hope that will make clear at least part of things what is there,
>>>>>>> behind the scenes.
>>>>>>>
>>>>>>>
>>>>>>>> cheers -ben
>>>>>>>>
>>>>>>>>
>>>>>>>
>>>>>>> --
>>>>>>> Best regards,
>>>>>>> Igor Stasenko.
>>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>> --
>>>>>> Best regards,
>>>>>> Igor Stasenko.
>>>>>>
>>>>>
>>>>>
>>>>
>>>
>>>
>>> --
>>> Best regards,
>>> Igor Stasenko.
>>>
>>
>>
>>
>> --
>> Best regards,
>> Igor Stasenko.
>>
>
>


-- 
Best regards,
Igor Stasenko.

Reply via email to