r3wp [groups: 83 posts: 189283]
  • Home
  • Script library
  • AltME Archive
  • Mailing list
  • Articles Index
  • Site search
 

World: r3wp

[SVG Renderer] SVG rendering in Draw AGG

ICarii
10-Oct-2009
[151]
I've been playing with Shadwolf/etc SVG 06 svg renderer today and 
am at the point where i am working on linking in gradients.  The 
test SVG i am using (because it seems to be a good mix) is http://en.wikipedia.org/wiki/File:SVG.svg
Steeve
10-Oct-2009
[152x3]
Icarii, your svg file is too much complicated for me.

It's using both gradientUnits="objectBoundingBox" and gradientUnits="userSpaceOnUse" 
 to render the gradients.

userSpaceOnUse

 use real coordinates for the vectors used by gradients (what i do 
 currently).
objectBoundingBox

  use % vectors which have to be converted into real unit,  depending 
  of the real size of the object (after rendering) where the gradient 
  is applied (what the fuck  !!! it's magic).


I have enough pain to construct correct gradients in real units for 
the moment.Your svg file is too much complicated.
Currently my problem is with the linear gradients when a matrix operation 
is applied on them.


The linear gradient use a vector v = (x1, y1) - (x2, y2) to indicate 
his direction and length.


grad-pen is defined like this:  [grad-pen linear normal xy 0 len 
angle [... stop colors]]

And i calculate his values with:

- xy = (x1,y1)
- len =  length of the vector v 
- the angle of the vector v


When a matrix is associated with the gradient, i multiply the coordinates 
of the vector v by the matrix before calculating the other values.
It's working well when the gradient is vertical or horizontal.

But when the gradient is inclined , the matrix multiplication give 
a wrong vector and i don't know why.
To be precise, the resulting vector seems to have the correct position 
and length, but a wrong angle.
ICarii
10-Oct-2009
[155]
what sort of output are you getting for the angle in the grad-pen 
call?
Steeve
10-Oct-2009
[156]
Well, assuming you got x1,y1,x2,y2 from the Lineargradient

I calculate the angle like that:
arctangent (y2 - y1) / (x2 - x1)

As i said previously, the angle is correct when there is no matrix 
transformation on the gradient.
I compare the rendering with what i see in Inskape.
Steeve
11-Oct-2009
[157x5]
the svg i test currently (public domain) http://sites.google.com/site/rebolish/test-1/lizard.svg
And what i got with rebol: http://sites.google.com/site/rebolish/test-1/lizard-rebol.png
the gradients still have the same problem
when matrix transformations are applied, some are wrong, but hey 
! Quite a good result already !
Well, i think i got it for the linear gradients...
ICarii
11-Oct-2009
[162]
btw the bounding box call in the second sizing mode can be gotten 
from the size of the canvas you are drawing to.
Pekr
12-Oct-2009
[163]
Steeve - your work is quite impressive! Just don't become demotivated 
by possible lack of responses :-) If you find some bugs, or you come 
up with some ideas of how to make View more SVG friendly, write your 
notes down, we can discuss it with Cyphre. I think that we are still 
in rather initial phase, so we can e.g. change the way of how e.g. 
gradient-fills work (I do remember someone reported that you can't 
translate gradient definitions between /draw and SVG)
Steeve
12-Oct-2009
[164x3]
This matrix must not be applied on the gradient's vector as-is, but 
on something else.
And i found what, at least...


The documentation of SVG is lacking of a good explanation about this 
curious matrix transformation.
All we can read is that curious sentence:


When the object's bounding box is not square, 
the stripes that are 
conceptually perpendicular to the gradient vector within object bounding 
box space 
will render non-perpendicular relative to the gradient 
vector in user space 
due to application of the non-uniform scaling 
transformation 
from bounding box space to user space

What does that mean ?????


It means that the SVG gradient must be rendered without using the 
matrix transformation.

And THEN the transformation matrix must be applied on the resulting 
strips.

You see the problem ?

The matrix must not be apllied on the gradient's vector, but on the 
resulting strips produced by the use 
of the initial gradient's vector.


What foolish morons have designed such a complicated way of constructing 
gradients.

Can't they just give a matrix that can be applied on gradient's vector 
as-is, no they can't, it's to simple.
Morons, I said !!!


Because of that i had to make more transformations to obtain the 
REAL vector.
step by step I do something like that:


1/ Take the initial gradient vector V and apply the matrix on it, 
it gives a vector V1

2/ RE-take the initial vector V, rotate it of 90 degrees, apply the 
matrix on it, and rotate back the resulting vector
. It gives the vector V2

3/ Project the vector V1 on the line V2 (orthogonal projection). 
It gives a third vector V3.
4/ That's all, the REAL vector to use for the gradient is V3.


