[Cuis-dev] VectorGraphics and Morph

Juan Vuletich juan at jvuletich.org
Fri Jun 19 07:42:46 PDT 2020


Hi Hilaire,

On 6/19/2020 7:41 AM, Hilaire Fernandes via Cuis-dev wrote:
>
> Hello,
>
> I will resume my understanding of the situation and I will make an 
> hopefully small request to Juan.
>
> VectorGraphics canvas long time objective is to move from bitmap 
> canvas to vector canvas. Then, the whole Cuis display content will be 
> defined with vector operations. When needed, to display the whole 
> screen or to refresh a damaged area, a rasterizing will occur. I think 
> this part is pretty tricky with vector canvas.
>
> As long as the Cuis world relies on the bitmap canvas, it is not 
> directly possible to use vector operations to draw a morph because the 
> canvas argument in the drawOn: is bitmap based and therefore does not 
> understand the vector operations
>

Yep. Right.

> Nevertheless, as shown with the circular toolbar, with a small hack, 
> it is possible to draw a morph with vector operations. You needs to 
> instantiate an intermediate vector canvas and a form where 
> rasterization will take place. If you remember, Juan did some recent 
> changes to make this work smoothly with transparent Form (a ticket was 
> open to make the change hopefully permanent in the BitBlt plugin, for 
> faster  rendering). As a side benefit, the form instances are kept as 
> cache for quick Morph rendering. As long as the Morph size does not 
> change, no more vectors and rasterization operations are needed.
>
> So all in all, although the Cuis canvas is still defined with Bitmap 
> operations, it is now possible to have nice looking vector Morphs.
>
> The typical code of such a Morph will look like this:
>
> *drawOn: aCanvas*
>      aCanvas
>          image: (self mouseIsOver ifTrue:[ self buttonOverForm] ifFalse: [self buttonNormalForm])
>          at: `0 at 0`.
>
> You can have two form caches, one for mouse over rendering.
>
> *buttonOverForm*
>      ^ buttonOverForm ifNil: [
>          buttonOverForm _ self drawMyShapeWith: (Color white alpha: color alpha).
>          icon ifNotNil: [icon displayOn: buttonOverForm at: center - (icon extent // 2) rule: Form blend].
>          buttonOverForm]
>
> You can compose the vector rendered part with other bitmap operation, 
> ie to add an icon here.
>
> *drawMyShapeWith: background*
>      | vectorCanvas aLocation aForm |
>      aForm _ Form extent: extent depth: Display depth.
>      aForm fillColor: Color transparent.
>      vectorCanvas _ VectorCanvas onForm: aForm.
>      aLocation _ AffineTransformation withTranslation: bounds topLeft negated.
>      vectorCanvas engine geometryTransformation: aLocation.
>      vectorCanvas strokeWidth: 2 color: color muchDarker fillColor: background  do: [: engine |
>          engine abs_MoveToX: (corners floatAt: 1) y: (corners floatAt: 2);
>              abs_LineToX: (corners floatAt: 3) y: (corners floatAt: 4);
>              abs_ArcToX: (corners floatAt: 5) y: (corners floatAt: 6)
>                  radiusX: radius radiusY: radius angleOfXAxis: aperture largeFlag: false sweepFlag: false;
>              abs_LineToX: (corners floatAt: 7) y: (corners floatAt: 8);
>              abs_ArcToX: (corners floatAt: 1) y: (corners floatAt: 2)
>                  radiusX: innerRadius radiusY: innerRadius angleOfXAxis: aperture largeFlag: false sweepFlag: true].
>      ^ aForm
>
> It is the vector rendering, specific to the Morph.
>

This is a very cool idea, and you are the first to come up with it, and 
make it work. Kudos for that!

> *isOrthoRectangularMorph*
>      ^ false
>
> Inform it is not rectangular, Juan already prepare this.
>
> *morphContainsPoint: aLocalPoint*
>      | polarPoint min max |
>      (self morphLocalBounds containsPoint: aLocalPoint) ifFalse: [^ false].
>      polarPoint _ (aLocalPoint + bounds topLeft - radius asPoint) * (1 @ -1).
>      min _  Float halfPi - (aperture / 2) - shift.
>      max _ Float halfPi + (aperture / 2) - shift.
>      ^ (polarPoint r
>          between: innerRadius
>          and: radius)
>              and: ["Deal when crossing zero"
>                  (polarPoint theta
>                      between: min
>                      and:  max)
>                  or: [polarPoint theta
>                          between: min + Float twoPi
>                          and:  max + Float twoPi
>                      ]
>                  ]
>
> Then you can have Morph detection/selecting really matching the vector 
> shape.
>

This is also true. But see my answer to Mariano's comment in this 
thread, for the interesting and cool part :)

> If you are interested in graphics/morph sutff, I encourage you to take 
> a look and have fun with your creativity.
>

Indeed!

> Juan, about my request. An intermediate step to the whole Vector 
> things for the Cuis display is a kind of PasteUpMorph accepting sub 
> morphs directly rendered with vectorCanvas instance. I will be the 
> first client with DrGeo to test  and to use it. It could be a next 
> step to Dyanbook display too.
>
> Hilaire
>
> -- 
> GNU Dr. Geo
> http://drgeo.eu
> https://pouet.chapril.org/@hilaire

You mean making your caching strategy part of the framework? Sounds like 
a good idea, and not too hard to do (you already did the work). Still, 
Morphs would need a message to invalidate the cached Form and redraw it 
again with VectorCanvas, right? Right now, you are caching 2 Forms, but 
a genera framework solution should allow easily invalidating the cached 
form without needing to know how many variants could exist, and what 
triggers the change.

This is getting really interesting. Let's move it forward!

Cheers,

-- 
Juan Vuletich
www.cuis-smalltalk.org
https://github.com/Cuis-Smalltalk/Cuis-Smalltalk-Dev
https://github.com/jvuletich
https://www.linkedin.com/in/juan-vuletich-75611b3
@JuanVuletich

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.cuis.st/mailman/archives/cuis-dev/attachments/20200619/2618ae52/attachment-0001.htm>


More information about the Cuis-dev mailing list