Nuklear
Nuklear copied to clipboard
Why are there small deviations in gaps between drawn columns in charts?
Consider:
...
#define WINDOW_WIDTH 800
#define WINDOW_HEIGHT 600
...
...
if (nk_begin(ctx, "BareMusic", nk_rect(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT),
NK_WINDOW_BORDER|NK_WINDOW_NO_SCROLLBAR|NK_WINDOW_TITLE))
{
nk_layout_row_dynamic(ctx, 100, 1);
if (nk_group_begin(ctx, "1", NK_WINDOW_BORDER | NK_WINDOW_NO_SCROLLBAR)) {
nk_group_end(ctx);
}
/* IMAGE HAS THE RESULT OF FOLLOWING */
if (nk_chart_begin(ctx,NK_CHART_COLUMN,16,0,4))
{
int i;
for (i = 0; i < 16; ++i)
nk_chart_push(ctx, 4);
nk_chart_end(ctx);
}
}
nk_end(ctx);
...
Result is:

Your image is unaccesible to me, just copy paste the screen shot in the github issue and it should autoupload...
What I think you are reffering to are the unqeual gaps between the bar graphs:

The reason is: Although the chart bars are floating point nk_rect...

...they are being converted to integers in the command cue. Specifically the nk_command_rect_filled struct:
struct nk_command_rect_filled {
struct nk_command header;
struct nk_vec4 rounding;
short x, y;
unsigned short w, h;
struct nk_color color;
};
This is done, because non-integer drawing of windows will result in an unsharp appearance of windows. However, in the case of the chart bars, this clashes visually as you found out.
Quick and dirty workaround is editing nk_chart_push_column(): The column X position is defined by the two lines:
item.x = chart->x + ((float)chart->slots[slot].index * item.w);
item.x = item.x + ((float)chart->slots[slot].index);
Forcing item width to be integer will always make the column gaps the same:
item.x = chart->x + ((float)chart->slots[slot].index * (int)item.w);
item.x = item.x + ((float)chart->slots[slot].index);
The int conversion will always round down, so it will be fine layout wise. Only caveat is that at certain sizes, there will be a fraction of a column blank space created.

Do you think this is properly designed? I have a faint memory that I was writing a similar construct using raw OpenGL or something, and I believe I found some no-compromise solution to this kind of drawing.
Particularly, I think it should work fine with floats, but you may need to use a suitable precision of decimals and/or e.g. fix the widget l/w to e.g. numbers that are evenly or oddly divisible. So that one can guarantee that the boxes and their gaps will always align.
Do you think this is properly designed?
In regards to snapping GUI coordinates to integers? I think that's perfectly fine. Especially once textured elements come into play, being off-pixel results in severe sharpness loss. Just take a look what insane feats text rendering demands to account for sub-pixel positioning: baking multiple subpixel versions of Glyphs. This is quite the rabbit-hole, so snapping to integers as Nuklear does even for text with when enabled, is a perfectly fine strategy.
In regards to the use-case of integer snapping in column charts and histograms - it's clearly wrong, as demonstrated this by this issue. If you have any ideas on how to properly fix it, make a PR. Such a fix is very welcome.
My proposal is this: Round down to the integer, exactly as with item.x = chart->x + ((float)chart->slots[slot].index * (int)item.w); and make sure the columns are middle aligned, instead of left-aligned. (In fact this middle-align would have to be carried out with all Chart layers, so a line chart + column chart + histograms would all line up with one-another.)
This will avoid the glaring missing empty column at certain sizes, fix the gap problem and would not need a new command type for subpixel positioning.
This is done, because non-integer drawing of windows will result in an unsharp appearance of windows.
But is this a result of Nuklear or the backend?
This is done, because non-integer drawing of windows will result in an unsharp appearance of windows.
But is this a result of Nuklear or the backend?
Nuklear.
But I mean e.g. because:
https://gamedev.stackexchange.com/questions/138837/drawing-at-floating-point-position
What happens on the back-end is the concern of the back-end. nk_convert() is tasked with outputting vertex positions and can be configured to whatever you need. For instance, in Nuklear's OpenGL backend, configures this here: https://github.com/Immediate-Mode-UI/Nuklear/blob/master/demo/glfw_opengl3/nuklear_glfw_gl3.h#L259 Going to the GPU, all positions and UV coordinates are FLOAT.
It's just, that in regards to positioning and sizing of Windows, Buttons and other elements those floats are rounded to have no decimal place to prevent sub-pixel blurring. Whether the graphics chip gets positions in ints or floats can be configured as you like. If you specifically believe the removal of the decimal place to prevent subpixel positioning to be sub-optimal for your use-case, change it and send a PR.
I think one doesn't need to restrict to integers, but one must ensure the divisibility and aligning of even/odd widths. https://www.foster77.co.uk/Foster,%20Mathematical%20Spectrum,%20Odd%20and%20Even%20Fractions.pdf
I didn't particularly understand why one allows rect to have w=16.5625 unless one can ensure that the chart's w without padding aligns evenly to n*w (and of course one'd need to account for the paddings of the bars themselves as well).