aboutsummaryrefslogtreecommitdiff
path: root/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'main.c')
-rw-r--r--main.c395
1 files changed, 395 insertions, 0 deletions
diff --git a/main.c b/main.c
new file mode 100644
index 0000000..2a37839
--- /dev/null
+++ b/main.c
@@ -0,0 +1,395 @@
+/* nuklear - public domain */
+#include <SDL3/SDL_render.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdarg.h>
+#include <string.h>
+#include <math.h>
+#include <assert.h>
+#include <limits.h>
+#include <time.h>
+
+#include <SDL3/SDL.h>
+#include <SDL3_image/SDL_image.h>
+
+/* This demo uses "main callbacks" which are new in SDL3
+ * Those provide highly portable entry point and event loop for the app
+ * see: https://wiki.libsdl.org/SDL3/README-main-functions
+ * */
+#define SDL_MAIN_USE_CALLBACKS
+#include <SDL3/SDL_main.h>
+
+#include "./camera.c"
+
+/* ===============================================================
+ *
+ * CONFIG
+ *
+ * ===============================================================*/
+
+/* optional: sdl3_renderer does not need any of these defines
+ * (but some examples might need them, so be careful) */
+#define NK_INCLUDE_STANDARD_VARARGS
+#define NK_INCLUDE_STANDARD_IO
+
+/* note that sdl3_renderer comes with nk_sdl_style_set_debug_font()
+ * so you may wish to use that instead of font baking */
+#define NK_INCLUDE_FONT_BAKING
+#define NK_INCLUDE_DEFAULT_FONT
+
+/* note that sdl3_renderer comes with nk_sdl_allocator()
+ * and you probably want to use that allocator instead of the default ones */
+/*#define NK_INCLUDE_DEFAULT_ALLOCATOR*/
+
+/* mandatory: sdl3_renderer depends on those defines */
+#define NK_INCLUDE_COMMAND_USERDATA
+#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT
+
+
+/* We can re-use the types provided by SDL which are extremely portable,
+ * so there is no need for Nuklear to detect those on its own */
+/*#define NK_INCLUDE_FIXED_TYPES*/
+#ifndef NK_INCLUDE_FIXED_TYPES
+ #define NK_INT8 Sint8
+ #define NK_UINT8 Uint8
+ #define NK_INT16 Sint16
+ #define NK_UINT16 Uint16
+ #define NK_INT32 Sint32
+ #define NK_UINT32 Uint32
+ /* SDL guarantees 'uintptr_t' typedef */
+ #define NK_SIZE_TYPE uintptr_t
+ #define NK_POINTER_TYPE uintptr_t
+#endif
+
+/* We can reuse the `bool` symbol because SDL3 guarantees its existence */
+/*#define NK_INCLUDE_STANDARD_BOOL*/
+#ifndef NK_INCLUDE_STANDARD_BOOL
+ #define NK_BOOL bool
+#endif
+
+/* We can re-use various portable libc functions provided by SDL */
+#define NK_ASSERT(condition) SDL_assert(condition)
+#define NK_STATIC_ASSERT(exp) SDL_COMPILE_TIME_ASSERT(, exp)
+#define NK_MEMSET(dst, c, len) SDL_memset(dst, c, len)
+#define NK_MEMCPY(dst, src, len) SDL_memcpy(dst, src, len)
+#define NK_VSNPRINTF(s, n, f, a) SDL_vsnprintf(s, n, f, a)
+#define NK_STRTOD(str, endptr) SDL_strtod(str, endptr)
+
+/* SDL3 does not provide "dtoa" (only integer versions)
+ * but we can emulate it with SDL_snprintf */
+static char* nk_sdl_dtoa(char *str, double d);
+#define NK_DTOA(str, d) nk_sdl_dtoa(str, d)
+
+/* SDL can also provide us with math functions, but beware that Nuklear's own
+ * implementation can be slightly faster at the cost of some precision */
+#define NK_INV_SQRT(f) (1.0f / SDL_sqrtf(f))
+#define NK_SIN(f) SDL_sinf(f)
+#define NK_COS(f) SDL_cosf(f)
+
+/* HACK: Nuklear pulls two stb libraries in order to use font baking
+ * those libraries pull in some libc headers internally, creating a linkage dependency,
+ * so you’ll most likely want to use SDL symbols instead */
+#define STBTT_ifloor(x) ((int)SDL_floor(x))
+#define STBTT_iceil(x) ((int)SDL_ceil(x))
+#define STBTT_sqrt(x) SDL_sqrt(x)
+#define STBTT_pow(x,y) SDL_pow(x,y)
+#define STBTT_fmod(x,y) SDL_fmod(x,y)
+#define STBTT_cos(x) SDL_cosf(x)
+#define STBTT_acos(x) SDL_acos(x)
+#define STBTT_fabs(x) SDL_fabs(x)
+#define STBTT_assert(x) SDL_assert(x)
+#define STBTT_strlen(x) SDL_strlen(x)
+#define STBTT_memcpy SDL_memcpy
+#define STBTT_memset SDL_memset
+#define stbtt_uint8 Uint8
+#define stbtt_int8 Sint8
+#define stbtt_uint16 Uint16
+#define stbtt_int16 Sint16
+#define stbtt_uint32 Uint32
+#define stbtt_int32 Sint32
+#define STBRP_SORT SDL_qsort
+#define STBRP_ASSERT SDL_assert
+/* There is no need to define STBTT_malloc/STBTT_free macros
+ * Nuklear will define those to user-provided nk_allocator */
+
+
+#define NK_IMPLEMENTATION
+#include "../nuklear/nuklear.h"
+#define NK_SDL3_RENDERER_IMPLEMENTATION
+#include "nuklear_sdl3_renderer.h"
+
+#define WINDOW_WIDTH 1200
+#define WINDOW_HEIGHT 800
+
+/* ===============================================================
+ *
+ * DEMO
+ *
+ * ===============================================================*/
+
+struct nk_sdl_app {
+ SDL_Window* window;
+ SDL_Renderer* renderer;
+ struct nk_context * ctx;
+ struct nk_colorf bg;
+ enum nk_anti_aliasing AA;
+ camera_t* camera;
+};
+
+static SDL_AppResult
+nk_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[])
+{
+ struct nk_sdl_app* app;
+ struct nk_context* ctx;
+ camera_t * camera;
+ float font_scale;
+ NK_UNUSED(argc);
+ NK_UNUSED(argv);
+
+ if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS)) {
+ return nk_sdl_fail();
+ }
+
+ app = SDL_malloc(sizeof(*app));
+ if (app == NULL) {
+ return nk_sdl_fail();
+ }
+
+ app->camera = malloc(sizeof(*camera));
+ app->camera->latest_frame = NULL;
+ get_camera_devices(app->camera);
+
+ if (!SDL_CreateWindowAndRenderer("Nuklear: SDL3 Renderer", WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_RESIZABLE, &app->window, &app->renderer)) {
+ SDL_free(app);
+ return nk_sdl_fail();
+ }
+ *appstate = app;
+
+ if (!SDL_SetRenderVSync(app->renderer, 1)) {
+ SDL_LogError(SDL_LOG_CATEGORY_CUSTOM, "SDL_SetRenderVSync failed: %s", SDL_GetError());
+ }
+
+ app->bg.r = 0.10f;
+ app->bg.g = 0.18f;
+ app->bg.b = 0.24f;
+ app->bg.a = 1.0f;
+
+ font_scale = 1;
+ {
+ /* This scaling logic was kept simple for the demo purpose.
+ * On some platforms, this might not be the exact scale
+ * that you want to use. For more information, see:
+ * https://wiki.libsdl.org/SDL3/README-highdpi */
+ const float scale = SDL_GetWindowDisplayScale(app->window);
+ SDL_SetRenderScale(app->renderer, scale, scale);
+ font_scale = scale;
+ }
+
+ ctx = nk_sdl_init(app->window, app->renderer, nk_sdl_allocator());
+ app->ctx = ctx;
+
+#if 0
+ {
+ /* If you don't want to use advanced Nuklear font baking API
+ * you can use simple ASCII debug font provided by SDL
+ * just change the `#if 0` above to `#if 1` */
+ nk_sdl_style_set_debug_font(ctx);
+
+ /* Note that since debug font is extremely small (only 8x8 pixels),
+ * scaling it does not make much sense. The font would appear blurry. */
+ NK_UNUSED(font_scale);
+
+ /* You may wish to change a few style options, here are few recommendations: */
+ ctx->style.button.rounding = 0.0f;
+ ctx->style.menu_button.rounding = 0.0f;
+ ctx->style.property.rounding = 0.0f;
+ ctx->style.property.border = 0.0f;
+ ctx->style.option.border = -1.0f;
+ ctx->style.checkbox.border = -1.0f;
+ ctx->style.property.dec_button.border = -2.0f;
+ ctx->style.property.inc_button.border = -2.0f;
+ ctx->style.tab.tab_minimize_button.border = -2.0f;
+ ctx->style.tab.tab_maximize_button.border = -2.0f;
+ ctx->style.tab.node_minimize_button.border = -2.0f;
+ ctx->style.tab.node_maximize_button.border = -2.0f;
+ ctx->style.checkbox.spacing = 5.0f;
+
+ /* It's better to disable anti-aliasing when using small fonts */
+ app->AA = NK_ANTI_ALIASING_OFF;
+ }
+#else
+ {
+ 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, 16 * 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);
+
+ app->AA = NK_ANTI_ALIASING_ON;
+ }
+#endif
+
+ nk_input_begin(ctx);
+
+ return SDL_APP_CONTINUE;
+}
+
+SDL_AppResult
+SDL_AppEvent(void *appstate, SDL_Event* event)
+{
+ struct nk_sdl_app* app = (struct nk_sdl_app*)appstate;
+
+ switch (event->type) {
+ case SDL_EVENT_QUIT:
+ return SDL_APP_SUCCESS;
+ case SDL_EVENT_WINDOW_DISPLAY_SCALE_CHANGED:
+ /* You may wish to rescale the renderer and Nuklear during this event.
+ * Without this the UI and Font could appear too small or too big.
+ * This is not handled by the demo in order to keep it simple,
+ * but you may wish to re-bake the Font whenever this happens. */
+ SDL_Log("Unhandled scale event! Nuklear may appear blurry");
+ return SDL_APP_CONTINUE;
+ }
+
+ /* Remember to always rescale the event coordinates,
+ * if your renderer uses custom scale. */
+ SDL_ConvertEventToRenderCoordinates(app->renderer, event);
+
+ nk_sdl_handle_event(app->ctx, event);
+
+ return SDL_APP_CONTINUE;
+}
+
+SDL_AppResult
+SDL_AppIterate(void *appstate)
+{
+ struct nk_sdl_app* app = (struct nk_sdl_app*)appstate;
+ struct nk_context* ctx = app->ctx;
+ int wwidth = 0;
+ int wheight = 0;
+ static char text[9][64];
+ static int text_len[9];
+ SDL_GetWindowSizeInPixels(app->window, &wwidth, &wheight);
+
+ nk_input_end(ctx);
+
+ /* GUI */
+ if (nk_begin(ctx, "Recent", nk_rect(0, 0, 300, wheight),
+ NK_WINDOW_TITLE|NK_TEXT_CENTERED))
+ {
+
+ }
+ nk_end(ctx);
+
+ /* GUI */
+ if (nk_begin(ctx, "Main", nk_rect(300, 0, wwidth-200-300, wheight),
+ NK_WINDOW_BORDER))
+ {
+ nk_layout_row_dynamic(ctx, 30, 2);
+ nk_label(ctx, "Loaf Key", 0);
+ nk_edit_string(ctx, NK_EDIT_SIMPLE, text[0], &text_len[0], 64, nk_filter_default);
+ if(nk_button_label(ctx, "Action!")) {
+ start_camera_stream(app->camera);
+ }
+ if(nk_button_label(ctx, "Cut!")) {
+ stop_camera_stream(app->camera);
+ }
+ nk_spacer(ctx);
+ nk_spacer(ctx);
+ }
+
+ if (nk_begin(ctx, "Main", nk_rect(300, 0, wwidth-200-300, wheight),
+ NK_WINDOW_BORDER))
+ {
+ if (app->camera->latest_frame != NULL && app->camera->latest_frame->data_bytes > 0) {
+ const uvc_frame_t * frame = app->camera->latest_frame;
+ printf("Texture WxH: %dx%d, Bytes: %zd\n", frame->width, frame->height, frame->data_bytes);
+ SDL_Texture * texture = SDL_CreateTexture(app->renderer, SDL_PIXELFORMAT_MJPG, SDL_TEXTUREACCESS_STREAMING, frame->width, frame->height);
+ if (texture == NULL) {
+ puts("ERROR Creating Texture!");
+ const char * err = SDL_GetError();
+ puts(err);
+ puts("---");
+ }
+ bool upres = SDL_UpdateTexture(texture, NULL, frame->data, frame->data_bytes);
+ if (!upres) {
+ puts("Failed to add frame to Texture");
+ const char * err = SDL_GetError();
+ puts(err);
+ puts("---");
+ }
+
+ struct nk_image camera_image;
+ camera_image = nk_image_ptr(texture);
+ struct nk_command_buffer * canvas = nk_window_get_canvas(ctx);
+ struct nk_rect total_space = nk_window_get_content_region(ctx);
+ const struct nk_color grid_color = nk_rgba(255, 255, 255, 255);
+ nk_draw_image(canvas, total_space, &camera_image, grid_color);
+ }
+ }
+ nk_end(ctx);
+
+ SDL_SetRenderDrawColorFloat(app->renderer, app->bg.r, app->bg.g, app->bg.b, app->bg.a);
+ SDL_RenderClear(app->renderer);
+
+ nk_sdl_render(ctx, app->AA);
+ nk_sdl_update_TextInput(ctx);
+
+ /* show if TextInput is active for debug purpose. Feel free to remove this. */
+ SDL_SetRenderDrawColor(app->renderer, 0xFF, 0xFF, 0xFF, 0xFF);
+ // SDL_RenderDebugTextFormat(app->renderer, 10, 10, "APP WINDOW W:%d, H:%d", wwidth, wheight);
+ SDL_RenderPresent(app->renderer);
+
+ nk_input_begin(ctx);
+ return SDL_APP_CONTINUE;
+}
+
+void
+SDL_AppQuit(void* appstate, SDL_AppResult result)
+{
+ struct nk_sdl_app* app = (struct nk_sdl_app*)appstate;
+ NK_UNUSED(result);
+
+ if (app) {
+ close_camera(app->camera);
+ nk_input_end(app->ctx);
+ nk_sdl_shutdown(app->ctx);
+ SDL_DestroyRenderer(app->renderer);
+ SDL_DestroyWindow(app->window);
+ SDL_free(app);
+ }
+}
+
+static char*
+nk_sdl_dtoa(char *str, double d)
+{
+ NK_ASSERT(str);
+ if (!str) return NULL;
+ (void)SDL_snprintf(str, 99999, "%.17g", d);
+ return str;
+}
+