# HG changeset patch # User Michael Pavone # Date 1512198967 28800 # Node ID bdeb2a1d0385bd1499165f2a55c1abe3db032c34 # Parent e890971f37579b381a26a536f113973c60054d56 Add shader selector to video settings diff -r e890971f3757 -r bdeb2a1d0385 nuklear_ui/blastem_nuklear.c --- a/nuklear_ui/blastem_nuklear.c Fri Dec 01 09:22:43 2017 -0800 +++ b/nuklear_ui/blastem_nuklear.c Fri Dec 01 23:16:07 2017 -0800 @@ -276,8 +276,114 @@ } } +typedef struct { + char *fragment; + char *vertex; +} shader_prog; + +shader_prog *get_shader_progs(dir_entry *entries, size_t num_entries, shader_prog *progs, uint32_t *num_existing, uint32_t *storage) +{ + uint32_t num_progs = *num_existing; + uint32_t prog_storage = *storage; + uint32_t starting = num_progs; + + for (uint32_t i = 0; i < num_entries; i++) { + if (entries[i].is_dir) { + continue; + } + char *no_ext = basename_no_extension(entries[i].name); + uint32_t len = strlen(no_ext); + if (no_ext[len-1] == 'f' && no_ext[len-2] == '.') { + uint8_t dupe = 0;; + for (uint32_t j = 0; j < starting; j++) { + if (!strcmp(entries[i].name, progs[j].fragment)) { + dupe = 1; + break; + } + } + if (!dupe) { + if (num_progs == prog_storage) { + prog_storage *= 2; + progs = realloc(progs, sizeof(progs) * prog_storage); + } + progs[num_progs].vertex = NULL; + progs[num_progs++].fragment = strdup(entries[i].name); + } + } + free(no_ext); + } + + for (uint32_t i = 0; i < num_entries; i++) { + if (entries[i].is_dir) { + continue; + } + char *no_ext = basename_no_extension(entries[i].name); + uint32_t len = strlen(no_ext); + if (no_ext[len-1] == 'v' && no_ext[len-2] == '.') { + for (uint32_t j = 0; j < num_progs; j++) { + if (!strncmp(no_ext, progs[j].fragment, len-1) && progs[j].fragment[len-1] == 'f' && progs[j].fragment[len] == '.') { + progs[j].vertex = strdup(entries[i].name); + } + } + } + free(no_ext); + } + free_dir_list(entries, num_entries); + *num_existing = num_progs; + *storage = prog_storage; + return progs; +} + +shader_prog *get_shader_list(uint32_t *num_out) +{ + char *shader_dir = path_append(get_config_dir(), "shaders"); + size_t num_entries; + dir_entry *entries = get_dir_list(shader_dir, &num_entries); + free(shader_dir); + shader_prog *progs; + uint32_t num_progs = 0, prog_storage; + if (num_entries) { + progs = calloc(num_entries, sizeof(shader_prog)); + prog_storage = num_entries; + progs = get_shader_progs(entries, num_entries, progs, &num_progs, &prog_storage); + } else { + progs = NULL; + prog_storage = 0; + } + shader_dir = path_append(get_exe_dir(), "shaders"); + entries = get_dir_list(shader_dir, &num_entries); + progs = get_shader_progs(entries, num_entries, progs, &num_progs, &prog_storage); + *num_out = num_progs; + return progs; +} + void view_video_settings(struct nk_context *context) { + static shader_prog *progs; + static char **prog_names; + static uint32_t num_progs; + static uint32_t selected_prog; + if(!progs) { + progs = get_shader_list(&num_progs); + prog_names = calloc(num_progs, sizeof(char*)); + for (uint32_t i = 0; i < num_progs; i++) + { + prog_names[i] = basename_no_extension(progs[i].fragment);; + uint32_t len = strlen(prog_names[i]); + if (len > 2) { + prog_names[i][len-2] = 0; + } + if (!progs[i].vertex) { + progs[i].vertex = strdup("default.v.glsl"); + } + if (!strcmp( + progs[i].fragment, + tern_find_path_default(config, "video\0fragment_shader\0", (tern_val){.ptrval = "default.f.glsl"}, TVAL_PTR).ptrval + )) { + selected_prog = i; + } + } + } uint32_t width = render_width(); uint32_t height = render_height(); if (nk_begin(context, "Video Settings", nk_rect(0, 0, width, height), 0)) { @@ -286,6 +392,13 @@ settings_toggle(context, "Open GL", "video\0gl\0", 1); settings_toggle(context, "Scanlines", "video\0scanlines\0", 0); settings_int_input(context, "Windowed Width", "video\0width\0", "640"); + nk_label(context, "Shader", NK_TEXT_LEFT); + uint32_t next_selected = nk_combo(context, (const char **)prog_names, num_progs, selected_prog, 30, nk_vec2(300, 300)); + if (next_selected != selected_prog) { + selected_prog = next_selected; + config = tern_insert_path(config, "video\0fragment_shader\0", (tern_val){.ptrval = strdup(progs[next_selected].fragment)}, TVAL_PTR); + config = tern_insert_path(config, "video\0vertex_shader\0", (tern_val){.ptrval = strdup(progs[next_selected].vertex)}, TVAL_PTR); + } settings_int_property(context, "NTSC Overscan", "Top", "video\0ntsc\0overscan\0top\0", 2, 0, 32); settings_int_property(context, "", "Bottom", "video\0ntsc\0overscan\0bottom\0", 17, 0, 32); settings_int_property(context, "", "Left", "video\0ntsc\0overscan\0left\0", 13, 0, 32); @@ -294,6 +407,7 @@ settings_int_property(context, "", "Bottom", "video\0pal\0overscan\0bottom\0", 17, 0, 32); settings_int_property(context, "", "Left", "video\0pal\0overscan\0left\0", 13, 0, 32); settings_int_property(context, "", "Right", "video\0pal\0overscan\0right\0", 14, 0, 32); + if (nk_button_label(context, "Back")) { pop_view(); }