Skip to content

removed global object in SDL2 demo, more C++-friendly API #799

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 45 additions & 45 deletions demo/sdl_opengl2/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -79,13 +79,14 @@ int
main(int argc, char *argv[])
{
/* Platform */
struct nk_sdl sdl;
SDL_Window *win;
SDL_GLContext glContext;
int win_width, win_height;
int running = 1;

/* GUI */
struct nk_context *ctx;
struct nk_context ctx;
struct nk_colorf bg;

#ifdef INCLUDE_CONFIGURATOR
Expand All @@ -111,18 +112,18 @@ main(int argc, char *argv[])
SDL_GetWindowSize(win, &win_width, &win_height);

/* GUI */
ctx = nk_sdl_init(win);
nk_sdl_init(&ctx, &sdl);
/* Load Fonts: if none of these are loaded a default font will be used */
/* Load Cursor: if you uncomment cursor loading please hide the cursor */
{struct nk_font_atlas *atlas;
nk_sdl_font_stash_begin(&atlas);
/*struct nk_font *droid = nk_font_atlas_add_from_file(atlas, "../../../extra_font/DroidSans.ttf", 14, 0);*/
/*struct nk_font *roboto = nk_font_atlas_add_from_file(atlas, "../../../extra_font/Roboto-Regular.ttf", 16, 0);*/
/*struct nk_font *future = nk_font_atlas_add_from_file(atlas, "../../../extra_font/kenvector_future_thin.ttf", 13, 0);*/
/*struct nk_font *clean = nk_font_atlas_add_from_file(atlas, "../../../extra_font/ProggyClean.ttf", 12, 0);*/
/*struct nk_font *tiny = nk_font_atlas_add_from_file(atlas, "../../../extra_font/ProggyTiny.ttf", 10, 0);*/
/*struct nk_font *cousine = nk_font_atlas_add_from_file(atlas, "../../../extra_font/Cousine-Regular.ttf", 13, 0);*/
nk_sdl_font_stash_end();
{
nk_sdl_font_stash_begin(&sdl);
/*struct nk_font *droid = nk_font_atlas_add_from_file(sdl.atlas, "../../../extra_font/DroidSans.ttf", 14, 0);*/
/*struct nk_font *roboto = nk_font_atlas_add_from_file(sdl.atlas, "../../../extra_font/Roboto-Regular.ttf", 16, 0);*/
/*struct nk_font *future = nk_font_atlas_add_from_file(sdl.atlas, "../../../extra_font/kenvector_future_thin.ttf", 13, 0);*/
/*struct nk_font *clean = nk_font_atlas_add_from_file(sdl.atlas, "../../../extra_font/ProggyClean.ttf", 12, 0);*/
/*struct nk_font *tiny = nk_font_atlas_add_from_file(sdl.atlas, "../../../extra_font/ProggyTiny.ttf", 10, 0);*/
/*struct nk_font *cousine = nk_font_atlas_add_from_file(sdl.atlas, "../../../extra_font/Cousine-Regular.ttf", 13, 0);*/
nk_sdl_font_stash_end(&ctx, &sdl);
/*nk_style_load_all_cursors(ctx, atlas->cursors);*/
/*nk_style_set_font(ctx, &roboto->handle)*/;}

Expand All @@ -131,63 +132,63 @@ main(int argc, char *argv[])
{
/* Input */
SDL_Event evt;
nk_input_begin(ctx);
nk_input_begin(&ctx);
while (SDL_PollEvent(&evt)) {
if (evt.type == SDL_QUIT) goto cleanup;
nk_sdl_handle_event(&evt);
nk_sdl_handle_event(&ctx, &evt);
}
nk_sdl_handle_grab(); /* optional grabbing behavior */
nk_input_end(ctx);
nk_sdl_handle_grab(&ctx, win); /* optional grabbing behavior */
nk_input_end(&ctx);

/* GUI */
if (nk_begin(ctx, "Demo", nk_rect(50, 50, 230, 250),
if (nk_begin(&ctx, "Demo", nk_rect(50, 50, 230, 250),
NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_SCALABLE|
NK_WINDOW_MINIMIZABLE|NK_WINDOW_TITLE))
{
enum {EASY, HARD};
static int op = EASY;
static int property = 20;

nk_layout_row_static(ctx, 30, 80, 1);
if (nk_button_label(ctx, "button"))
nk_layout_row_static(&ctx, 30, 80, 1);
if (nk_button_label(&ctx, "button"))
fprintf(stdout, "button pressed\n");
nk_layout_row_dynamic(ctx, 30, 2);
if (nk_option_label(ctx, "easy", op == EASY)) op = EASY;
if (nk_option_label(ctx, "hard", op == HARD)) op = HARD;
nk_layout_row_dynamic(ctx, 25, 1);
nk_property_int(ctx, "Compression:", 0, &property, 100, 10, 1);

nk_layout_row_dynamic(ctx, 20, 1);
nk_label(ctx, "background:", NK_TEXT_LEFT);
nk_layout_row_dynamic(ctx, 25, 1);
if (nk_combo_begin_color(ctx, nk_rgb_cf(bg), nk_vec2(nk_widget_width(ctx),400))) {
nk_layout_row_dynamic(ctx, 120, 1);
bg = nk_color_picker(ctx, bg, NK_RGBA);
nk_layout_row_dynamic(ctx, 25, 1);
bg.r = nk_propertyf(ctx, "#R:", 0, bg.r, 1.0f, 0.01f,0.005f);
bg.g = nk_propertyf(ctx, "#G:", 0, bg.g, 1.0f, 0.01f,0.005f);
bg.b = nk_propertyf(ctx, "#B:", 0, bg.b, 1.0f, 0.01f,0.005f);
bg.a = nk_propertyf(ctx, "#A:", 0, bg.a, 1.0f, 0.01f,0.005f);
nk_combo_end(ctx);
nk_layout_row_dynamic(&ctx, 30, 2);
if (nk_option_label(&ctx, "easy", op == EASY)) op = EASY;
if (nk_option_label(&ctx, "hard", op == HARD)) op = HARD;
nk_layout_row_dynamic(&ctx, 25, 1);
nk_property_int(&ctx, "Compression:", 0, &property, 100, 10, 1);

nk_layout_row_dynamic(&ctx, 20, 1);
nk_label(&ctx, "background:", NK_TEXT_LEFT);
nk_layout_row_dynamic(&ctx, 25, 1);
if (nk_combo_begin_color(&ctx, nk_rgb_cf(bg), nk_vec2(nk_widget_width(&ctx),400))) {
nk_layout_row_dynamic(&ctx, 120, 1);
bg = nk_color_picker(&ctx, bg, NK_RGBA);
nk_layout_row_dynamic(&ctx, 25, 1);
bg.r = nk_propertyf(&ctx, "#R:", 0, bg.r, 1.0f, 0.01f,0.005f);
bg.g = nk_propertyf(&ctx, "#G:", 0, bg.g, 1.0f, 0.01f,0.005f);
bg.b = nk_propertyf(&ctx, "#B:", 0, bg.b, 1.0f, 0.01f,0.005f);
bg.a = nk_propertyf(&ctx, "#A:", 0, bg.a, 1.0f, 0.01f,0.005f);
nk_combo_end(&ctx);
}
}
nk_end(ctx);
nk_end(&ctx);

/* -------------- EXAMPLES ---------------- */
#ifdef INCLUDE_CALCULATOR
calculator(ctx);
calculator(&ctx);
#endif
#ifdef INCLUDE_CANVAS
canvas(ctx);
canvas(&ctx);
#endif
#ifdef INCLUDE_OVERVIEW
overview(ctx);
overview(&ctx);
#endif
#ifdef INCLUDE_CONFIGURATOR
style_configurator(ctx, color_table);
style_configurator(&ctx, color_table);
#endif
#ifdef INCLUDE_NODE_EDITOR
node_editor(ctx);
node_editor(&ctx);
#endif
/* ----------------------------------------- */

Expand All @@ -201,15 +202,14 @@ main(int argc, char *argv[])
* defaults everything back into a default state.
* Make sure to either a.) save and restore or b.) reset your own state after
* rendering the UI. */
nk_sdl_render(NK_ANTI_ALIASING_ON);
nk_sdl_render(&ctx, &sdl, win, NK_ANTI_ALIASING_ON);
SDL_GL_SwapWindow(win);
}

cleanup:
nk_sdl_shutdown();
nk_sdl_shutdown(&ctx, &sdl);
SDL_GL_DeleteContext(glContext);
SDL_DestroyWindow(win);
SDL_Quit();
return 0;
}

117 changes: 55 additions & 62 deletions demo/sdl_opengl2/nuklear_sdl_gl2.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,26 @@
#define NK_SDL_GL2_H_

#include <SDL2/SDL.h>
NK_API struct nk_context* nk_sdl_init(SDL_Window *win);
NK_API void nk_sdl_font_stash_begin(struct nk_font_atlas **atlas);
NK_API void nk_sdl_font_stash_end(void);
NK_API int nk_sdl_handle_event(SDL_Event *evt);
NK_API void nk_sdl_render(enum nk_anti_aliasing);
NK_API void nk_sdl_shutdown(void);
NK_API void nk_sdl_handle_grab(void);

struct nk_sdl_device {
struct nk_buffer cmds;
struct nk_draw_null_texture tex_null;
GLuint font_tex;
};

struct nk_sdl {
struct nk_sdl_device ogl;
struct nk_font_atlas atlas;
Uint64 time_of_last_frame;
};

NK_API void nk_sdl_init(struct nk_context *ctx, struct nk_sdl *sdl);
NK_API void nk_sdl_font_stash_begin(struct nk_sdl *sdl);
NK_API void nk_sdl_font_stash_end(struct nk_context *ctx, struct nk_sdl *sdl);
NK_API int nk_sdl_handle_event(struct nk_context *ctx, SDL_Event *evt);
NK_API void nk_sdl_render(struct nk_context *ctx, struct nk_sdl *sdl, SDL_Window *win, enum nk_anti_aliasing);
NK_API void nk_sdl_shutdown(struct nk_context *ctx, struct nk_sdl *sdl);
NK_API void nk_sdl_handle_grab(struct nk_context *ctx, SDL_Window *win);

#endif
/*
Expand All @@ -34,30 +47,15 @@ NK_API void nk_sdl_handle_grab(void);
#include <string.h>
#include <stdlib.h>

struct nk_sdl_device {
struct nk_buffer cmds;
struct nk_draw_null_texture tex_null;
GLuint font_tex;
};

struct nk_sdl_vertex {
float position[2];
float uv[2];
nk_byte col[4];
};

static struct nk_sdl {
SDL_Window *win;
struct nk_sdl_device ogl;
struct nk_context ctx;
struct nk_font_atlas atlas;
Uint64 time_of_last_frame;
} sdl;

NK_INTERN void
nk_sdl_device_upload_atlas(const void *image, int width, int height)
nk_sdl_device_upload_atlas(struct nk_sdl_device *dev, const void *image, int width, int height)
{
struct nk_sdl_device *dev = &sdl.ogl;
glGenTextures(1, &dev->font_tex);
glBindTexture(GL_TEXTURE_2D, dev->font_tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
Expand All @@ -67,20 +65,20 @@ nk_sdl_device_upload_atlas(const void *image, int width, int height)
}

NK_API void
nk_sdl_render(enum nk_anti_aliasing AA)
nk_sdl_render(struct nk_context *ctx, struct nk_sdl *sdl, SDL_Window *win, enum nk_anti_aliasing AA)
{
/* setup global state */
struct nk_sdl_device *dev = &sdl.ogl;
struct nk_sdl_device *dev = &sdl->ogl;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if any of ctx, sdl, win and similar pointers are nullptr in the NK_API type interfaces?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

UB obviously. This patch isn't a real PR. It's just a proof of concept and to ask library maintainers whether they like this direction.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While it is a big change in how the demo is set up, I believe the benefits out of thread-safety does outweigh the cons of backward compatibility breaks. We could add some NK_ASSERT()s to ensure there arn't any nullptrs.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes yes I will improve the patch by adding some comments (to better explain the API), do similar changes in other SDL examples and add missing assertions,

int width, height;
int display_width, display_height;
struct nk_vec2 scale;

Uint64 now = SDL_GetTicks64();
sdl.ctx.delta_time_seconds = (float)(now - sdl.time_of_last_frame) / 1000;
sdl.time_of_last_frame = now;
Uint64 now = SDL_GetTicks();
ctx->delta_time_seconds = (float)(now - sdl->time_of_last_frame) / 1000;
sdl->time_of_last_frame = now;

SDL_GetWindowSize(sdl.win, &width, &height);
SDL_GL_GetDrawableSize(sdl.win, &display_width, &display_height);
SDL_GetWindowSize(win, &width, &height);
SDL_GL_GetDrawableSize(win, &display_width, &display_height);
scale.x = (float)display_width/(float)width;
scale.y = (float)display_height/(float)height;

Expand Down Expand Up @@ -139,7 +137,7 @@ nk_sdl_render(enum nk_anti_aliasing AA)
/* convert shapes into vertexes */
nk_buffer_init_default(&vbuf);
nk_buffer_init_default(&ebuf);
nk_convert(&sdl.ctx, &dev->cmds, &vbuf, &ebuf, &config);
nk_convert(ctx, &dev->cmds, &vbuf, &ebuf, &config);

/* setup vertex buffer pointer */
{const void *vertices = nk_buffer_memory_const(&vbuf);
Expand All @@ -149,7 +147,7 @@ nk_sdl_render(enum nk_anti_aliasing AA)

/* iterate over and execute each draw command */
offset = (const nk_draw_index*)nk_buffer_memory_const(&ebuf);
nk_draw_foreach(cmd, &sdl.ctx, &dev->cmds)
nk_draw_foreach(cmd, ctx, &dev->cmds)
{
if (!cmd->elem_count) continue;
glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id);
Expand All @@ -161,7 +159,7 @@ nk_sdl_render(enum nk_anti_aliasing AA)
glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset);
offset += cmd->elem_count;
}
nk_clear(&sdl.ctx);
nk_clear(ctx);
nk_buffer_clear(&dev->cmds);
nk_buffer_free(&vbuf);
nk_buffer_free(&ebuf);
Expand Down Expand Up @@ -211,58 +209,53 @@ nk_sdl_clipboard_copy(nk_handle usr, const char *text, int len)
free(str);
}

