Skip to content

Add SDL3 #779

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 21 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
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
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ demo/*/*/demo
demo/*/bin/*
example/bin/*
docs/xml
docs/build
docs/src
doc/doc*
doc/*
Expand All @@ -14,3 +13,4 @@ doc/*
*.exe
*.dSYM
/private/
build
43 changes: 43 additions & 0 deletions demo/sdl3/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
cmake_minimum_required(VERSION 3.16)
project(nuklear_sdl3
DESCRIPTION "nuklear_sdl3: Nuklear Immediate Mode GUI for SDL3"
HOMEPAGE_URL "https://github.com/Immediate-Mode-UI/Nuklear/"
LANGUAGES C
)

# nuklear
add_library(nuklear INTERFACE)
target_include_directories(nuklear INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/../..)

# nuklear_sdl3
add_library(nuklear_sdl3 INTERFACE)
target_include_directories(nuklear_sdl3 INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})

# Options
if ("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_SOURCE_DIR}")
set(NUKLEAR_SDL3_IS_MAIN TRUE)
else()
set(NUKLEAR_SDL3_IS_MAIN FALSE)
endif()
option(NUKLEAR_SDL3_EXAMPLES "Examples" ${NUKLEAR_SDL3_IS_MAIN})

if (NUKLEAR_SDL3_EXAMPLES)
# CMAKE Modules
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")

find_package(SDL3 REQUIRED)

# nuklear_sdl3_renderer
add_executable(nuklear_sdl3_renderer
nuklear_sdl3_renderer.c
)
target_link_libraries(nuklear_sdl3_renderer PUBLIC
nuklear
nuklear_sdl3
SDL3::SDL3
m # TODO: Remove the math dependency and use nk_floor()
)

# on Visual Studio, set our app as the default project
set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT "nuklear_sdl3_renderer")
endif()
8 changes: 8 additions & 0 deletions demo/sdl3/cmake/FindSDL3.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
include(FetchContent)
FetchContent_Declare(
SDL3
GIT_REPOSITORY https://github.com/libsdl-org/SDL.git
GIT_TAG release-3.2.4
GIT_SHALLOW TRUE
)
FetchContent_MakeAvailable(SDL3)
251 changes: 251 additions & 0 deletions demo/sdl3/nuklear_sdl3_renderer.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,251 @@
/* nuklear - public domain */
#include <stdio.h>
#include <stddef.h> /* offsetof TODO: sdl2_renderer didn't need this header? */

#define SDL_MAIN_USE_CALLBACKS
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>

#define NK_INCLUDE_FIXED_TYPES
#define NK_INCLUDE_STANDARD_IO
#define NK_INCLUDE_STANDARD_VARARGS
#define NK_INCLUDE_DEFAULT_ALLOCATOR
#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT
#define NK_INCLUDE_FONT_BAKING
#define NK_INCLUDE_DEFAULT_FONT
#define NK_IMPLEMENTATION
#define NK_SDL3_RENDERER_IMPLEMENTATION
#define NK_INCLUDE_STANDARD_BOOL
#define NK_INCLUDE_COMMAND_USERDATA
#define NK_MFREE(userdata, ptr) SDL_free(ptr)
#define NK_MALLOC(userdata, old, size) SDL_malloc(size)
#include "nuklear.h"
#include "nuklear_sdl3_renderer.h"

#define WINDOW_WIDTH 1200
#define WINDOW_HEIGHT 800

/* ===============================================================
*
* EXAMPLE
*
* ===============================================================*/
/* This are some code examples to provide a small overview of what can be
* done with this library. To try out an example uncomment the defines */
/*#define INCLUDE_ALL */
/*#define INCLUDE_STYLE */
/*#define INCLUDE_CALCULATOR */
/*#define INCLUDE_CANVAS */
#define INCLUDE_OVERVIEW
/*#define INCLUDE_CONFIGURATOR */
/*#define INCLUDE_NODE_EDITOR */

/*#define INCLUDE_ALL*/

#ifdef INCLUDE_ALL
#define INCLUDE_STYLE
#define INCLUDE_CALCULATOR
#define INCLUDE_CANVAS
#define INCLUDE_OVERVIEW
/* #define INCLUDE_CONFIGURATOR */
#define INCLUDE_NODE_EDITOR
#endif

#ifdef INCLUDE_STYLE
#include "../../demo/common/style.c"
#endif
#ifdef INCLUDE_CALCULATOR
#include "../../demo/common/calculator.c"
#endif
#ifdef INCLUDE_CANVAS
#include "../../demo/common/canvas.c"
#endif
#ifdef INCLUDE_OVERVIEW
#include "../../demo/common/overview.c"
#endif
#ifdef INCLUDE_CONFIGURATOR
#include "../../demo/common/style_configurator.c"
#endif
#ifdef INCLUDE_NODE_EDITOR
#include "../../demo/common/node_editor.c"
#endif

/* ===============================================================
*
* DEMO
*
* ===============================================================*/

typedef struct AppContext {
SDL_Window* window;
SDL_Renderer* renderer;
struct nk_context * ctx;
struct nk_colorf bg;
} AppContext;

SDL_AppResult SDL_Fail(){
SDL_LogError(SDL_LOG_CATEGORY_CUSTOM, "Error %s", SDL_GetError());
return SDL_APP_FAILURE;
}

SDL_AppResult SDL_AppInit(void** appstate, int argc, char* argv[]) {
if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS)) {
return SDL_Fail();
}

