From 2816730b2fee205e7302c02d9c31deb5f3e58680 Mon Sep 17 00:00:00 2001 From: LazyBumHorse Date: Fri, 7 Jun 2019 00:36:34 +0200 Subject: [PATCH] make shader presets use relative paths Also change fill_pathname_resolve_relative() to apply path_resolve_realpath() as well --- gfx/video_shader_parse.c | 88 ++++++++++++++---------- gfx/video_shader_parse.h | 7 +- libretro-common/file/file_path.c | 45 +++++++++++- libretro-common/include/file/file_path.h | 19 ++++- menu/menu_shader.c | 6 +- 5 files changed, 122 insertions(+), 43 deletions(-) diff --git a/gfx/video_shader_parse.c b/gfx/video_shader_parse.c index d0b66521e6..9da9b90041 100644 --- a/gfx/video_shader_parse.c +++ b/gfx/video_shader_parse.c @@ -945,16 +945,27 @@ static void shader_write_variable(config_file_t *conf, /** * video_shader_write_conf_cgp: - * @conf : Preset file to read from. + * @conf : Preset file to write to. * @shader : Shader passes handle. + * @preset_path : Optional path to where the preset will be written. * * Saves preset and all associated state (passes, * textures, imports, etc) to disk. + * If @preset_path is not NULL, shader paths are saved + * relative to it. **/ void video_shader_write_conf_cgp(config_file_t *conf, - struct video_shader *shader) + struct video_shader *shader, const char *preset_path) { unsigned i; + char key[64]; + size_t tmp_size = PATH_MAX_LENGTH; + char *tmp = (char*)malloc(tmp_size); + char *tmp_rel = (char*)malloc(tmp_size); + char *tmp_base = (char*)malloc(tmp_size); + + if (!tmp || !tmp_rel || !tmp_base) + return; config_set_int(conf, "shaders", shader->passes); if (shader->feedback_pass >= 0) @@ -962,49 +973,52 @@ void video_shader_write_conf_cgp(config_file_t *conf, for (i = 0; i < shader->passes; i++) { - char key[64]; - size_t tmp_size = PATH_MAX_LENGTH * sizeof(char); - char *tmp = (char*)malloc(tmp_size); const struct video_shader_pass *pass = &shader->pass[i]; - if (tmp) + snprintf(key, sizeof(key), "shader%u", i); + strlcpy(tmp, pass->source.path, tmp_size); + + if (preset_path) { - key[0] = '\0'; + strlcpy(tmp_base, preset_path, tmp_size); - snprintf(key, sizeof(key), "shader%u", i); - strlcpy(tmp, pass->source.path, tmp_size); + path_basedir(tmp_base); + path_relative_to(tmp_rel, tmp, tmp_base, tmp_size); - if (!path_is_absolute(tmp)) - path_resolve_realpath(tmp, tmp_size); - config_set_string(conf, key, tmp); - - free(tmp); - - if (pass->filter != RARCH_FILTER_UNSPEC) - { - snprintf(key, sizeof(key), "filter_linear%u", i); - config_set_bool(conf, key, pass->filter == RARCH_FILTER_LINEAR); - } - - snprintf(key, sizeof(key), "wrap_mode%u", i); - config_set_string(conf, key, wrap_mode_to_str(pass->wrap)); - - if (pass->frame_count_mod) - { - snprintf(key, sizeof(key), "frame_count_mod%u", i); - config_set_int(conf, key, pass->frame_count_mod); - } - - snprintf(key, sizeof(key), "mipmap_input%u", i); - config_set_bool(conf, key, pass->mipmap); - - snprintf(key, sizeof(key), "alias%u", i); - config_set_string(conf, key, pass->alias); - - shader_write_fbo(conf, &pass->fbo, i); + config_set_path(conf, key, tmp_rel); } + else + config_set_path(conf, key, tmp); + + + if (pass->filter != RARCH_FILTER_UNSPEC) + { + snprintf(key, sizeof(key), "filter_linear%u", i); + config_set_bool(conf, key, pass->filter == RARCH_FILTER_LINEAR); + } + + snprintf(key, sizeof(key), "wrap_mode%u", i); + config_set_string(conf, key, wrap_mode_to_str(pass->wrap)); + + if (pass->frame_count_mod) + { + snprintf(key, sizeof(key), "frame_count_mod%u", i); + config_set_int(conf, key, pass->frame_count_mod); + } + + snprintf(key, sizeof(key), "mipmap_input%u", i); + config_set_bool(conf, key, pass->mipmap); + + snprintf(key, sizeof(key), "alias%u", i); + config_set_string(conf, key, pass->alias); + + shader_write_fbo(conf, &pass->fbo, i); } + free(tmp); + free(tmp_rel); + free(tmp_base); + if (shader->num_parameters) { size_t param_size = 4096 * sizeof(char); diff --git a/gfx/video_shader_parse.h b/gfx/video_shader_parse.h index fa17dd23af..4e4800fb16 100644 --- a/gfx/video_shader_parse.h +++ b/gfx/video_shader_parse.h @@ -183,14 +183,17 @@ bool video_shader_read_conf_cgp(config_file_t *conf, /** * video_shader_write_conf_cgp: - * @conf : Preset file to read from. + * @conf : Preset file to write to. * @shader : Shader passes handle. + * @preset_path : Optional path to where the preset will be written. * * Saves preset and all associated state (passes, * textures, imports, etc) to disk. + * If @preset_path is not NULL, shader paths are saved + * relative to it. **/ void video_shader_write_conf_cgp(config_file_t *conf, - struct video_shader *shader); + struct video_shader *shader, const char *preset_path); /** * video_shader_resolve_relative: diff --git a/libretro-common/file/file_path.c b/libretro-common/file/file_path.c index 385887c873..bd774eb474 100644 --- a/libretro-common/file/file_path.c +++ b/libretro-common/file/file_path.c @@ -732,7 +732,8 @@ bool path_is_absolute(const char *path) * @buf : buffer for path * @size : size of buffer * - * Turns relative paths into absolute path. + * Turns relative paths into absolute paths and + * resolves use of "." and ".." in absolute paths. * If relative, rebases on current working dir. **/ void path_resolve_realpath(char *buf, size_t size) @@ -759,6 +760,47 @@ void path_resolve_realpath(char *buf, size_t size) #endif } +/** + * path_relative_to: + * @out : buffer to write the relative path to + * @path : path to be expressed relatively + * @base : base directory to start out on + * @size : size of output buffer + * + * Turns @path into a path relative to @base and writes it to @out. + * + * @base is assumed to be a base directory, i.e. a path ending with '/' or '\'. + * Both @path and @base are assumed to be absolute paths without "." or "..". + * + * E.g. path /a/b/e/f.cg with base /a/b/c/d/ turns into ../../e/f.cg + **/ +void path_relative_to(char *out, const char *path, const char *base, size_t size) +{ + unsigned i; + const char *trimmed_path, *trimmed_base; + +#ifdef _WIN32 + /* For different drives, return absolute path */ + if (strlen(path) > 2 && strlen(base) > 2) + if (path[1] == ':' && base[1] == ':') + if (path[0] != base[0]) + return path; +#endif + + /* Trim common beginning */ + for (i = 0; path[i] && base[i] && path[i] == base[i]; ) + i++; + trimmed_path = path+i; + trimmed_base = base+i; + + /* Each segment of base turns into ".." */ + out[0] = '\0'; + for (i = 0; trimmed_base[i]; i++) + if (trimmed_base[i] == '/' || trimmed_base[i] == '\\') + strlcat(out, "../", size); /* Use '/' as universal separator */ + strlcat(out, trimmed_path, size); +} + /** * fill_pathname_resolve_relative: * @out_path : output path @@ -782,6 +824,7 @@ void fill_pathname_resolve_relative(char *out_path, fill_pathname_basedir(out_path, in_refpath, size); strlcat(out_path, in_path, size); + path_resolve_realpath(out_path, size); } /** diff --git a/libretro-common/include/file/file_path.h b/libretro-common/include/file/file_path.h index 5565fe4648..0dcb7c1c80 100644 --- a/libretro-common/include/file/file_path.h +++ b/libretro-common/include/file/file_path.h @@ -150,11 +150,28 @@ void path_parent_dir(char *path); * @buf : buffer for path * @size : size of buffer * - * Turns relative paths into absolute path. + * Turns relative paths into absolute paths and + * resolves use of "." and ".." in absolute paths. * If relative, rebases on current working dir. **/ void path_resolve_realpath(char *buf, size_t size); +/** + * path_relative_to: + * @out : buffer to write the relative path to + * @path : path to be expressed relatively + * @base : relative to this + * @size : size of output buffer + * + * Turns @path into a path relative to @base and writes it to @out. + * + * @base is assumed to be a base directory, i.e. a path ending with '/' or '\'. + * Both @path and @base are assumed to be absolute paths without "." or "..". + * + * E.g. path /a/b/e/f.cgp with base /a/b/c/d/ turns into ../../e/f.cgp + **/ +void path_relative_to(char *out, const char *path, const char *base, size_t size); + /** * path_is_absolute: * @path : path diff --git a/menu/menu_shader.c b/menu/menu_shader.c index 47e0ebf941..82c946e0f1 100644 --- a/menu/menu_shader.c +++ b/menu/menu_shader.c @@ -316,13 +316,13 @@ bool menu_shader_manager_save_preset( if (!conf) return false; - video_shader_write_conf_cgp(conf, shader); - if (fullpath) { if (!string_is_empty(basename)) strlcpy(preset_path, buffer, sizeof(preset_path)); + video_shader_write_conf_cgp(conf, shader, preset_path); + if (config_file_write(conf, preset_path, false)) { RARCH_LOG("Saved shader preset to %s.\n", preset_path); @@ -343,6 +343,8 @@ bool menu_shader_manager_save_preset( fill_pathname_join(preset_path, dirs[d], buffer, sizeof(preset_path)); + video_shader_write_conf_cgp(conf, shader, preset_path); + if (config_file_write(conf, preset_path, false)) { RARCH_LOG("Saved shader preset to %s.\n", preset_path);