NK_API struct nk_context*
nk_sdl_init(SDL_Window *win)
NK_API void
nk_sdl_init(struct nk_context *ctx, struct nk_sdl *sdl)
{
sdl.win = win;
nk_init_default(&sdl.ctx, 0);
sdl.ctx.clip.copy = nk_sdl_clipboard_copy;
sdl.ctx.clip.paste = nk_sdl_clipboard_paste;
sdl.ctx.clip.userdata = nk_handle_ptr(0);
nk_buffer_init_default(&sdl.ogl.cmds);
sdl.time_of_last_frame = SDL_GetTicks64();
return &sdl.ctx;
nk_init_default(ctx, 0);
ctx->clip.copy = nk_sdl_clipboard_copy;
ctx->clip.paste = nk_sdl_clipboard_paste;
ctx->clip.userdata = nk_handle_ptr(0);
nk_buffer_init_default(&sdl->ogl.cmds);
sdl->time_of_last_frame = SDL_GetTicks();
}

NK_API void
nk_sdl_font_stash_begin(struct nk_font_atlas **atlas)
nk_sdl_font_stash_begin(struct nk_sdl *sdl)
{
nk_font_atlas_init_default(&sdl.atlas);
nk_font_atlas_begin(&sdl.atlas);
*atlas = &sdl.atlas;
nk_font_atlas_init_default(&sdl->atlas);
nk_font_atlas_begin(&sdl->atlas);
}