It take me a while to figure that, by analysing the Inkscape rendering. 
Morons i said !!!
I show you that part of my code...

		switch type [
			linear [
				unless x2 [x2: x1]
				unless y2 [y2: y1]

				if matrix [

     ; ** apply the matrix on the vector rotated of 90°, then rotate it 
     back,  give the vector V1
					set [y1' x1'] mulm y1 negate x1 matrix
					set [y2' x2'] mulm y2 negate x2 matrix
					x1': negate x1'
					x2': negate x2'

     ;** apply the matrix on the initial vector, give the vector V2
					set [x1 y1] mulm x1 y1 matrix
					set [x2 y2] mulm x2 y2 matrix
					;** project the vector V2 on the line V1
					set [x1 y1] project x1' y1' x2' y2' x1 y1
					set [x2 y2] project x1' y1' x2' y2' x2 y2
				]
				angle: atan2 x2 - x1 y2 - y1 
				if units = "objectBoundingBox" [
					x1: box/1/x * x1
					y1: box/1/y * y1
					x2: box/2/x * x2
					y2: box/2/y * y2
				]
				out as-pair x1 y1	;** offset
				out 0				;** start rng
				out square-root add x2 - x1 ** 2 y2 - y1  ** 2	;** stop rng
				out angle			;** angle
			]
...
Well i thought SVG 's radialGradients will be easier. I was wrong.
SVG Proposes another stupid feature (yet another one).
Actually they can specify 2 circles.

One where the gradient is really rendered. And another one used as 
a window which clips the first one.
What the heck is that !!!!

it's why in a SVG's radial gradient, there is 2 different  centers 
 (cx, cy) (fx, fy)  for the 2 separated circles.


When the 2 centers are equals, then there is no prolem to render 
it whit the rebol's radial gradient, easy.
But when they differ, it's impossible.

I can't blame Rebol to not allow that, because it's a really stupid 
useless feature.
Pekr
12-Oct-2009
[167]
Now the question is - should we adapt, or do we create copy of such 
functions, to allow being compatible?
Steeve
12-Oct-2009
[168x8]
I'm angry, i don't see why grad-pen in Rebol should allow such stupid 
feature
in fact, i think i could simulate that behavior.
By 
1/ rendering the radial gradient in the initial circle.

2/ create an image with that circle and clip it with the shape of 
the second one.
3/ Use that image as a pattern for the fill-pen attribut


But it would be a mess of  computing time and of memory, because 
in the draw block we would have images used as pattern instead of 
computed gradients
i think that feature (2 different centers) is not used that much.

In the lizard.svg example i gave, they don't use it, the 2 centers 
are always equal.
By default Inkscape don't use that feature when you design a radial 
vector.
Ok, i finished with Radial gradients (less the impossible feature: 
2 different centers)


SVG use a matrix transformation to convert a circular radial gradient 
into an ellipsoid.

And you know what ? 

We can do the same thing with grad-pen which provides 2 scalling 
factors (grad-scale-x and grad-scale-y)

So in that case it's easier than for linear-gradient.
1/ take the focal point of the Radial gradient (fx, fy)

2/ Create 2 vectors starting from this point: 1 vertical and 1 horizontal, 
using the radius as their length.
3/ apply the matrix transformation on them.

5/ get  the component X of the transformed horizontal vector, and 
the component Y of the transformed vetical vector
6/ grad-scale-x:  x / r
7/ grad-scale-y: y / r

That's all folks
Gezz... i forget the rotation of the ellipsoid...
more work...
Ok, done
Guys, i updated the lizard.svg rendered with Rebol http://sites.google.com/site/rebolish/test-1/lizard-rebol.png

To compare with http://sites.google.com/site/rebolish/test-1/lizard.svg.


I'm glad to announce that i see absolutly no differences inside Google 
chrome.

All the grandients (linear and radial) are perfectly rendered by 
Rebol.
Graham
12-Oct-2009
[176]
Nice ...
ICarii
12-Oct-2009
[177]
great work steeve! :)
Steeve
12-Oct-2009
[178]
Basically, you can load the draw block generated for the lizard here.
it's handed by the variable PANE.
http://sites.google.com/site/rebolish/test-1/lizard.r
Maxim
12-Oct-2009
[179]
GREAT WORK Steeve  :-)
Steeve
12-Oct-2009
[180]
Added a litte animation.
The bumping lizard !!!!
http://sites.google.com/site/rebolish/test-1/lizard.r
Maxim
12-Oct-2009
[181]
the difference in your render and SVG render is mainly the anti-aliasing, 
which is crisper in the svg renderer.... probably has a better algorythm 
setup than the one use by R3... this is probably manageable within 
AGG, but AFAIK there is no control for it within R3.
Steeve
12-Oct-2009
[182]
Not the problem of the antialiasing, I just think i made a false 
translation of the command used in the shapes.

They use a smouthing curve, me not i guess. I have to verify that.
But Rebol can draw smoothing curves too, no problemo.
Maxim
12-Oct-2009
[183x3]
if you draw the outlines twice, they should be a bit crisper... is 
that what you mean?
there seems to be two spots missing on the left left... very faint, 
but missing or not visible at least.
also the anti-aliasing was a result of my browser which rescaled 
the image minus 5 pixels... so it has nothing to do with your render.
Steeve
12-Oct-2009
[186x2]
ok
i only checked with google chrome, it was very similar
BrianH
12-Oct-2009
[188]
Sorry, got tired of the shouted group name/description :)
Steeve
12-Oct-2009
[189]
i don't know which renderer chrome uses
BrianH
12-Oct-2009
[190]
It's a good one. It looks identical to yours, though that may be 
server side in your example link.
Maxim
12-Oct-2009
[191]
we should also note that this is in R3  :-)  not everyone realizes 
this IMO.
BrianH
12-Oct-2009
[192]
Seriously? Cool :)
Steeve
12-Oct-2009
[193]
yes it's R3
BrianH
12-Oct-2009
[194]
Draw should be the same, afaik, which isn't that far. Have the parse 
improvements helped?
Steeve
12-Oct-2009
[195x2]
not so much ;-)
but the new grad-pen command of draw is awesome
BrianH
12-Oct-2009
[197]
Cool :)
Maxim
12-Oct-2009
[198]
that was seriously missing in R2 draw.. happy its in R3  :-)
Steeve
12-Oct-2009
[199]
By the way the DRAW function can't render that, it's crashing.
BrianH
12-Oct-2009
[200]
The DRAW function is still there? I really need to pay more attention 
to the graphics stuff.