But let’s return to Wordlase. It has a web demo now. I do not write any web-specific code in the game - it’s C89 application, compiled with Emscripten. If you follow the example (use of nkc_set_main_loop) than you will get web-version of your application for free.
The most interesting part of the Nuklear+ is supported frontends and backends. Frontend, in that case, means the part that initializes all OS-specific stuff. You can see implementation in the nkc_frontend folder. Currently supported: SDL, GLFW, X11, GDI+ frontends. They are not equal. For example, GDI+ uses WinAPI even for font rendering and image loading. So the resulting picture can be different. The implemented abilities are not equal too. For example, X11 frontend can’t change display resolution in fullscreen mode yet (pull requests are welcome).
How to select frontend? Define NKCD=NKC_x where x is one of: SDL, GLFW, XLIB, GDIP. For example: gcc -DNKCD=NKC_GLFW main.c
The backend is making an actual rendering. It is in nuklear_drivers folder. The OpenGL renderers will give pretty similar picture since they use equal functions for drawing and stb_image for pictures rendering. The pure X11 can’t even load fonts. So do not forget to test your application for your selected frontend+backend pair.
As you can see, the picture is the same. If there are any differences - it’s just a JPEG’s compression artifacts.
How to select backend? In general OpenGL 2 will be used by default. You can define NKC_USE_OPENGL=3 for OpenGL 3, or NKC_USE_OPENGL=NGL_ES2 for Open GL ES 2.0 if supported. Do not define NKC_USE_OPENGL if you want to use pure X11. OpenGL options do not affect GDI+ - it’s always WinAPI only.
Let’s see a GDI+ screen shoot too:
It’s supports semi-transparent PNG images, the picture looks almost the same as original OpenGL render. The difference is a font: hinting, anti-aliasing, size etc. Also, GDI+ renderer is not very fast on big images.
The worst case is a pure X11 renderer (it was even unable to load images before my pull request):
There are really many differences now: logo, the lights of a sun, sharp girl’s edge, font. Why? The game’s background is assembled from semi-transparent PNG images. But X11 supports only bit-transparency, as in a GIF-files. Also, it is really slow on big images with alpha. The situation without alpha enabled is even worse:
Why do we need pure Xlib and GDI+ is they are so ugly? They are bad for big semi-transparent images only. But if you are making small utility and use images for UI icons - these renderers can be a good variant since there a small amount of dependencies. Also, I used pure Xlib on a weak Linux systems with software OpenGL only. In that case, Xlib is much faster. Hint: One big non-transparent JPEG works fast and good on X11 too.
As an example of a good usage of pure X11 backend I want to show you a Wordlase’s gameplay window:
There are no big images, but a lot of simple interface icons, that not using transparency heavily.
Ok, now the renderer is selected, OS window is created. It’s time to write some GUI code!
The first Wordlase’s screen is a language select:
There are 2 interesting techniques on this screen: images on window’s background and widgets centering.
It’s pretty easy to put images on Nuklear window’s background:
nk_layout_space_push(ctx, nk_rect(x, y, width, height));
nk_image(ctx, img);
x and y are the position, related to the window. width and height - dimensions of the image.
Centering is a more complicated task. Nuklear does not support it, so you need to calculate position by yourself:
if ( nk_begin(ctx, WIN_TITLE,
nk_rect(0, 0, winWidth, winHeight), NK_WINDOW_NO_SCROLLBAR)
) {
int i;
/* 0.2 are a space skip on button's left and right, 0.6 - button */
static const float ratio[] = {0.2f, 0.6f, 0.2f}; /* 0.2+0.6+0.2=1 */
/* Just make vertical skip with calculated height of static row */
nk_layout_row_static(ctx,
(winHeight - (BUTTON_HEIGHT+VSPACE_SKIP)*langCount )/2, 15, 1
);
nk_layout_row(ctx, NK_DYNAMIC, BUTTON_HEIGHT, 3, ratio);
for(i=0; i<langCount; i++){
nk_spacing(ctx, 1); /* skip 0.2 left */
if( nk_button_image_label(ctx, image, caption, NK_TEXT_CENTERED)
){
loadLang(nkcHandle, ctx, i);
}
nk_spacing(ctx, 1); /* skip 0.2 right */
}
}
nk_end(ctx);
You can find funny theme selector widget in options:
It’s pretty easy to implement too:
if (nk_combo_begin_color(ctx, themeColors[s.curTheme],
nk_vec2(nk_widget_width(ctx), (LINE_HEIGHT+5)*WTHEME_COUNT) )
){
int i;
nk_layout_row_dynamic(ctx, LINE_HEIGHT, 1);
for(i=0; i<WTHEME_COUNT; i++)
if( nk_button_color(ctx, themeColors[i]) ){
nk_combo_close(ctx);
changeGUItheme(nkcHandle, s.curTheme);
}
nk_combo_end(ctx);
}
The implementation is based on fact that combo’s content is just a subwindow. You can place here anything you want.
The most complicated-looking screen is the main gameplay window:
But it’s not hard to implement. It’s just 4 rows on that screen:
So now the only question is how to create a button of exact concrete size in a line? It’s dealt with row’s ratio:
float ratio[] = {
(float)BUTTON_HEIGHT/winWidth, /* square button */
(float)BUTTON_HEIGHT/winWidth, /* square button */
(float)topWordSpace/winWidth,
(float)WORD_WIDTH/winWidth
};
nk_layout_row(ctx, NK_DYNAMIC, BUTTON_HEIGHT, 4, ratio);
The BUTTON_HEIGHT and WORD_WIDTH are constants in pixels, topWordSpace is calculated as winWidth minus all other elements widths.
The last complicated window is a current word’s statistics:
The layout is made with grouping: you can say to Nuklear, that there will be 2 widgets in the row. But the group is a widget too! Just use nk_group_begin and nk_group_end for creating a new group, then make layout inside this group in a usual way (nk_layout_row etc).
Nuklear is already ready even for commercial games and applications. Nuklear+ can help to make them easier.
ARTICLES
articles linux c gui tiny nuklear opengl
Dialogue & Discussion
ewe
Friday, February 15th, 2019, 01.17pm
Nice lib, but how do You write directly to desktop/main window? gui no hava any function for that.
DeXPeriX
Monday, February 18th, 2019, 06.34pm
I do not use any drawing API in this game. It is a pure Nuklear example. Putting image onto window’s background described in the article:
Leave a comment