Open aababy opened 8 years ago
Almost correct! :)
for (path = shape->paths; path != NULL; path = path->next) {
nvgMoveTo(vg, path->pts[0], path->pts[1]);
for (i = 0; i < path->npts-1; i += 3) {
float* p = &path->pts[i*2];
nvgBeginPath(vg);
nvgBezierTo(vg, p[2], p[3], p[4], p[5], p[6], p[7]);
nvgStroke(vg);
}
}
If you want to draw filled shapes, Nanovg requires you to define holes explicitly. The following paper shows you how to calculate the area of a bezier poly, which you can use to set the solid/hole. https://tug.org/TUGboat/tb33-1/tb103jackowski.pdf
Hi, Mikko, thank you for your response. But when I use your code. It show me a blank canvas.
for (shape = g_image->shapes; shape != NULL; shape = shape->next) {
nvgStrokeWidth(vg, shape->strokeWidth);
for (path = shape->paths; path != NULL; path = path->next) {
nvgMoveTo(vg, path->pts[0], path->pts[1]);
for (i = 0; i < path->npts-1; i += 3) {
float* p = &path->pts[i*2];
nvgBeginPath(vg);
nvgBezierTo(vg, p[2], p[3], p[4], p[5], p[6], p[7]);
nvgStroke(vg);
}
}
}
How about this?
for (shape = g_image->shapes; shape != NULL; shape = shape->next) {
nvgStrokeWidth(vg, shape->strokeWidth);
for (path = shape->paths; path != NULL; path = path->next) {
nvgBeginPath(vg);
nvgMoveTo(vg, path->pts[0], path->pts[1]);
for (i = 0; i < path->npts-1; i += 3) {
float* p = &path->pts[i*2];
nvgBeginPath(vg);
nvgBezierTo(vg, p[2], p[3], p[4], p[5], p[6], p[7]);
}
if (path->closed)
nvgLineTo(vg, path->pts[0], path->pts[1]);
nvgStroke(vg);
}
}
Thank you for your help, I have modify the code, and it almost render all the files in nanosvg sample.(drawing.svg, 23.svg). But when I rendering "nano.svg", it show me a black rectangle. Am I need to calculate the area of a bezier poly? I also reference from nanosvgrast.h. https://tug.org/TUGboat/tb33-1/tb103jackowski.pdf but the pdf is too complex. and it's too difficult to understand the relationship between the pdf and nanovg. How could I do it?
for (shape = g_image->shapes; shape != NULL; shape = shape->next) {
if (!(shape->flags & NSVG_FLAGS_VISIBLE))
continue;
nvgFillColor(vg, getNVGColor(shape->fill.color));
nvgStrokeColor(vg, getNVGColor(shape->stroke.color));
nvgStrokeWidth(vg, shape->strokeWidth);
for (path = shape->paths; path != NULL; path = path->next) {
nvgBeginPath(vg);
nvgMoveTo(vg, path->pts[0], path->pts[1]);
for (i = 0; i < path->npts-1; i += 3) {
float* p = &path->pts[i*2];
nvgBezierTo(vg, p[2], p[3], p[4], p[5], p[6], p[7]);
}
if (path->closed)
nvgLineTo(vg, path->pts[0], path->pts[1]);
if(shape->fill.type)
nvgFill(vg);
if(shape->stroke.type)
nvgStroke(vg);
}
}
Hi,
I have a further question along the line of using nanosvg with nanovg.
Specifically I am trying to get linear gradients working.
I understand, that the contents of shape->fill.gradient->xform
contain some kind of transform of the gradient coordinates. and the paint object of nanoVG also contain an xform array.
When I tried copying, it did not work and I tried manually creating a gradient with nvgLinearGradient()
, but I could not figure out how to generate the gradient coordinates from gradient.xform
.
So my question would be how do I generate a linear gradient for NanoVG from the gradient object in NanoSVG? And while we are at it I would not mind getting the radial gradient to work aswell :)
the gradient transform is inverse transform, that is, if you multiply a world position with the matrix, you'll get a point in the gradient, where start is 0 and end is 1. If you take inverse of the gradient matrix, then you should be able to figure out the world positions from that.
Thanks! That worked well.
Inverse gradient matrix more-or-less helped for linear gradients. However, using this code:
NVGpaint createLinearGradient(NSVGgradient* gradient, float alpha) {
float inverse[6];
float sx, sy, ex, ey;
nvgTransformInverse(inverse, gradient->xform);
nvgTransformPoint(&sx, &sy, inverse, 0, 0);
nvgTransformPoint(&ex, &ey, inverse, 0, 1);
return nvgLinearGradient(vg, sx, sy, ex, ey,
SVGCOLOR4(gradient->stops[0].color, alpha),
SVGCOLOR4(gradient->stops[gradient->nstops - 1].color, alpha));
}
there is still some inaccuracy. Original SVG picture (created in Inkscape):
is rendered as:
The same shift of positions happens also in Y axis. Mikko, could you please help me to fix it? Do you have some idea of what's wrong?
Another issue is radial gradient. Could you please give me some code snippet or at least hint how to transform NSVGgradient to NVGpaint for radial gradients? Center can be obtained by transforming point (0,0) with inverse gradient matrix, but I have no clue how to compute radius.
Thanks in advance for your help.
Could you post the above svg here?
The circular gradient is drawn so that the circle center is at (0,0), and the radius is 1 units. So, for a very simple case:
nvgTransformPoint(&sx, &sy, inverse, 0, 0);
nvgTransformPoint(&ex, &ey, inverse, 0, 1);
radius = ey - sy;
Currently there's not enough API to pass scaled/skewed radial gradient to NanoVG.
Mikko, BTW circular gradient works fine. Thanks!
However, also here I can observe a problem with transforming positions far from origin of the picture. So also gradient radius works well if the object is placed near to the page origin, but is incorrect for objects place far from it. Example:
y.zip
with two identical rectangles having identical radial gradient placed at different positions is rendered as:
Upper left rectangle is within page boundaries, lower right rectangle is outside/far from origin.
After several other experiments with radial gradient I found that the problem is not distance from page origin, but distance from its diagonal. Above diagonal, rendered radius is smaller, below diagonal the radius is bigger. See this example:
z.zip
I checked with nanosvg raserizer and it works fine. So things should be ok.
Can you post the exact code whch you use to create the gradient?
Sure, here is my current working version of the source file for ZgeNano library - a wrapper for NanoVG and NanoSVG libraries used in ZGameEditor. Please have a look at the nsvg_Draw function. Maybe there's something wrong also in nvg_Init() (???). Thanks for your time.
This is not correct:
nvgTransformPoint(&cx, &cy, inverse, 0, 0);
nvgTransformPoint(&r1, &r2, inverse, 0, 1);
outr = r2 - r1;
It should be:
nvgTransformPoint(&cx, &cy, inverse, 0, 0);
nvgTransformPoint(&r1, &r2, inverse, 0, 1);
outr = r2 - cy;
The point r1,r2 is essentially a point on the top (or bottom, can remember), of the gradient circle. So you get radius by subtracting the center. You could also take the distance between the points.
That does not explain the linear gradient problem. Maybe I gave you the wrong point for the linear gradient, you could try:
nvgTransformPoint(&ex, &ey, inverse, 1, 0);
Sure, radial gradients now work fine. Thanks.
nvgTransformPoint(&ex, &ey, inverse, 1, 0);
does not help - it rotates linear gradient by 90 degrees. Does your SVG rendered process it correctly?
Mikko, I tested the current rendering on several free and quite complex svg pictures (e.g. this) and rendering is fine. It's maybe problem of that particular image (x.svg) I used for testing before. I do not think shifting of linear gradient is some serious and practical problem, so not sure it is worth of debugging/fixing. But it is up to you.
BTW do you plan to support also blur, clipping and/or masking in NanoSVG nd NanoVG?
The linear gradient problem seems to happen also with the rasterizer, so there's something wrong with the parser. Would you mind opening another issues about that? include the image and zip file with it.
Blurring and masking would be awesome, but they complicate the rendering a lot, so no plans to do that for the time being.
A new issue #75 has been created for linear gradients.
Blurring and masking would be awesome, but they complicate the rendering a lot, so no plans to do that for the time being.
That's pity, at least blur would help, because it's being used quite frequently.
Is comparing the area by Boguslaw Jackowski the most straightfoward way to determine the whether nvgPathWinding(vg, NVG_SOLID)
vs nvgPathWinding(vg, NVG_HOLE)
should be used after drawing the path? I wouldn't be opposed to implementing this in my nanovg/nanosvg renderer, but I'm wondering if there's an easier trick than that.
Actually, now that I think about it, comparing areas doesn't seem like it would suffice. What if I want to support paths like this? It can be drawn in nanovg explicitly, but I'm not sure how I can extract the evenness/oddness of a subpath from nanosvg's data structure.
Maybe related, maybe even trivial, but I would like to use the rasterized image as paint, I am following the example here https://github.com/memononen/nanosvg/blob/master/example/example2.c but don't really know how to go from unsigned char* img
to something that behaves like the data returned by nvgCreateImage
which can be used as fill, any tips ?
@AndrewBelt, have you come up with a generic solution to handle SVG's with holes?
@kpeeters I don't remember if I added full support or not and I'm on my mobile device so I didn't look too deeply, but if I did, it would be here. https://github.com/VCVRack/Rack/blob/v0.6/src/widgets/SVGWidget.cpp#L91
I was able to get nanosvg and nanovg working together using @AndrewBelt's code with minimal modification. As of now, the actively developed version of VCVRack with the latest version of the glue code is here.
Since the rest of the GUI I'm working in isn't rendered with nanovg or Rack widgets, I needed some additional nanovg calls to get the SVG rendering to be within the desired screen space: nvgScissor
, nvgTranslate
, and nvgScale
calls before the svgDraw
call.
I do get some stdout error message spam, Error 00000501 after fill simple
when the rendered area quite small, though. This appears to be coming from within nanovg
Not really relevant to nanosvg, but I thought the follow-up could be helpful...
This is not an issue, but I don't know the way to contact with you. Hi, I'm look to use nanovg to render SVG with the data parse from nanosvg. Could you help me correct this code to support full feature (just like open the svg file with a svg viewer)? I have search the google, but find nothing about this. Could you append it into readme.md. Thank you.