fix [#33108] Running save_as_mainfile breaks relative texture paths
save-as with path remapping left the paths relate to the file written.
This commit is contained in:
@@ -167,6 +167,9 @@ enum {
|
||||
#define G_FILE_RELATIVE_REMAP (1 << 24)
|
||||
#define G_FILE_HISTORY (1 << 25)
|
||||
#define G_FILE_MESH_COMPAT (1 << 26) /* BMesh option to save as older mesh format */
|
||||
#define G_FILE_SAVE_COPY (1 << 27) /* restore paths after editing them */
|
||||
|
||||
#define G_FILE_FLAGS_RUNTIME (G_FILE_NO_UI | G_FILE_RELATIVE_REMAP | G_FILE_MESH_COMPAT | G_FILE_SAVE_COPY)
|
||||
|
||||
/* G.windowstate */
|
||||
#define G_WINDOWSTATE_USERDEF 0
|
||||
|
@@ -32,7 +32,11 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* currently unused but we may want to add macros here for BKE later */
|
||||
#define BKE_BIT_TEST_SET(value, test, flag) \
|
||||
{ \
|
||||
if (test) (value) |= flag; \
|
||||
else (value) &= ~flag; \
|
||||
} (void)0
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@@ -48,6 +48,11 @@ void BLI_bpath_traverse_id_list(struct Main *bmain, struct ListBase *lb, BPathVi
|
||||
void BLI_bpath_traverse_main(struct Main *bmain, BPathVisitor visit_cb, const int flag, void *userdata);
|
||||
int BLI_bpath_relocate_visitor(void *oldbasepath, char *path_dst, const char *path_src);
|
||||
|
||||
/* Functions for temp backup/restore of paths, path count must NOT change */
|
||||
void *BLI_bpath_list_backup(struct Main *bmain, const int flag);
|
||||
void BLI_bpath_list_restore(struct Main *bmain, const int flag, void *ls_handle);
|
||||
void BLI_bpath_list_free(void *ls_handle);
|
||||
|
||||
#define BLI_BPATH_TRAVERSE_ABS (1 << 0) /* convert paths to absolute */
|
||||
#define BLI_BPATH_TRAVERSE_SKIP_LIBRARY (1 << 2) /* skip library paths */
|
||||
#define BLI_BPATH_TRAVERSE_SKIP_PACKED (1 << 3) /* skip packed data */
|
||||
|
@@ -618,3 +618,73 @@ int BLI_bpath_relocate_visitor(void *pathbase_v, char *path_dst, const char *pat
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/**
|
||||
* Backup/Restore/Free functions,
|
||||
* \note These functions assume the data won't chane order.
|
||||
*/
|
||||
|
||||
struct PathStore {
|
||||
struct PathStore *next, *prev;
|
||||
} PathStore;
|
||||
|
||||
static int bpath_list_append(void *userdata, char *UNUSED(path_dst), const char *path_src)
|
||||
{
|
||||
/* store the path and string in a single alloc */
|
||||
ListBase *ls = userdata;
|
||||
size_t path_size = strlen(path_src) + 1;
|
||||
struct PathStore *path_store = MEM_mallocN(sizeof(PathStore) + path_size, __func__);
|
||||
char *filepath = (char *)(path_store + 1);
|
||||
|
||||
memcpy(filepath, path_src, path_size);
|
||||
BLI_addtail(ls, path_store);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static int bpath_list_restore(void *userdata, char *path_dst, const char *path_src)
|
||||
{
|
||||
/* assume ls->first wont be NULL because the number of paths can't change!
|
||||
* (if they do caller is wrong) */
|
||||
ListBase *ls = userdata;
|
||||
struct PathStore *path_store = ls->first;
|
||||
const char *filepath = (char *)(path_store + 1);
|
||||
int ret;
|
||||
|
||||
if (strcmp(path_src, filepath) == 0) {
|
||||
ret = FALSE;
|
||||
}
|
||||
else {
|
||||
BLI_strncpy(path_dst, filepath, FILE_MAX);
|
||||
ret = TRUE;
|
||||
}
|
||||
|
||||
BLI_freelinkN(ls, path_store);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* return ls_handle */
|
||||
void *BLI_bpath_list_backup(Main *bmain, const int flag)
|
||||
{
|
||||
ListBase *ls = MEM_callocN(sizeof(ListBase), __func__);
|
||||
|
||||
BLI_bpath_traverse_main(bmain, bpath_list_append, flag, ls);
|
||||
|
||||
return ls;
|
||||
}
|
||||
|
||||
void BLI_bpath_list_restore(Main *bmain, const int flag, void *ls_handle)
|
||||
{
|
||||
ListBase *ls = ls_handle;
|
||||
|
||||
BLI_bpath_traverse_main(bmain, bpath_list_restore, flag, ls);
|
||||
}
|
||||
|
||||
void BLI_bpath_list_free(void *ls_handle)
|
||||
{
|
||||
ListBase *ls = ls_handle;
|
||||
BLI_assert(ls->first == NULL); /* assumes we were used */
|
||||
BLI_freelistN(ls);
|
||||
MEM_freeN(ls);
|
||||
}
|
||||
|
@@ -2890,7 +2890,7 @@ static void write_global(WriteData *wd, int fileflags, Main *mainvar)
|
||||
fg.winpos= G.winpos;
|
||||
|
||||
/* prevent to save this, is not good convention, and feature with concerns... */
|
||||
fg.fileflags= (fileflags & ~(G_FILE_NO_UI|G_FILE_RELATIVE_REMAP|G_FILE_MESH_COMPAT));
|
||||
fg.fileflags= (fileflags & ~G_FILE_FLAGS_RUNTIME);
|
||||
|
||||
fg.globalf= G.f;
|
||||
BLI_strncpy(fg.filename, mainvar->name, sizeof(fg.filename));
|
||||
@@ -3039,6 +3039,10 @@ int BLO_write_file(Main *mainvar, const char *filepath, int write_flags, ReportL
|
||||
char tempname[FILE_MAX+1];
|
||||
int file, err, write_user_block;
|
||||
|
||||
/* path backup/restore */
|
||||
void *path_list_backup = NULL;
|
||||
const int path_list_flag = (BLI_BPATH_TRAVERSE_SKIP_LIBRARY | BLI_BPATH_TRAVERSE_SKIP_MULTIFILE);
|
||||
|
||||
/* open temporary file, so we preserve the original in case we crash */
|
||||
BLI_snprintf(tempname, sizeof(tempname), "%s@", filepath);
|
||||
|
||||
@@ -3048,6 +3052,11 @@ int BLO_write_file(Main *mainvar, const char *filepath, int write_flags, ReportL
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* check if we need to backup and restore paths */
|
||||
if (UNLIKELY((write_flags & G_FILE_RELATIVE_REMAP) && (G_FILE_SAVE_COPY & write_flags))) {
|
||||
path_list_backup = BLI_bpath_list_backup(mainvar, path_list_flag);
|
||||
}
|
||||
|
||||
/* remapping of relative paths to new file location */
|
||||
if (write_flags & G_FILE_RELATIVE_REMAP) {
|
||||
char dir1[FILE_MAX];
|
||||
@@ -3083,6 +3092,11 @@ int BLO_write_file(Main *mainvar, const char *filepath, int write_flags, ReportL
|
||||
err= write_file_handle(mainvar, file, NULL, NULL, write_user_block, write_flags, thumb);
|
||||
close(file);
|
||||
|
||||
if (UNLIKELY(path_list_backup)) {
|
||||
BLI_bpath_list_restore(mainvar, path_list_flag, path_list_backup);
|
||||
BLI_bpath_list_free(path_list_backup);
|
||||
}
|
||||
|
||||
if (err) {
|
||||
BKE_report(reports, RPT_ERROR, strerror(errno));
|
||||
remove(tempname);
|
||||
|
@@ -106,7 +106,7 @@ int WM_homefile_read_exec(struct bContext *C, struct wmOperator *op);
|
||||
int WM_homefile_read(struct bContext *C, struct ReportList *reports, short from_memory);
|
||||
int WM_homefile_write_exec(struct bContext *C, struct wmOperator *op);
|
||||
void WM_file_read(struct bContext *C, const char *filepath, struct ReportList *reports);
|
||||
int WM_file_write(struct bContext *C, const char *target, int fileflags, struct ReportList *reports, int copy);
|
||||
int WM_file_write(struct bContext *C, const char *target, int fileflags, struct ReportList *reports);
|
||||
void WM_autosave_init(struct wmWindowManager *wm);
|
||||
|
||||
/* mouse cursors */
|
||||
|
@@ -762,7 +762,7 @@ int write_crash_blend(void)
|
||||
}
|
||||
}
|
||||
|
||||
int WM_file_write(bContext *C, const char *target, int fileflags, ReportList *reports, int copy)
|
||||
int WM_file_write(bContext *C, const char *target, int fileflags, ReportList *reports)
|
||||
{
|
||||
Library *li;
|
||||
int len;
|
||||
@@ -818,7 +818,7 @@ int WM_file_write(bContext *C, const char *target, int fileflags, ReportList *re
|
||||
fileflags |= G_FILE_HISTORY; /* write file history */
|
||||
|
||||
if (BLO_write_file(CTX_data_main(C), filepath, fileflags, reports, thumb)) {
|
||||
if (!copy) {
|
||||
if (!(fileflags & G_FILE_SAVE_COPY)) {
|
||||
G.relbase_valid = 1;
|
||||
BLI_strncpy(G.main->name, filepath, sizeof(G.main->name)); /* is guaranteed current file */
|
||||
|
||||
|
@@ -72,6 +72,7 @@
|
||||
#include "BKE_report.h"
|
||||
#include "BKE_scene.h"
|
||||
#include "BKE_screen.h" /* BKE_ST_MAXNAME */
|
||||
#include "BKE_utildefines.h"
|
||||
|
||||
#include "BKE_idcode.h"
|
||||
|
||||
@@ -2077,7 +2078,6 @@ static int wm_save_as_mainfile_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
char path[FILE_MAX];
|
||||
int fileflags;
|
||||
int copy = 0;
|
||||
|
||||
save_set_compress(op);
|
||||
|
||||
@@ -2087,29 +2087,27 @@ static int wm_save_as_mainfile_exec(bContext *C, wmOperator *op)
|
||||
BLI_strncpy(path, G.main->name, FILE_MAX);
|
||||
untitled(path);
|
||||
}
|
||||
|
||||
if (RNA_struct_property_is_set(op->ptr, "copy"))
|
||||
copy = RNA_boolean_get(op->ptr, "copy");
|
||||
|
||||
fileflags = G.fileflags;
|
||||
|
||||
/* set compression flag */
|
||||
if (RNA_boolean_get(op->ptr, "compress")) fileflags |= G_FILE_COMPRESS;
|
||||
else fileflags &= ~G_FILE_COMPRESS;
|
||||
if (RNA_boolean_get(op->ptr, "relative_remap")) fileflags |= G_FILE_RELATIVE_REMAP;
|
||||
else fileflags &= ~G_FILE_RELATIVE_REMAP;
|
||||
BKE_BIT_TEST_SET(fileflags, RNA_boolean_get(op->ptr, "compress"),
|
||||
G_FILE_COMPRESS);
|
||||
BKE_BIT_TEST_SET(fileflags, RNA_boolean_get(op->ptr, "relative_remap"),
|
||||
G_FILE_RELATIVE_REMAP);
|
||||
BKE_BIT_TEST_SET(fileflags,
|
||||
(RNA_struct_property_is_set(op->ptr, "copy") &&
|
||||
RNA_boolean_get(op->ptr, "copy")),
|
||||
G_FILE_SAVE_COPY);
|
||||
|
||||
#ifdef USE_BMESH_SAVE_AS_COMPAT
|
||||
/* property only exists for 'Save As' */
|
||||
if (RNA_struct_find_property(op->ptr, "use_mesh_compat")) {
|
||||
if (RNA_boolean_get(op->ptr, "use_mesh_compat")) fileflags |= G_FILE_MESH_COMPAT;
|
||||
else fileflags &= ~G_FILE_MESH_COMPAT;
|
||||
}
|
||||
else {
|
||||
fileflags &= ~G_FILE_MESH_COMPAT;
|
||||
}
|
||||
BKE_BIT_TEST_SET(fileflags,
|
||||
(RNA_struct_find_property(op->ptr, "use_mesh_compat") &&
|
||||
RNA_boolean_get(op->ptr, "use_mesh_compat")),
|
||||
G_FILE_MESH_COMPAT);
|
||||
#endif
|
||||
|
||||
if (WM_file_write(C, path, fileflags, op->reports, copy) != 0)
|
||||
if (WM_file_write(C, path, fileflags, op->reports) != 0)
|
||||
return OPERATOR_CANCELLED;
|
||||
|
||||
WM_event_add_notifier(C, NC_WM | ND_FILESAVE, NULL);
|
||||
|
Reference in New Issue
Block a user