AppContext* appContext = (AppContext*)SDL_malloc(sizeof(AppContext));
if (appContext == NULL) {
return SDL_Fail();
}

if (!SDL_CreateWindowAndRenderer("Nuklear: SDL3 Renderer", WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_RESIZABLE, &appContext->window, &appContext->renderer)) {
SDL_free(appContext);
return SDL_Fail();
}

SDL_StartTextInput(appContext->window);

Choose a reason for hiding this comment

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

On desktop platforms, SDL_StartTextInput() is implicitly called on SDL window creation. On some, typically non desktop, platforms this call implicitly enables and shows virtual keyboard.

Copy link

Choose a reason for hiding this comment

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

In SDL3, this needs to be explicitly called on Desktop platforms. I think adding a comment about the behavior of calling this on mobile is probably in order

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hmm, is there a cleaner way we could accomplish this? Perhaps a callback when a textbox on focus/blur?


appContext->bg.r = 0.10f;
appContext->bg.g = 0.18f;
appContext->bg.b = 0.24f;
appContext->bg.a = 1.0f;

*appstate = appContext;

float font_scale = 1;

{
int render_w, render_h;
int window_w, window_h;
float scale_x, scale_y;
SDL_GetCurrentRenderOutputSize(appContext->renderer, &render_w, &render_h);
SDL_GetWindowSize(appContext->window, &window_w, &window_h);
scale_x = (float)(render_w) / (float)(window_w);
scale_y = (float)(render_h) / (float)(window_h);
SDL_SetRenderScale(appContext->renderer, scale_x, scale_y);
font_scale = scale_y;
}

struct nk_context* ctx = nk_sdl_init(appContext->window, appContext->renderer);
appContext->ctx = ctx;

{
struct nk_font_atlas *atlas;
struct nk_font_config config = nk_font_config(0);
struct nk_font *font;

/* set up the font atlas and add desired font; note that font sizes are
* multiplied by font_scale to produce better results at higher DPIs */
atlas = nk_sdl_font_stash_begin(ctx);
font = nk_font_atlas_add_default(atlas, 13 * font_scale, &config);
/*font = nk_font_atlas_add_from_file(atlas, "../../../extra_font/DroidSans.ttf", 14 * font_scale, &config);*/
/*font = nk_font_atlas_add_from_file(atlas, "../../../extra_font/Roboto-Regular.ttf", 16 * font_scale, &config);*/
/*font = nk_font_atlas_add_from_file(atlas, "../../../extra_font/kenvector_future_thin.ttf", 13 * font_scale, &config);*/
/*font = nk_font_atlas_add_from_file(atlas, "../../../extra_font/ProggyClean.ttf", 12 * font_scale, &config);*/
/*font = nk_font_atlas_add_from_file(atlas, "../../../extra_font/ProggyTiny.ttf", 10 * font_scale, &config);*/
/*font = nk_font_atlas_add_from_file(atlas, "../../../extra_font/Cousine-Regular.ttf", 13 * font_scale, &config);*/
nk_sdl_font_stash_end(ctx);

/* this hack makes the font appear to be scaled down to the desired
* size and is only necessary when font_scale > 1 */
font->handle.height /= font_scale;
/*nk_style_load_all_cursors(ctx, atlas->cursors);*/
nk_style_set_font(ctx, &font->handle);
}

return SDL_APP_CONTINUE;
}

SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event* event) {
AppContext* app = (AppContext*)appstate;

switch (event->type) {
case SDL_EVENT_QUIT:
return SDL_APP_SUCCESS;
}

nk_sdl_handle_event(app->ctx, event);

return SDL_APP_CONTINUE;
}

SDL_AppResult SDL_AppIterate(void *appstate) {
AppContext* app = (AppContext*)appstate;
struct nk_context* ctx = app->ctx;
nk_input_end(ctx);

/* GUI */
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"))
printf("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, 1000, 1, 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(app->bg), nk_vec2(nk_widget_width(ctx),400))) {
nk_layout_row_dynamic(ctx, 120, 1);
app->bg = nk_color_picker(ctx, app->bg, NK_RGBA);
nk_layout_row_dynamic(ctx, 25, 1);
app->bg.r = nk_propertyf(ctx, "#R:", 0, app->bg.r, 1.0f, 0.01f,0.005f);
app->bg.g = nk_propertyf(ctx, "#G:", 0, app->bg.g, 1.0f, 0.01f,0.005f);
app->bg.b = nk_propertyf(ctx, "#B:", 0, app->bg.b, 1.0f, 0.01f,0.005f);
app->bg.a = nk_propertyf(ctx, "#A:", 0, app->bg.a, 1.0f, 0.01f,0.005f);
nk_combo_end(ctx);
}
}
nk_end(ctx);

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

SDL_SetRenderDrawColor(app->renderer, 255, 0, 255, SDL_ALPHA_OPAQUE);
SDL_RenderClear(app->renderer);

nk_sdl_render(ctx, NK_ANTI_ALIASING_ON);

SDL_RenderPresent(app->renderer);

nk_input_begin(ctx);
return SDL_APP_CONTINUE;
}

void SDL_AppQuit(void* appstate, SDL_AppResult result) {
AppContext* app = (AppContext*)appstate;

if (app) {
nk_sdl_shutdown(app->ctx);
SDL_DestroyRenderer(app->renderer);
SDL_DestroyWindow(app->window);
SDL_free(app);
}

SDL_Quit();
}
Loading
Loading