Basic SVG Parser

Monkey Forums/Monkey Code/Basic SVG Parser

CopperCircle(Posted 2014) [#1]
Hi, here is a basic SVG parser/renderer. My plan was to look at being able to load SVG's, scale them to the size needed and then create an image atlas for the app to use. For certain types of graphics/UI elements this could be great with all the different device resolutions/sizes. It could also be used to create fonts at any size.

Anyway I threw this together and have not had time to take it any further, not all SVG commands have been implemented and there is no triangulation yet so it will only look correct on HTML5.

It requires SKN3's latest XML module and also contains various code snippets from the monkey forums (thanks to those who's code is used).

https://github.com/CopperCircle/Monkey-SVG


Nobuyuki(Posted 2014) [#2]
Notes:

1. You need to add the following code to the top of this file in order for it to work correctly, in addition to adding xml.monkey!
#TEXT_FILES += "*.svg"


2. This is pretty neato, if I don't say so myself; I was looking into making something a lot like this but ya beat me to it!

Two things which I was working on which may help this code snippet out was attempting to implement more advanced bezier rasterization techniques (ie: a DrawBezier code snippet) such as de Casteljau's method and Hain-Ahmad-Langan rasterization, and decomposition of polygons. I didn't get very far into it, but here are some of the documents I was using as research:

http://tinyurl.com/HainBez
http://cs.gmu.edu/~jmlien/research/app-cd/p218-lien.pdf


AdamRedwoods(Posted 2014) [#3]
nice! ambitious project. i would suggest looking at other people's projects and try porting (that is, if your objective is ultimately to get SVG into monkey):
https://github.com/memononen/nanosvg
https://github.com/pents90/svg-android/tree/master/svgandroid


muddy_shoes(Posted 2014) [#4]
This is definitely a capability that would be great to have. Maybe stick it up on github or similar if you want some collboration?


muddy_shoes(Posted 2014) [#5]
This is definitely a capability that would be great to have. Maybe stick it up on github or similar if you want some collaboration?


CopperCircle(Posted 2014) [#6]
Hi, thanks for the comments and links, I hope others will look to collaborate on this so I have put it up on github. I think the next step would be to look at getting the concave polys to draw on all targets, I have started to look at the options for triangulation and maybe something like Triangle could be ported which should be robust enough to handle holes and overlaps. http://www.cs.cmu.edu/~quake/triangle.html

https://github.com/CopperCircle/Monkey-SVG


muddy_shoes(Posted 2014) [#7]
Unfortunately the license (and projected authorial attitude) for Triangle seems incompatible with making something we could use in games. There are some other options listed here: http://stackoverflow.com/questions/406301/polygon-triangulation-with-holes?rq=1


skid(Posted 2014) [#8]
I just added a triangulate function to the code forum, it's just another ear clipper but I am keen on implementing a more advanced algorithm.


muddy_shoes(Posted 2014) [#9]
Does that deal with holes and overlaps? It doesn't look like it.


skid(Posted 2014) [#10]
I thought clipping ears with triangles was OK for holes as long as your ear check included any other verts being inside it.

Handling overlap needs an improvement to the implementation or second clipping pass.

It would be helpful to have spec / data / basic description to work with, including interpreting data where first three verts go anti clockwise etc.

Does html5 solve both issues properly or does it just do basic triangulation?


muddy_shoes(Posted 2014) [#11]
Ear-clipping doesn't handle holes. The simple solution to using it with polys with holes is to make "cuts" to the hole but working out where to make those cuts is actually not simple for arbitrary shapes.

As far as a spec, we're talking about SVG, so the spec is up at W3.org. A basic example of the issue would be something like this, which defines an ellipse with two smaller ellipses cut out of it:

  <g
     inkscape:label="Layer 1"
     inkscape:groupmode="layer"
     id="layer1">
    <path
       style="fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:#ffffff;stroke-width:4;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
       d="M 408.5625 163.78125 C 234.9873 163.78125 94.28125 314.73864 94.28125 500.9375 C 94.28125 687.13636 234.9873 838.0625 408.5625 838.0625 C 582.1377 838.0625 722.84375 687.13636 722.84375 500.9375 C 722.84375 314.73864 582.1377 163.78125 408.5625 163.78125 z M 481.4375 366.65625 C 515.36356 366.65625 542.84375 398.61359 542.84375 438.0625 C 542.84375 477.51141 515.36356 509.5 481.4375 509.5 C 447.51144 509.5 420 477.51141 420 438.0625 C 420 398.61359 447.51144 366.65625 481.4375 366.65625 z M 344.28125 406.65625 C 382.94118 406.65625 414.28125 469.95366 414.28125 548.0625 C 414.28125 626.17134 382.94118 689.5 344.28125 689.5 C 305.62132 689.5 274.28125 626.17134 274.28125 548.0625 C 274.28125 469.95366 305.62132 406.65625 344.28125 406.65625 z "
       id="path2985" />
  </g>



muddy_shoes(Posted 2014) [#12]
Oh, and DrawPoly on HTML5 doesn't support this either. I think the underlying canvas path stuff can though.


skid(Posted 2014) [#13]
Muddy, thanks for the reply.

It is possibly saner to plug SVG into a scan line renderer to reach any kind of spec parity although nVidia think they can handle such things.

Living without holes and overlaps for level design seems like a small price to including this kind of format into an asset pipeline.

I think Mojo support for line width, smoothing and endpoints would be most useful addition to things at this point..


CopperCircle(Posted 2014) [#14]
skid, I agree we don't need to support holes/overlaps, you can break shapes up in Illustrator/Inkscape to get over it. I have quickly added your triangulate method and updated the repo but on my concave test it seems to return an inverted shape?


skid(Posted 2014) [#15]
testing with concave.svg I get a doh error - Monkey Runtime Error : doh! could not read concave.svg

[edit] fixed by removing some of the header

also, Error is a reserved word in monkey and is capitalized in Ted so I have renamed it, problem area for me was here:

Method LoadSVG:Void(_file:String)
	Local _Error:XMLError
	file = ParseXML(LoadString(_file), _Error)
	If file = Null			
		Error("doh! could not read "+_file+" _Error="+_Error)
	Else
		If file.GetAttribute("width") w=Int(file.GetAttribute("width")) ; width=w
		If file.GetAttribute("height") h=Int(file.GetAttribute("height")) ; height=h
	Endif
End Method



skid(Posted 2014) [#16]
Here is new version of triangulate.monkey that passes the mustache test.

Monkey.svg is looking a bit patchy, I can't say it's obvious what needs fixing next but I'm wondering if it's a clockwise winding thing still.

I am testing in html5 and it's interesting to see the seams between polygons, i'm pretty sure we can deal to that with new mojo-x that is hopefully due soon.


CopperCircle(Posted 2014) [#17]
Thanks, I will try the new version, also you need the latest xml from SKN3 as he has fixed it to work with the headers that illustrator produces. I will change error in the repo


Difference(Posted 2014) [#18]
This is great guys!

For this to reach it's full potential, Mojo Graphics should have at least this function:

DrawTriangles(trianglevertices:Float[],indexes:Int[]) 


( iOS and desktop targets antialias the edge of polygons, so the DrawPoly(triangle[]) method will show gaps/line artifacts ) .

I hacked it in this old demo and have been advocating for it since then, I hope that now skid is onboard we can sway mark to putting it in... :-) http://scheutz.dk/stuff/monkeyvector.html

For thick lines
DrawTriangleStrip:Void(vertices:Float[])
is really usefull and mostly the fastest way.

BTW: I have a triangulate function I can share if needed?


CopperCircle(Posted 2014) [#19]
Thanks Difference, it sounds like the new mojo-x may help with this, but would be great to try your functions in the mean time, feel free to branch the repo?


Difference(Posted 2014) [#20]
I guess I could for the Desktop target since it's free now? - I'll look into it, but I'd rather just share the code in a post, because I don't have experience with GIT pull requests and such.
Problem untill now has been that we are not allowed to share the code for all targets.

[EDIT]: Where is the desktop mojo target ?
Not here: https://github.com/blitz-research/monkey/tree/develop/modules/mojo

and where is mojo-x ?


CopperCircle(Posted 2014) [#21]
Mojo-x is not release yet. Also skid I updated the repo with your newer triangulate method and its getting there, the text.svg example is very broken though...


skid(Posted 2014) [#22]
Cool, thanks for testing - this is quite a challenge.


Nobuyuki(Posted 2014) [#23]
Problem untill now has been that we are not allowed to share the code for all targets.

[EDIT]: Where is the desktop mojo target ?
Not here: https://github.com/blitz-research/monkey/tree/develop/modules/mojo


Jeez, it's been 2 months already, even. https://github.com/blitz-research/monkey/issues/43


skid(Posted 2014) [#24]
Version 0.5 of triangulate is up which passes the monkey and mustache test.

I need help with the IsWoundClockwise algorithm as the one I've tried is either broken or just wrong.

Hopefully if this function can be fixed the text test should be passable also.


Difference(Posted 2014) [#25]
I Use the PolygonArea() function from here: http://www.monkey-x.com/Community/posts.php?topic=1659&post=15542 to determine winding.

There is also a function to determine if triangulation is needed or we can just use mojo's DrawPoly() because that works fine with non concave polygons.


Raz(Posted 2014) [#26]
This could be really useful for me, I'm looking to do some graph rendering :)


Difference(Posted 2014) [#27]
I've been testing my own Triangulate() routine on this and getting results similar to skids.

I've made a simple test shape, to experiment with polygons with holes. (A pentagon inside a hexagon)

This SVG parses to a poly with 15 points. An outer ring that repeats point 0 as point 12 and 14 and an inner ring that repeats the last point. (Point 7,14 and 15 are identical)

I think it should parse as two separate polygons made of 6 + 5 points and send those to the triangulate routine.
I also think it should NOT duplicate the endpoints and I don't think it should repeat the first point as the last point.

Splitting paths when the SVG code indicates "Close Path" will allow us to build a solid triangulator that deals with compound paths/holes.




CopperCircle(Posted 2014) [#28]
Hi, I have just updated the repo, I added skid's new v0.6 triangulate function, tweaked the parser to not add extra endpoints and I also added a splitPath bool to the DrawPath method, this will split paths into separate polys when a close path is called.
This now draws Difference's test correctly and the text test is almost there, the problem is I am just drawing the extra path polys as white to represent transparent, this wont work if the path is being drawn over another object.


Difference(Posted 2014) [#29]
Great work! , multiple polygons are definitely the way to go.

Theres still one repetition of the endpoint/startpoint that IMO needs to go on the test.svg
Test it by using DrawPoly(poly[c][..poly[c].Length()-2]) - will work too on html5,skids triangulate and my own because the parser does not need to add the last point.

It turns out skids Triangulate() does not triangulate the test.svg at all. It just returns 2 convex polygons. I don't know if this is intentionally?
If so skids function should be called Convexyfy() or something similar. :)
The n-gons does not need triangulation to look okay with mojos DrawPoly(), but in order to do polygons with holes, we need to triangulate everything.

PS: I have a glitch where I need to copy paste the test.svg into a new file, or else I get a "doh" error. I'm OS X, so I'm guessing this is a file encoding issue/UTF-8 /lineending .... something [EDIT] : It's the !DOCTYPE tag, but I think I am using version 23 of XML.monkey, will test further.


CopperCircle(Posted 2014) [#30]
Hi, make sure you have the latest XML module, SKN3 updated it to work with Illustrator SVG XML for me.
Also do you want to share your triangulate function? the more the merrier, I will look at the final extra point being created.
Edit: I was creating and extra point on absolute MoveTo commands, this has been fixed now and the correct amount of points are created in the test.svg


skid(Posted 2014) [#31]
When I clip an ear I test that no other vertices are inside. Thinking about it, I should be testing that no edges subdivide the ear.


Difference(Posted 2014) [#32]
I'll post my triangulator soon, - I'm giving creating holes a go first.
I'm using the latest XML version
Great: I'll use the new version when testing my tesselator.

@skid: What I do is test if any points are inside the ear. If the poly is none-selfintersecting that should do it.


Difference(Posted 2014) [#33]
I'm looking at this now.
Using the latest version form github, my simple test.svg is being parsed to 3 polygons, the last one empty

Try a: Print "Polygons: " + poly.Length() in DrawTriangulatedPoly to test.

I'll put in a check for empty polygons, but I it seems the parser is outputting one poly too much


CopperCircle(Posted 2014) [#34]
Hi, yes but only two polys are passed to the DrawPoly or Triangulate functions, the empty poly is created from how I am splitting them in a multi array.


Difference(Posted 2014) [#35]
ok, I see that now, hence the -2 in the loop.
I'll throw away the last poly for now :-)


Difference(Posted 2014) [#36]
Almost there, but made this that doesn't seem to draw with any method (html5, mine, skids)

mustwithholeanddownarrow.svg :


[EDIT]
This one is ok:




[EDIT2]
This one totally explodes: http://upload.wikimedia.org/wikipedia/commons/f/fd/Ghostscript_Tiger.svg


Difference(Posted 2014) [#37]
http://www.monkey-x.com/Community/posts.php?topic=8035

^^ My triangulator with initial holes support! :-)


CopperCircle(Posted 2014) [#38]
Good work!, I have updated the repo and added your triangulator, I also fixed a bug with the polygon svg command so now your tests both work, the parser only supports SVG v1.1 and has only been tested with SVG output from Adobe Illustrator, I re-saved the tiger svg (check repo) and it works! there are a few elements missing that I have not added to the command processor, so will try and add these soon.
This is almost there, would be great to get it all working and then I am thinking of trying to get SVG fonts into angelfont or fontmachine.


Difference(Posted 2014) [#39]
New tessellate.monkey version up. (v0.3 ) 2014.02.26
This one handles tiger, text and monkey :-)
http://www.monkey-x.com/Community/posts.php?topic=8035


CopperCircle(Posted 2014) [#40]
Hi, sounds great :)
Just tried the new version and I get Array index out of range in the Tessellate Method, triangleindexes[i] = indexedpoly.ear[0] ?
Thanks.


Difference(Posted 2014) [#41]
[EDIT] : I can reproduce it on Windows Desktop, will fix ASP
[EDIT2] : Fix confirmed, and corrected in forum post. :-)

Sorry, can you try putting If Self.Length() <3 Then Return False
as the first line in Method ClipEar:Bool() to see if that fixes it?

I just re-downloaded from GitHub and updated tessellate.monkey from my from forum post, and I don't get that error.
I can see two reasons why it could happen

Also if the svg you're testing with is not one of the samples, please post it here.

	Method ClipEar:Bool()
		If Self.Length() <3 Then Return False



CopperCircle(Posted 2014) [#42]
Thanks, works now :) I have updated the repo with your latest build and updated the parser, I added the svg smooth quadratic Bézier curveto commands but there are not perfect yet, they are needed for svg fonts which I am working on.
I noticed the nose on the tiger is not the same as HTML5 in GLFW the shape is lost and there are few bits of the poly around the chin. Monkey.svg and text.svg look great.


Difference(Posted 2014) [#43]
Cool. :-)
I'm working on improving the holemerger, - maybe that will improve the results.
I also added some debugging variables to detect when something is lost.

I think you should output polylines to a separate function, - then we can make a function that makes fat lines from polygons.
I have one I think I can modify to work.
I guess stroke could use that too?


Difference(Posted 2014) [#44]
Good news. mojo GLFW is here: https://github.com/blitz-research/monkey/blob/develop/modules/mojo/native/mojo.glfw.cpp
I'll hack in a DrawTriangles() ASAP

My new version of the tesselator seems quite stable and handles multiple holes well. :-)
Will post it ASAP

After examining the tiger.svg in Illustrator, it looks like the problem comes from lines being sent to the tesselator as polygons.


CopperCircle(Posted 2014) [#45]
Great, I will look to improve the parser and also output lines/polylines separately.


Difference(Posted 2014) [#46]
New version is up at http://www.monkey-x.com/Community/posts.php?topic=8035

I added a first version of a ThickPolyLine to draw triangulated lines with width.

Please note that I changed the calling convention a little to:
Tessellator.TriangulateAndDrawPolyline:Void(points:Float[],thickness:Float,closed:Bool)
Tessellator.TriangulateAndDrawPolygons:Void(polys:Float[][])


Heres a multihole svg for testing:

gridholes.svg



Raz(Posted 2014) [#47]
Just giving this a proper go now, really impressed with it :)

I would very much like to use this along with server side generated SVGs, right now I am thinking via the PHP library SVGGraph - http://www.goat1000.com/svggraph.php

The below SVG generates this through a standard browser


and monkey-svg currently generates


I did wonder if the parser doesn't work with rgb() colour values, but I get the same when using #FFFFFF format colours.

Regardless though, really impressed :D

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="640" height="480" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg">
	<rect width="100%" height="100%" fill="rgb(240,240,240)" stroke-width="1px" stroke="rgb(0,0,0)"/>
	<path d="M33 458h597M33 435.95h597M33 413.9h597M33 391.85h597M33 369.8h597M33 347.75h597M33 325.7h597M33 303.65h597M33 281.6h597M33 259.55h597M33 237.5h597M33 215.45h597M33 193.4h597M33 171.35h597M33 149.3h597M33 127.25h597M33 105.2h597M33 83.15h597M33 61.1h597M33 39.05h597M33 17h597M33 17v441M232 17v441M431 17v441M630 17v441" stroke="rgb(220,220,220)"/>
	<rect width="189" x="38" y="237.5" height="220.5" id="e2" style="fill:red;stroke:rgb(0,0,0);stroke-width:1px;"/>
	<rect width="189" x="237" y="17" height="441" id="e3" style="fill:green;stroke:rgb(0,0,0);stroke-width:1px;"/><rect width="189" x="436" y="127.25" height="330.75" id="e4" style="fill:blue;stroke:rgb(0,0,0);stroke-width:1px;"/>
	<path d="M33 461v-3M232 461v-3M431 461v-3M630 461v-3M30 458h3M30 435.95h3M30 413.9h3M30 391.85h3M30 369.8h3M30 347.75h3M30 325.7h3M30 303.65h3M30 281.6h3M30 259.55h3M30 237.5h3M30 215.45h3M30 193.4h3M30 171.35h3M30 149.3h3M30 127.25h3M30 105.2h3M30 83.15h3M30 61.1h3M30 39.05h3M30 17h3" stroke-width="1px" stroke="rgb(0,0,0)"/>
	<g stroke-width="2px" stroke="rgb(0,0,0)">
		<path d="M28 458h607"/>
		<path d="M33 12v451"/>
	</g>
	<g font-size="10px" font-family="monospace" fill="rgb(0,0,0)">
		<g text-anchor="end">
			<text x="28" y="461">0</text>
			<text x="28" y="438.95">10</text>
			<text x="28" y="416.9">20</text>
			<text x="28" y="394.85">30</text>
			<text x="28" y="372.8">40</text>
			<text x="28" y="350.75">50</text>
			<text x="28" y="328.7">60</text>
			<text x="28" y="306.65">70</text>
			<text x="28" y="284.6">80</text>
			<text x="28" y="262.55">90</text>
			<text x="28" y="240.5">100</text>
			<text x="28" y="218.45">110</text>
			<text x="28" y="196.4">120</text>
			<text x="28" y="174.35">130</text>
			<text x="28" y="152.3">140</text>
			<text x="28" y="130.25">150</text>
			<text x="28" y="108.2">160</text>
			<text x="28" y="86.15">170</text>
			<text x="28" y="64.1">180</text>
			<text x="28" y="42.05">190</text>
			<text x="28" y="20">200</text>
		</g>
		<g text-anchor="middle">
			<text y="470" x="132.5">0</text>
			<text y="470" x="331.5">1</text>
			<text y="470" x="530.5">2</text>
		</g>
	</g>
</svg>



CopperCircle(Posted 2014) [#48]
Hi, yes the trouble with SVG files is there are loads of different attributes to implement! I am planning to work on the parser over the weekend and will update the git repo, I should be able to add rgb and style attributes, also text is not currently supported.


Difference(Posted 2014) [#49]
@CopperCircle: sounds great.

I'm looking into supporting miter, round and bevel joints for the lines, also there will be a miter-limit.
Capping will be butt,round and square.

Will this Function syntax work for you?



[EDIT]: I just forked and added tessellate.monkey as a pull request. Let me know if that's a good way for future updates.


CopperCircle(Posted 2014) [#50]
Hi, that syntax looks fine and yes adding to the repo with your updates sounds great, I will be updating again this weekend. Thanks.


CopperCircle(Posted 2014) [#51]
Hi, just updated the repo, this is getting better all the time, great work on the tessellate code :)
- Refactored some code, added tesselate v0.6, added support for rgb and named colours, added stroke/polyline, added basic text support.

I added Raz's graph example and noticed that tessellate polyline is triangulating single straight lines, not sure how's best to handle them...


Difference(Posted 2014) [#52]
Really nice work. Great to see this progressing :-)

The problem with the graph.svg seems to come from the parser:

1) The lines are being sent both as polygon and polyline, they should only be polylines ( this seems also to be the case with the little arc below the text in "text.svg" ? )

2) I think it's the line sent from the parser that is not correct. Try viewing the pointarray with the below function ( you can put in a call in the top of TriangulateAndDrawPolyline )
It looks "crosshatched"

Function DebugDrawFloatPoints :Void(points:Float[])
	SetColor 255,0,0
	For Local p:Int=0 Until  points.Length()-2 Step 2
			DrawLine points[p],points[p+1],points[p+2],points[p+3]
	Next	
End function


3) The tiger.svg suffers from lack of miter-limit capping, I got this fixed in the next version.

4) I'm noticing you're not using the closed = false flag anywhere. The flag is intended for non-closed lines such as the little arc in text.svg.

Thick lines turns out to be a little more complicated than I first thought due to the deterioration of the inner corners, as the line gets thicker.
I got a couple of strategies, and will find the best one !

Keep up the good work. :-)


Raz(Posted 2014) [#53]
Awesome job in getting the graph rendered :D That's really amazing work.


Raz(Posted 2014) [#54]
I'll have to start doing some reading on SVG so I can be a little less needy and a little more helpful... but....

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg width="640" height="480" version="1.1" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg">
	<g>
		<path stroke="rgb(0,0,0)" fill="none" stroke-width="2px" d="M27 441.67 L127 392.67 227 327.33 327 311 427 196.67 527 49.667 627 17 "/>
	</g>
	
</svg>

Are you able to determine why this only renders the first section of the path? Chrome renders a graph looking line.


CopperCircle(Posted 2014) [#55]
Hi, yes your right it was passing the same poly twice! doh! Fixed now and a few more improvements on the repo, but if you try the lines.svg it still triangulates the straight lines? The tiger.svg is looking almost perfect now :)

Raz: the parser is not stable yet so I would wait and test each update, it is getting better all the time.


Difference(Posted 2014) [#56]
Getting good :-)

These are the lines sent to the Polyline function:



You can use
Function TriangulateAndDrawPolyline:Void(points:Float[],thickness:Float,closed:Bool)
DebugDrawFloatPoints points
Return
with this funtion to view it.



[EDIT] : Try this with the tiger.svg too. There's a line across the face:




Raz(Posted 2014) [#57]
Absolutely I love testing each update and will figure out how I can actually help


CopperCircle(Posted 2014) [#58]
Hi, I am just passing the points as they are in the file, if you use this debug function you can see the order they are drawn in and if you change the DrawLine step to 4 the grid lines are fine, not sure how to deal with stroke/lines as the behaviour seems to need to change depending on the source?




Difference(Posted 2014) [#59]
I think it's because you're not starting a new Subpath on the "M" command, resulting in a polyline rather than individual line segments. ?

http://www.w3.org/TR/SVG/paths.html#PathDataMovetoCommands

The effect is as if the "pen" were lifted and moved to a new location



Raz(Posted 2014) [#60]
If a path is defined as having fill="none" and/or doesn't end with the Z (closepath) control it would suggest to me that instead of drawing a poly, it should just be a series of drawn lines? This would also allow for proper interpretation of M/m


CopperCircle(Posted 2014) [#61]
That is what the parser does, I have now added sub paths to M and all is working well, I will update repo later.


Difference(Posted 2014) [#62]
Great, will you be using the "closed" flag=false for this?

[EDIT] or rather (since default is now closed=false, will you send the flag for closed polylines? (It's needed for nice joining of start and end)

I have a new line function finished that has miter-limit and bevel joins working

A little thing I have noticed that linewidths are not scaled when zooming in and out, it would be great to have that added.


Raz(Posted 2014) [#63]
Ahh sorry Copper, I look forward to the update :D


Difference(Posted 2014) [#64]
I've updated tessellate.monkey to v0.7.

I added a pull request on github and put it here too : http://www.monkey-x.com/Community/posts.php?topic=8035
I basically rewrote the line generation function.


CopperCircle(Posted 2014) [#65]
Hi, quick update has been posted to the repo, Raz: your graph is working now :) , I also added linewidth scaling and tessellate v0.7. Difference I will add better support for your new line functions soon, thanks for the update.

[EDIT] Seems Git is playing up and the code did not post...!

Here is the latest version:



Difference(Posted 2014) [#66]
Theres a small glich with this version: It sends and empty first poly to TriangulateAndDrawPolygons witch causes the function to return without doing anything.

A quick fix is replacing the array sanity check in TriangulateAndDrawPolygons like this

replace
If Not newpoints.Length() Return ' no polygons
If Not newpoints[0].Length() Return 'no point in first poly
 

with
	
If Not newpoints.Length() Return ' no polygons
If Not newpoints[0].Length() 
	 'no point in first poly
	If newpoints.Length() =  1 Then Return  			
		'Throw away first poly
		newpoints = newpoints[1..]			
Endif	


That said, it's looking good!


CopperCircle(Posted 2014) [#67]
Thanks, I should have tested first!, I am changing the poly creation so there will be no empty polys soon. Also just tried the tiger.svg on GFLW and get the Array index error again on the pc?

While indexedpoly.ClipEar()
triangleindexes[i] = indexedpoly.ear[0]


Difference(Posted 2014) [#68]
Sorry, I should have tested too! :-) (well I sort of did, but this error only happens on GLFW Windows, not Mac...)

It's crashing because I forgot to uncomment If Self.Length() <3 Then Return False in Method ClipEar:Bool()

I updated the forum post with this fix, and will be posting a little update later today, where I hopefully found a better fix for inner protrutions in the line thingy.


Raz(Posted 2014) [#69]
Fantastic, bar chart fully rendering as expected :) I look forward to seeing the line graph working too.


Difference(Posted 2014) [#70]
Updated the thick lines with what I think is a good way of catching inner protrusions (when a thick line self intersects itself in a sharp corner)

http://www.monkey-x.com/Community/posts.php?topic=8035


CopperCircle(Posted 2014) [#71]
Great, GLFW working and the lines look much cleaner, also Raz the line graph SVG uses a multipoint line command which is not yet implement, SVG has so many commands and rules it will take abit of time to get them in.


Raz(Posted 2014) [#72]
No rush Copper :)


CopperCircle(Posted 2014) [#73]
It was a quick addition, repo has been updated.


Raz(Posted 2014) [#74]
Oh my god, that's amazing thank you :)


Difference(Posted 2014) [#75]
@CopperCircle - This is all going so well that I'd like to suggest a refactoring of the code!

I'd like to see the nodes go from SVG into monkey objects.
Then these objects generate points and triangles as needed.

This would allow for a number of enhancements, some of them beeing:

1) More robust code, easier to maintain.
2) Primitives that can be reused not just with SVG but by general monkey code
3) Equal point spacing for beziers and other curves
4) Robust corner preservation between segments even when changing resolution
5) Caching of triangulations, and point generated
6) Easy morphing between shapes.

I have already a little while ago made the beginning of such a system, that I'd be willing to share If you can be persuaded to take the project in that direction.

My code currently uses "Shapes", a collection of "Shape" made of "Shapesegments".

Shapesegments are Line, Arc, CubicBezier, etc.

I realize that this started out as a way to get SVG on the screen for capturing, but that will be totally possible with a refactoring to objects too.

Tell me your thoughts. :-)
If anybody else want's to chip in please do!


Nobuyuki(Posted 2014) [#76]
I actually was waiting for the shapes and path classes to be refactored in a more OO manner or friendly style myself, since I wanted to hack in de casteljau's method to the bezier lines, but it's a bit of a flat mess right now so I couldn't justify the time spent getting up to speed on the code.

+1 for a refactor,I want to consolidate my work on beziers with this project


CopperCircle(Posted 2014) [#77]
I definitely agree it needs a big refactor, it was just a proof of concept thrown together over a couple of evenings, but now the triangulation is working well across platforms it would be great to get it up to scratch or port an existing parser. The problem is I have very little time with work and a family so was hoping others may help with building it, we would then also be able to add SVG fonts which would be great.


Nobuyuki(Posted 2014) [#78]
The way I see it, the following things would be good to separate out:

1. Path rendering classes. The model can be a refresh/invalidate based one, this way a series of points (hereafter referred to as "fast data") can be stored in an array or a stack and reduce object re-instancing on a refresh where points need to be regenerated. This is more important for objects which need to be broken into discrete pieces manually, like beziers, arcs and the like. The hierarchy of path segments and compound paths can be interface-based, or based on an abstract base, to allow both types of objects to be rendered either together hierarchically in a list/stack, or individually (like when specifying drawing only a closed path's stroke or fill, and not both).

2. Shape / Compound path rendering / fill class. Probably has the same general interface as the above, but would include important extra components for rendering a compatible fill (abstract/interface), and more importantly, breaking a compound path into convex shapes / triangulating the fill.

3. Stroke and mitering classes. These are supposed to mitigate the "tight loop" problem, and are an accepted and standardized part of path rendering these days. Implementing recursive bezier rendering at a given resolution using one of the methods I mentioned very early on in the thread is pretty much a prerequisite to this, though, since a static/linear number of rendering points at "even" positions along a bezier is still an issue that no amount of mitering will make look correct at tight loops.

4. Parser classes. An internal object should contain all the metadata needed to render a graphic in the refactored module, agnostic to the serial format, since the format we use internally to display it "fast" is quite different from the underlying serialized format (svg) anyway. The individual rendering shape/path classes should have a "universal access" pre-generated output in the fast format, whereas it should be able to be fed parameters to generate this fast data in much easier ways. The purpose of the parser is to translate the language of the serialized format into parameters that the individual shape/path classes can turn into display data. How much processing the shape classes should do, and where, is a matter of debate. I'd advocate strongly against tying directly to the constructor, though a ctor can call the actual data-generating mutator with similar parameters. This is again to reduce the need to create new objects when point data needs to be refreshed.


Separating this out opens a lot more possibilities for the module than simply displaying vector graphics. Users could choose to create their own simple metadata format, for example, combining JSON with raw beziers to produce paths for game objects to travel. They could create collision data using the shape's point rasterization functions to automatically break up SVG paths into lines for box2d at low detail levels. They could use stroke and mitering to generate masks to prevent their objects from getting stuck on sharp points, or in tight squeezes. They could use it to generate a normal for a bezier curve. Etc.

I guess this is pretty much exactly what Difference was saying, only more long-winded, and not elaborating on morph targets or animation at all (since that's a really tough problem, and can probably be extended later). I'd be interested if we'd be able to tie together spine metadata with SVG and extra joint metadata, though I believe SVG has animation support built in, too. The latter is just seemingly a very complicated way to describe simple animation scripting, which we are probably gonna do in Monkey ourselves, anyway, since there aren't any good programs to generate SVG animations afaik.


CopperCircle(Posted 2014) [#79]
Hi, I am hoping to start refactoring this over the weekend, I will do it in bits as and when I have time. Thanks.


CopperCircle(Posted 2014) [#80]
I have made a start on refactoring and improving the parser, the repo has been updated.

"Refactored code into objects, added all SVG named colours, added W3.org basic SVG examples, added basic Transform Support, modified Tesselate to use scaling, changed basic shapes to use polys."


Nobuyuki(Posted 2014) [#81]
Looking good, man, keep up the good work! I'm glad to see BezierArrayCubic and similar functions split off. That should make it substantially easier to modify them with settings for rasterization. I recommend splitting off the segments arguments to separate "config" variables in the svgFunctions namespace, so that the method signature doesn't have to change when someone does start adding more advanced rasterizations to the bezier functions.

Edit: Segments are still specified in the svgPath class and really the home for it should probably go where all the other rasterization methods would eventually go. You could theoretically put the functions in a static class and have the settings as fields, but that would just make calling those functions take even more horizontal space, lol. Though that would keep some Const litter out of the root namespace... (Alternatively, an svgSettings class could also work)


Difference(Posted 2014) [#82]
Looking good.

I have now written my own SVG parser that sends the svg parts to objects , that can then be converted to points and triangulated, because that fit my needs better.

Can I ask that you keep scaling out of the tessellate code, and more importantly out of DrawTriangles, because I have just finished a generic version that will work on HTML5, GLFW and IOS, and if we're going to have any chance of getting it into mojo, I think it needs to be really basic.

I'll be posting a new version of tesselate + DrawTriangles for html5, glfw (almost idential to ios) later this week.

I'd like to put in functions for use with your parser, something like: GetIndexedTriangles() ?
I can put in scale and offfset parameters if you would like?

Class IndexedTriangles
	Field points:Float[]
	Field indexes:Int[]
End class

[EDIT] removed old code


CopperCircle(Posted 2014) [#83]
Sounds good, scale and offset would be handy thanks. Look forward to your update.


Difference(Posted 2014) [#84]
I've posted a new version of tessellate.monkey here : http://www.monkey-x.com/Community/posts.php?topic=8035

Also I posted the DrawTriangles function with native functions for HTML5 and GLFW here: http://www.monkey-x.com/Community/posts.php?topic=8246

I went back to the "index points to x coordinate" offset.

I made a public section and made most of the code private, so it should be easy to only use the tesselater to get back an instance of IndexedTriangles, and store a reference to that in the calling Class.

I added two simple functions for offset and scaling.

Also tessellate now expects nice clean input, but the CleanUpPolygon is included if needed, but you must call it yourself.


CopperCircle(Posted 2014) [#85]
Thanks for the update, sounds great, I will integrate the new version soon when I get some time to work on this.