NK_API void
nk_sdl_font_stash_end(void)
nk_sdl_font_stash_end(struct nk_context *ctx, struct nk_sdl *sdl)
{
const void *image; int w, h;
image = nk_font_atlas_bake(&sdl.atlas, &w, &h, NK_FONT_ATLAS_RGBA32);
nk_sdl_device_upload_atlas(image, w, h);
nk_font_atlas_end(&sdl.atlas, nk_handle_id((int)sdl.ogl.font_tex), &sdl.ogl.tex_null);
if (sdl.atlas.default_font)
nk_style_set_font(&sdl.ctx, &sdl.atlas.default_font->handle);
image = nk_font_atlas_bake(&sdl->atlas, &w, &h, NK_FONT_ATLAS_RGBA32);
nk_sdl_device_upload_atlas(&sdl->ogl, image, w, h);
nk_font_atlas_end(&sdl->atlas, nk_handle_id((int)sdl->ogl.font_tex), &sdl->ogl.tex_null);
if (sdl->atlas.default_font)
nk_style_set_font(ctx, &sdl->atlas.default_font->handle);
}

NK_API void
nk_sdl_handle_grab(void)
nk_sdl_handle_grab(struct nk_context *ctx, SDL_Window *win)
{
struct nk_context *ctx = &sdl.ctx;
if (ctx->input.mouse.grab) {
SDL_SetRelativeMouseMode(SDL_TRUE);
} else if (ctx->input.mouse.ungrab) {
/* better support for older SDL by setting mode first; causes an extra mouse motion event */
SDL_SetRelativeMouseMode(SDL_FALSE);
SDL_WarpMouseInWindow(sdl.win, (int)ctx->input.mouse.prev.x, (int)ctx->input.mouse.prev.y);
SDL_WarpMouseInWindow(win, (int)ctx->input.mouse.prev.x, (int)ctx->input.mouse.prev.y);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As window is now possible to be recreated and is independent from the Nukelar context could it happen that prev mouse input was on prev big window that is outside of new small window? Could Nuklear context aware of old window cause problems if new window is passed?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure. I don't know how the interaction here works exactly but I guess some additional function could be added (for the caller) to adjust the state if a new window object is provided.

} else if (ctx->input.mouse.grabbed) {
ctx->input.mouse.pos.x = ctx->input.mouse.prev.x;
ctx->input.mouse.pos.y = ctx->input.mouse.prev.y;
}
}

NK_API int
nk_sdl_handle_event(SDL_Event *evt)
nk_sdl_handle_event(struct nk_context *ctx, SDL_Event *evt)
{
struct nk_context *ctx = &sdl.ctx;
int ctrl_down = SDL_GetModState() & (KMOD_LCTRL | KMOD_RCTRL);

switch(evt->type)
Expand Down Expand Up @@ -356,11 +349,11 @@ nk_sdl_handle_event(SDL_Event *evt)
}

NK_API
void nk_sdl_shutdown(void)
void nk_sdl_shutdown(struct nk_context *ctx, struct nk_sdl *sdl)
{
struct nk_sdl_device *dev = &sdl.ogl;
nk_font_atlas_clear(&sdl.atlas);
nk_free(&sdl.ctx);
struct nk_sdl_device *dev = &sdl->ogl;
nk_font_atlas_clear(&sdl->atlas);
nk_free(ctx);
glDeleteTextures(1, &dev->font_tex);
nk_buffer_free(&dev->cmds);
memset(&sdl, 0, sizeof(sdl));
Expand Down