Nuklear icon indicating copy to clipboard operation
Nuklear copied to clipboard

Request: use dynamic values for number of vertices etc.

Open ronaaron opened this issue 5 years ago • 6 comments

The samples use 22 as the number of vertices for a curve/circle. If you draw a large circle, it ends up looking quite rough. So in one of my samples I set it to 100... but then not all the points can be rendered because there are too many.

The sample I'm talking about is just a clock, so there's a big outer circle and a bunch of smaller 'dots' as minute/hour indicators, as well as the clock hands.

Yes, probably it would be better to render a bitmap and blit it but that's not what the sample is about.

I would like to suggest that instead of using a hard-coded value for the number of vertices, perhaps it would be better to use a "maximum number of pixels" for the length of each segment. So that when drawing a circle, the number of vertices used would increase as the radius did, to maintain a level of smoothness uniformly without overtaxing memory.

Open to other suggestions...

ronaaron avatar Apr 10 '20 07:04 ronaaron

I would like to suggest that instead of using a hard-coded value for the number of vertices, perhaps it would be better to use a "maximum number of pixels" for the length of each segment. So that when drawing a circle, the number of vertices used would increase as the radius did, to maintain a level of smoothness uniformly without overtaxing memory.

Yep, a dynamic adjustment in runtime seems desirable (though we can discuss whether "max num of px" should be the input or some other "dynamic" specification).

Could you sketch which functions would you want to change or mimic in a potential PR, so that we can discuss it more specifically here?

dumblob avatar Apr 10 '20 08:04 dumblob

I would have to think a lot harder about it to come up with something useful, I think.

That said, anything which currently touches the nk_convert_config's *_segment_count is something which needs to be thought about.

I believe it's sufficient to deal solely with the nk_convert() function as it handles the circle and arc and curve drawing commands.

For my purposes, I think it would be ok to have a pixel value as the 'largest segment' allowable. Certainly it makes no sense to have tons of lines which are sub-pixel. Perhaps it makes sense to cull them somehow?

It really sucks that OpenGL doesn't have a curve primitive... although I see something called 'evaluators' which might be just what's needed.

ronaaron avatar Apr 10 '20 09:04 ronaaron

OK, here's a code snippet which seems to do a good job. I only put it in nk_draw_list_path_arc_to(), just before where "d_angle" is calculated (because that depends on 'segments'). I'm ignoring the passed-in segments value, and calculating a new one based on the arc-length:

const float abs_angle = NK_ABS(a_max-a_min);
const float arc_length = (NK_PI * radius * abs_angle) / 180;
const float factor = NK_MAX(arc_length, 1);
segments = 8*factor;

Yes, it's a bit more verbose than it needs to be, but I wanted the gist to be clear.

Comments?

ronaaron avatar Apr 12 '20 14:04 ronaaron

Slightly different: make the length of each segment smaller than some 'tolerance' value. I have no idea how to pick a good one, but this seems to work tolerably well:

/* make segments smaller than tolerance: */
const static float tolerance = 0.06;
/* adjust segments based on the radius and number of degrees */
const float abs_angle = NK_ABS(a_max-a_min);
const float arc_length = (NK_PI * radius * abs_angle) / 180;
segments = arc_length / tolerance ;

In both cases, there should be something like

segments = NK_MIN(max_segments, segments);

ronaaron avatar Apr 13 '20 05:04 ronaaron

OK, I think for arc and circle, this code works great:

/* make segments smaller than tolerance: */
const static float tolerance = 3;
/* adjust segments based on the radius and number of degrees */
const float angle = NK_ABS(a_max-a_min);
const float arc_length = radius * angle ;
/* clamp segments to range of [6,1024] */
segments = NK_MIN(1024,NK_MAX(6,NK_ABS(arc_length / tolerance))) ;

const float d_angle = angle / (float)segments;

It should therefore be possible to eliminate the 'segments' parameter for arc drawing, and remove the arc and circle members of the config structure.

ronaaron avatar Apr 13 '20 17:04 ronaaron

Bumping this issue. A very small and simple circle can take a huge amount of rectangles to draw.

Image

Image

sleeptightAnsiC avatar Jun 05 '25 16:06 sleeptightAnsiC