From b24712a9ca6fa807660a02d6988269748daecdbf Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Tue, 15 Dec 2020 18:18:53 +0100 Subject: Fix (studio-reported) broken handling of relative font paths. `blf_dir_search` BLF util would not properly handle relative fonts not found in pre-defined 'system fonts' directoriesi stored in `global_font_dir` global variable. Now it rebases relative paths to current .blend file location as expected. Note: the fact that VSE is setting font ptaths relative by default is probably not actually desired, but this is another issue really. See `BKE_sequencer_text_font_load` code. --- source/blender/blenfont/intern/blf_dir.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/source/blender/blenfont/intern/blf_dir.c b/source/blender/blenfont/intern/blf_dir.c index 51d3849aa48..25235097505 100644 --- a/source/blender/blenfont/intern/blf_dir.c +++ b/source/blender/blenfont/intern/blf_dir.c @@ -47,6 +47,9 @@ #include "blf_internal.h" #include "blf_internal_types.h" +#include "BKE_global.h" +#include "BKE_main.h" + static ListBase global_font_dir = {NULL, NULL}; static DirBLF *blf_dir_find(const char *path) @@ -137,9 +140,11 @@ char *blf_dir_search(const char *file) } if (!s) { - /* check the current directory, why not ? */ - if (BLI_exists(file)) { - s = BLI_strdup(file); + /* Assume file is either an abslute path, or a relative path to current directory. */ + BLI_strncpy(full_path, file, sizeof(full_path)); + BLI_path_abs(full_path, BKE_main_blendfile_path(G_MAIN)); + if (BLI_exists(full_path)) { + s = BLI_strdup(full_path); } } -- cgit v1.2.3 From ffe63b0440cb55dee7a0ec3c383cce99167b47a1 Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Tue, 15 Dec 2020 18:49:56 +0100 Subject: Fix crash opening maximized File Browser from Asset Browser If Preferences > Interface > Temporary Editors > File Browser is set to "Maximized Area", opening a File Browser from an Asset Browser would cause the new maximized editor to be an Asset Browser. Exiting it again would crash. This fixes the wrong behavior and the crash. There's still an issue with exiting the editor again, it stays a File Browser then and doesn't go back to being an Asset Browser. That's to be fixed separately. --- source/blender/editors/screen/screen_edit.c | 1 + source/blender/editors/space_file/filesel.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c index 6be2fb8004b..c3dcaefab79 100644 --- a/source/blender/editors/screen/screen_edit.c +++ b/source/blender/editors/screen/screen_edit.c @@ -1369,6 +1369,7 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *area, const newa->full = oldscreen; ED_screen_change(C, screen); + ED_area_tag_refresh(newa); } /* XXX bad code: setscreen() ends with first area active. fullscreen render assumes this too */ diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c index cd27b7b5773..b919a30e6cd 100644 --- a/source/blender/editors/space_file/filesel.c +++ b/source/blender/editors/space_file/filesel.c @@ -490,7 +490,7 @@ void ED_fileselect_set_params_from_userdef(SpaceFile *sfile) wmOperator *op = sfile->op; UserDef_FileSpaceData *sfile_udata = &U.file_space_data; - BLI_assert(sfile->browse_mode == FILE_BROWSE_MODE_FILES); + sfile->browse_mode = FILE_BROWSE_MODE_FILES; FileSelectParams *params = fileselect_ensure_updated_file_params(sfile); if (!op) { -- cgit v1.2.3 From 3834dc2f7b38a8a29b8cd6dbcd55ac5be7890553 Mon Sep 17 00:00:00 2001 From: Philipp Oeser Date: Fri, 11 Dec 2020 12:04:30 +0100 Subject: Fix Adjust Last Operation popup for operators relying on button context This was reported for duplicating particle systems, then using F9 to enable the 'Duplicate Settings' option (see T83317). In this case, the operator gets the particle_system from (buttons) context and if none can get found will duplicate all settings instead. The reason why none gets found here is that buttons_context() doesnt have a valid path when called from F9/SCREEN_OT_redo_last, path is cleared when global undo does a file-read which clears the path (see lib_link_workspace_layout_restore). It can be recomputed though to be valid even from redo_last (at least when in the Properties Editor). This was likely causing other operators (relying on buttons context) from the Properties Editor to fail as well. Fixes T83317 Maniphest Tasks: T83317 Differential Revision: https://developer.blender.org/D9825 --- source/blender/editors/space_buttons/buttons_context.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/source/blender/editors/space_buttons/buttons_context.c b/source/blender/editors/space_buttons/buttons_context.c index 3a2b8cf0115..c1f29231f96 100644 --- a/source/blender/editors/space_buttons/buttons_context.c +++ b/source/blender/editors/space_buttons/buttons_context.c @@ -826,6 +826,11 @@ int /*eContextResult*/ buttons_context(const bContext *C, bContextDataResult *result) { SpaceProperties *sbuts = CTX_wm_space_properties(C); + if (sbuts && sbuts->path == NULL) { + /* path is cleared for SCREEN_OT_redo_last, when global undo does a file-read which clears the + * path (see lib_link_workspace_layout_restore). */ + buttons_context_compute(C, sbuts); + } ButsContextPath *path = sbuts ? sbuts->path : NULL; if (!path) { -- cgit v1.2.3 From 8df167873a3b36f7b179266802699d4f935cd2f9 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Tue, 15 Dec 2020 12:39:27 -0600 Subject: Cleanup: Clang tidy else after return --- source/blender/editors/space_file/filelist.c | 31 ++++++++++++++-------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c index afa1fa0edee..3ed7b5499db 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -3450,22 +3450,21 @@ void filelist_readjob_start(FileList *filelist, const bContext *C) WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL); return; } - else { - /* setup job */ - wm_job = WM_jobs_get(CTX_wm_manager(C), - CTX_wm_window(C), - CTX_data_scene(C), - "Listing Dirs...", - WM_JOB_PROGRESS, - WM_JOB_TYPE_FILESEL_READDIR); - WM_jobs_customdata_set(wm_job, flrj, filelist_readjob_free); - WM_jobs_timer(wm_job, 0.01, NC_SPACE | ND_SPACE_FILE_LIST, NC_SPACE | ND_SPACE_FILE_LIST); - WM_jobs_callbacks( - wm_job, filelist_readjob_startjob, NULL, filelist_readjob_update, filelist_readjob_endjob); - - /* start the job */ - WM_jobs_start(CTX_wm_manager(C), wm_job); - } + + /* setup job */ + wm_job = WM_jobs_get(CTX_wm_manager(C), + CTX_wm_window(C), + CTX_data_scene(C), + "Listing Dirs...", + WM_JOB_PROGRESS, + WM_JOB_TYPE_FILESEL_READDIR); + WM_jobs_customdata_set(wm_job, flrj, filelist_readjob_free); + WM_jobs_timer(wm_job, 0.01, NC_SPACE | ND_SPACE_FILE_LIST, NC_SPACE | ND_SPACE_FILE_LIST); + WM_jobs_callbacks( + wm_job, filelist_readjob_startjob, NULL, filelist_readjob_update, filelist_readjob_endjob); + + /* start the job */ + WM_jobs_start(CTX_wm_manager(C), wm_job); } void filelist_readjob_stop(wmWindowManager *wm, Scene *owner_scene) -- cgit v1.2.3 From d59e87acf0b8954390ce2691145613ea8585010f Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Tue, 15 Dec 2020 12:41:41 -0600 Subject: Cleanup: Use nullptr instead of NULL in C++ code --- source/blender/blenkernel/intern/icons.cc | 72 +++++++++++++++---------------- 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/source/blender/blenkernel/intern/icons.cc b/source/blender/blenkernel/intern/icons.cc index 48f5e11778c..fbf69357478 100644 --- a/source/blender/blenkernel/intern/icons.cc +++ b/source/blender/blenkernel/intern/icons.cc @@ -78,7 +78,7 @@ enum { static CLG_LogRef LOG = {"bke.icons"}; /* Protected by gIconMutex. */ -static GHash *gIcons = NULL; +static GHash *gIcons = nullptr; /* Protected by gIconMutex. */ static int gNextIconId = 1; @@ -89,7 +89,7 @@ static int gFirstIconId = 1; std::mutex gIconMutex; /* Not mutex-protected! */ -static GHash *gCachedPreviews = NULL; +static GHash *gCachedPreviews = nullptr; /* Queue of icons for deferred deletion. */ typedef struct DeferredIconDeleteNode { @@ -149,7 +149,7 @@ static void icon_free_data(int icon_id, Icon *icon) } else if (icon->obj_type == ICON_DATA_STUDIOLIGHT) { StudioLight *sl = (StudioLight *)icon->obj; - if (sl != NULL) { + if (sl != nullptr) { BKE_studiolight_unset_icon_id(sl, icon_id); } } @@ -166,7 +166,7 @@ static Icon *icon_ghash_lookup(int icon_id) /* create an id for a new icon and make sure that ids from deleted icons get reused * after the integer number range is used up */ -static int get_next_free_id(void) +static int get_next_free_id() { std::scoped_lock lock(gIconMutex); int startId = gFirstIconId; @@ -214,13 +214,13 @@ void BKE_icons_free(void) BLI_assert(BLI_thread_is_main()); if (gIcons) { - BLI_ghash_free(gIcons, NULL, icon_free); - gIcons = NULL; + BLI_ghash_free(gIcons, nullptr, icon_free); + gIcons = nullptr; } if (gCachedPreviews) { BLI_ghash_free(gCachedPreviews, MEM_freeN, BKE_previewimg_freefunc); - gCachedPreviews = NULL; + gCachedPreviews = nullptr; } BLI_linklist_lockfree_free(&g_icon_delete_queue, MEM_freeN); @@ -232,9 +232,9 @@ void BKE_icons_deferred_free(void) for (DeferredIconDeleteNode *node = (DeferredIconDeleteNode *)BLI_linklist_lockfree_begin(&g_icon_delete_queue); - node != NULL; + node != nullptr; node = node->next) { - BLI_ghash_remove(gIcons, POINTER_FROM_INT(node->icon_id), NULL, icon_free); + BLI_ghash_remove(gIcons, POINTER_FROM_INT(node->icon_id), nullptr, icon_free); } BLI_linklist_lockfree_clear(&g_icon_delete_queue, MEM_freeN); } @@ -296,7 +296,7 @@ void BKE_previewimg_free(PreviewImage **prv) { if (prv && (*prv)) { BKE_previewimg_freefunc(*prv); - *prv = NULL; + *prv = nullptr; } } @@ -321,7 +321,7 @@ void BKE_previewimg_clear(struct PreviewImage *prv) PreviewImage *BKE_previewimg_copy(const PreviewImage *prv) { - PreviewImage *prv_img = NULL; + PreviewImage *prv_img = nullptr; if (prv) { prv_img = (PreviewImage *)MEM_dupallocN(prv); @@ -329,7 +329,7 @@ PreviewImage *BKE_previewimg_copy(const PreviewImage *prv) if (prv->rect[i]) { prv_img->rect[i] = (uint *)MEM_dupallocN(prv->rect[i]); } - prv_img->gputexture[i] = NULL; + prv_img->gputexture[i] = nullptr; } } return prv_img; @@ -345,7 +345,7 @@ void BKE_previewimg_id_copy(ID *new_id, const ID *old_id) PreviewImage **new_prv_p = BKE_previewimg_id_get_p(new_id); if (old_prv_p && *old_prv_p) { - BLI_assert(new_prv_p != NULL && ELEM(*new_prv_p, NULL, *old_prv_p)); + BLI_assert(new_prv_p != nullptr && ELEM(*new_prv_p, nullptr, *old_prv_p)); // const int new_icon_id = get_next_free_id(); // if (new_icon_id == 0) { @@ -379,13 +379,13 @@ PreviewImage **BKE_previewimg_id_get_p(const ID *id) break; } - return NULL; + return nullptr; } PreviewImage *BKE_previewimg_id_get(const ID *id) { PreviewImage **prv_p = BKE_previewimg_id_get_p(id); - return prv_p ? *prv_p : NULL; + return prv_p ? *prv_p : nullptr; } void BKE_previewimg_id_free(ID *id) @@ -401,13 +401,13 @@ PreviewImage *BKE_previewimg_id_ensure(ID *id) PreviewImage **prv_p = BKE_previewimg_id_get_p(id); if (prv_p) { - if (*prv_p == NULL) { + if (*prv_p == nullptr) { *prv_p = BKE_previewimg_create(); } return *prv_p; } - return NULL; + return nullptr; } void BKE_previewimg_id_custom_set(ID *id, const char *path) @@ -464,7 +464,7 @@ PreviewImage *BKE_previewimg_cached_ensure(const char *name) { BLI_assert(BLI_thread_is_main()); - PreviewImage *prv = NULL; + PreviewImage *prv = nullptr; void **key_p, **prv_p; if (!BLI_ghash_ensure_p_ex(gCachedPreviews, name, &key_p, &prv_p)) { @@ -488,7 +488,7 @@ PreviewImage *BKE_previewimg_cached_thumbnail_read(const char *name, { BLI_assert(BLI_thread_is_main()); - PreviewImage *prv = NULL; + PreviewImage *prv = nullptr; void **prv_p; prv_p = BLI_ghash_lookup_p(gCachedPreviews, name); @@ -599,7 +599,7 @@ ImBuf *BKE_previewimg_to_imbuf(PreviewImage *prv, const int size) const unsigned int h = prv->h[size]; const unsigned int *rect = prv->rect[size]; - ImBuf *ima = NULL; + ImBuf *ima = nullptr; if (w > 0 && h > 0 && rect) { /* first allocate imbuf for copying preview into it */ @@ -627,7 +627,7 @@ void BKE_previewimg_blend_write(BlendWriter *writer, const PreviewImage *prv) * but not doing so would causes all previews to be re-rendered after * undo which is too expensive. */ - if (prv == NULL) { + if (prv == nullptr) { return; } @@ -636,7 +636,7 @@ void BKE_previewimg_blend_write(BlendWriter *writer, const PreviewImage *prv) if (!(U.flag & USER_SAVE_PREVIEWS)) { prv_copy.w[1] = 0; prv_copy.h[1] = 0; - prv_copy.rect[1] = NULL; + prv_copy.rect[1] = nullptr; } BLO_write_struct_at_address(writer, PreviewImage, prv, &prv_copy); if (prv_copy.rect[0]) { @@ -649,7 +649,7 @@ void BKE_previewimg_blend_write(BlendWriter *writer, const PreviewImage *prv) void BKE_previewimg_blend_read(BlendDataReader *reader, PreviewImage *prv) { - if (prv == NULL) { + if (prv == nullptr) { return; } @@ -657,7 +657,7 @@ void BKE_previewimg_blend_read(BlendDataReader *reader, PreviewImage *prv) if (prv->rect[i]) { BLO_read_data_address(reader, &prv->rect[i]); } - prv->gputexture[i] = NULL; + prv->gputexture[i] = nullptr; /* For now consider previews read from file as finished to not confuse File Browser preview * loading. That could be smarter and check if there's a preview job running instead. * If the preview is tagged as changed, it needs to be updated anyway, so don't remove the tag. @@ -676,7 +676,7 @@ void BKE_previewimg_blend_read(BlendDataReader *reader, PreviewImage *prv) void BKE_icon_changed(const int icon_id) { - Icon *icon = NULL; + Icon *icon = nullptr; if (!icon_id || G.background) { return; @@ -714,8 +714,8 @@ static Icon *icon_create(int icon_id, int obj_type, void *obj) new_icon->flag = 0; /* next two lines make sure image gets created */ - new_icon->drawinfo = NULL; - new_icon->drawinfo_free = NULL; + new_icon->drawinfo = nullptr; + new_icon->drawinfo_free = nullptr; { std::scoped_lock lock(gIconMutex); @@ -867,11 +867,11 @@ ImBuf *BKE_icon_imbuf_get_buffer(int icon_id) Icon *icon = icon_ghash_lookup(icon_id); if (!icon) { CLOG_ERROR(&LOG, "no icon for icon ID: %d", icon_id); - return NULL; + return nullptr; } if (icon->obj_type != ICON_DATA_IMBUF) { CLOG_ERROR(&LOG, "icon ID does not refer to an imbuf icon: %d", icon_id); - return NULL; + return nullptr; } return (ImBuf *)icon->obj; @@ -881,13 +881,13 @@ Icon *BKE_icon_get(const int icon_id) { BLI_assert(BLI_thread_is_main()); - Icon *icon = NULL; + Icon *icon = nullptr; icon = icon_ghash_lookup(icon_id); if (!icon) { CLOG_ERROR(&LOG, "no icon for icon ID: %d", icon_id); - return NULL; + return nullptr; } return icon; @@ -930,7 +930,7 @@ void BKE_icon_id_delete(struct ID *id) BKE_icons_deferred_free(); std::scoped_lock lock(gIconMutex); - BLI_ghash_remove(gIcons, POINTER_FROM_INT(icon_id), NULL, icon_free); + BLI_ghash_remove(gIcons, POINTER_FROM_INT(icon_id), nullptr, icon_free); } /** @@ -944,7 +944,7 @@ bool BKE_icon_delete(const int icon_id) } std::scoped_lock lock(gIconMutex); - if (Icon *icon = (Icon *)BLI_ghash_popkey(gIcons, POINTER_FROM_INT(icon_id), NULL)) { + if (Icon *icon = (Icon *)BLI_ghash_popkey(gIcons, POINTER_FROM_INT(icon_id), nullptr)) { icon_free_data(icon_id, icon); icon_free(icon); return true; @@ -962,7 +962,7 @@ bool BKE_icon_delete_unmanaged(const int icon_id) std::scoped_lock lock(gIconMutex); - Icon *icon = (Icon *)BLI_ghash_popkey(gIcons, POINTER_FROM_INT(icon_id), NULL); + Icon *icon = (Icon *)BLI_ghash_popkey(gIcons, POINTER_FROM_INT(icon_id), nullptr); if (icon) { if (UNLIKELY(icon->flag & ICON_FLAG_MANAGED)) { BLI_ghash_insert(gIcons, POINTER_FROM_INT(icon_id), icon); @@ -1041,8 +1041,8 @@ struct Icon_Geom *BKE_icon_geom_from_file(const char *filename) BLI_assert(BLI_thread_is_main()); size_t data_len; uchar *data = (uchar *)BLI_file_read_binary_as_mem(filename, 0, &data_len); - if (data == NULL) { - return NULL; + if (data == nullptr) { + return nullptr; } return BKE_icon_geom_from_memory(data, data_len); } -- cgit v1.2.3 From 26e9c2147e2810d5238408b029195d427a78f80e Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Tue, 15 Dec 2020 12:43:21 -0600 Subject: Blenloader: Add utility function to write double array It makes sense to support writing double arrays just like floats. This is just split from a patch (D9697) to slim it down some. --- source/blender/blenloader/BLO_read_write.h | 1 + source/blender/blenloader/intern/writefile.c | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/source/blender/blenloader/BLO_read_write.h b/source/blender/blenloader/BLO_read_write.h index c4480e2c544..ea0532d884b 100644 --- a/source/blender/blenloader/BLO_read_write.h +++ b/source/blender/blenloader/BLO_read_write.h @@ -160,6 +160,7 @@ void BLO_write_raw(BlendWriter *writer, size_t size_in_bytes, const void *data_p void BLO_write_int32_array(BlendWriter *writer, uint num, const int32_t *data_ptr); void BLO_write_uint32_array(BlendWriter *writer, uint num, const uint32_t *data_ptr); void BLO_write_float_array(BlendWriter *writer, uint num, const float *data_ptr); +void BLO_write_double_array(BlendWriter *writer, uint num, const double *data_ptr); void BLO_write_float3_array(BlendWriter *writer, uint num, const float *data_ptr); void BLO_write_pointer_array(BlendWriter *writer, uint num, const void *data_ptr); void BLO_write_string(BlendWriter *writer, const char *data_ptr); diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index e7d55538f7e..0a4f2fde93f 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -1374,6 +1374,11 @@ void BLO_write_float_array(BlendWriter *writer, uint num, const float *data_ptr) BLO_write_raw(writer, sizeof(float) * (size_t)num, data_ptr); } +void BLO_write_double_array(BlendWriter *writer, uint num, const double *data_ptr) +{ + BLO_write_raw(writer, sizeof(double) * (size_t)num, data_ptr); +} + void BLO_write_pointer_array(BlendWriter *writer, uint num, const void *data_ptr) { BLO_write_raw(writer, sizeof(void *) * (size_t)num, data_ptr); -- cgit v1.2.3 From c9de65679bb0905e7f689b83931c9be9a8abfa02 Mon Sep 17 00:00:00 2001 From: Pablo Dobarro Date: Sun, 6 Dec 2020 23:11:33 +0100 Subject: Fix T83201: Cloth brush performance regression The if statement of the dynamic area mode branch should be an else if. When using local mode, this was running both the local and global code. I moved this code to sculpt_cloth and refactored it to use a switch case to prevent this from happening again. Reviewed By: mont29 Maniphest Tasks: T83201 Differential Revision: https://developer.blender.org/D9762 --- source/blender/editors/sculpt_paint/sculpt.c | 27 +--------------- source/blender/editors/sculpt_paint/sculpt_cloth.c | 37 ++++++++++++++++++++++ .../blender/editors/sculpt_paint/sculpt_intern.h | 4 +++ 3 files changed, 42 insertions(+), 26 deletions(-) diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index 94f05560f79..80a32682325 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -5742,32 +5742,7 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode); } else if (brush->sculpt_tool == SCULPT_TOOL_CLOTH) { - if (brush->cloth_simulation_area_type == BRUSH_CLOTH_SIMULATION_AREA_LOCAL) { - SculptSearchSphereData data = { - .ss = ss, - .sd = sd, - .radius_squared = square_f(ss->cache->initial_radius * (1.0 + brush->cloth_sim_limit)), - .original = false, - .ignore_fully_ineffective = false, - .center = ss->cache->initial_location, - }; - BKE_pbvh_search_gather(ss->pbvh, SCULPT_search_sphere_cb, &data, &nodes, &totnode); - } - if (brush->cloth_simulation_area_type == BRUSH_CLOTH_SIMULATION_AREA_DYNAMIC) { - SculptSearchSphereData data = { - .ss = ss, - .sd = sd, - .radius_squared = square_f(ss->cache->radius * (1.0 + brush->cloth_sim_limit)), - .original = false, - .ignore_fully_ineffective = false, - .center = ss->cache->location, - }; - BKE_pbvh_search_gather(ss->pbvh, SCULPT_search_sphere_cb, &data, &nodes, &totnode); - } - else { - /* Gobal simulation, get all nodes. */ - BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode); - } + nodes = SCULPT_cloth_brush_affected_nodes_gather(ss, brush, &totnode); } else { const bool use_original = sculpt_tool_needs_original(brush->sculpt_tool) ? true : diff --git a/source/blender/editors/sculpt_paint/sculpt_cloth.c b/source/blender/editors/sculpt_paint/sculpt_cloth.c index f8165890cc4..0ac0d796ca4 100644 --- a/source/blender/editors/sculpt_paint/sculpt_cloth.c +++ b/source/blender/editors/sculpt_paint/sculpt_cloth.c @@ -119,6 +119,43 @@ static void cloth_brush_simulation_location_get(SculptSession *ss, copy_v3_v3(r_location, ss->cache->location); } +PBVHNode **SCULPT_cloth_brush_affected_nodes_gather(SculptSession *ss, + Brush *brush, + int *r_totnode) +{ + BLI_assert(ss->cache); + BLI_assert(brush->sculpt_tool == SCULPT_TOOL_CLOTH); + PBVHNode **nodes = NULL; + + switch (brush->cloth_simulation_area_type) { + case BRUSH_CLOTH_SIMULATION_AREA_LOCAL: { + SculptSearchSphereData data = { + .ss = ss, + .radius_squared = square_f(ss->cache->initial_radius * (1.0 + brush->cloth_sim_limit)), + .original = false, + .ignore_fully_ineffective = false, + .center = ss->cache->initial_location, + }; + BKE_pbvh_search_gather(ss->pbvh, SCULPT_search_sphere_cb, &data, &nodes, r_totnode); + } break; + case BRUSH_CLOTH_SIMULATION_AREA_GLOBAL: + BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, r_totnode); + break; + case BRUSH_CLOTH_SIMULATION_AREA_DYNAMIC: { + SculptSearchSphereData data = { + .ss = ss, + .radius_squared = square_f(ss->cache->radius * (1.0 + brush->cloth_sim_limit)), + .original = false, + .ignore_fully_ineffective = false, + .center = ss->cache->location, + }; + BKE_pbvh_search_gather(ss->pbvh, SCULPT_search_sphere_cb, &data, &nodes, r_totnode); + } break; + } + + return nodes; +} + static float cloth_brush_simulation_falloff_get(const Brush *brush, const float radius, const float location[3], diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h index e0d413bc75f..bd5ba15b493 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.h +++ b/source/blender/editors/sculpt_paint/sculpt_intern.h @@ -423,6 +423,10 @@ void SCULPT_cloth_plane_falloff_preview_draw(const uint gpuattr, const float outline_col[3], float outline_alpha); +PBVHNode **SCULPT_cloth_brush_affected_nodes_gather(SculptSession *ss, + Brush *brush, + int *r_totnode); + BLI_INLINE bool SCULPT_is_cloth_deform_brush(const Brush *brush) { return (brush->sculpt_tool == SCULPT_TOOL_CLOTH && ELEM(brush->cloth_deform_type, -- cgit v1.2.3 From 288f2efbd41f325c4127a0f42bf5d2c6682fd00e Mon Sep 17 00:00:00 2001 From: Pablo Dobarro Date: Mon, 7 Dec 2020 17:32:52 +0100 Subject: Fix T83504: Cancel trim operators when there is no geometry The boolean solver crashes when there is no geometry in the mesh. Also, using the trimming tools without a valid intersection in the PBVH will make the orientation and position functionality of the trimming shape not work, so this is the safer solution. Reviewed By: mont29 Maniphest Tasks: T83504 Differential Revision: https://developer.blender.org/D9777 --- source/blender/editors/sculpt_paint/paint_mask.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c index 17690757fa5..92c78a674f0 100644 --- a/source/blender/editors/sculpt_paint/paint_mask.c +++ b/source/blender/editors/sculpt_paint/paint_mask.c @@ -1552,6 +1552,11 @@ static int sculpt_trim_gesture_box_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } + if (ss->totvert == 0) { + /* No geometry to trim or to detect a valid position for the trimming shape. */ + return OPERATOR_CANCELLED; + } + SculptGestureContext *sgcontext = sculpt_gesture_init_from_box(C, op); if (!sgcontext) { return OPERATOR_CANCELLED; @@ -1589,6 +1594,11 @@ static int sculpt_trim_gesture_lasso_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } + if (ss->totvert == 0) { + /* No geometry to trim or to detect a valid position for the trimming shape. */ + return OPERATOR_CANCELLED; + } + SculptGestureContext *sgcontext = sculpt_gesture_init_from_lasso(C, op); if (!sgcontext) { return OPERATOR_CANCELLED; -- cgit v1.2.3 From c9b4d75336271fd0427f47a43f3bf4cb525c5252 Mon Sep 17 00:00:00 2001 From: Pablo Dobarro Date: Mon, 14 Dec 2020 17:22:20 +0100 Subject: Sculpt: Fair Face Sets operation for Face Set Edit This implements a mesh fairing algorithm and implements the fair operations for Face Set edit. This edit operations create a smooth as possible geometry patch in the area of the selected Face Set. The mesh fairing algorithm is designed by Brett Fedack for the addon "Mesh Fairing": https://github.com/fedackb/mesh-fairing, with some modifications: - The main fairing function in BKE_mesh_fair.h does not triangulate the mesh. For the test I did in sculpt mode results are good enough without triangulating the topology. Depending on the use and the result quality needed for a particular tool, the mesh can be triangulate in the affected area before starting fairing. - Cotangents loop weights are not implemented yet. The idea is to also expose the vertex and loop weights in a different function in case a tool needs to set up custom weights. This algorithm will also be used to solve the limitations of line project and implement the Lasso Project and Polyline Project tools. It can also be used in tools in other areas of Blender, like Edit Mode or future retopology tools. Reviewed By: brecht Differential Revision: https://developer.blender.org/D9603 --- source/blender/blenkernel/BKE_mesh_fair.h | 56 +++ source/blender/blenkernel/CMakeLists.txt | 3 + source/blender/blenkernel/intern/mesh_fair.cc | 505 +++++++++++++++++++++ source/blender/editors/sculpt_paint/CMakeLists.txt | 1 + .../blender/editors/sculpt_paint/sculpt_face_set.c | 91 +++- 5 files changed, 655 insertions(+), 1 deletion(-) create mode 100644 source/blender/blenkernel/BKE_mesh_fair.h create mode 100644 source/blender/blenkernel/intern/mesh_fair.cc diff --git a/source/blender/blenkernel/BKE_mesh_fair.h b/source/blender/blenkernel/BKE_mesh_fair.h new file mode 100644 index 00000000000..2d5c85d4129 --- /dev/null +++ b/source/blender/blenkernel/BKE_mesh_fair.h @@ -0,0 +1,56 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Mesh Fairing algorithm designed by Brett Fedack, used in the addon "Mesh Fairing": + * https://github.com/fedackb/mesh-fairing. + */ + +#pragma once + +/** \file + * \ingroup bke + */ + +#include "BLI_utildefines.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Mesh Fairing. */ +/* Creates a smooth as possible geometry patch in a defined area. Different values of depth allow + * to minimize changes in the vertex positions or tangency in the affected area. */ + +typedef enum eMeshFairingDepth { + MESH_FAIRING_DEPTH_POSITION = 1, + MESH_FAIRING_DEPTH_TANGENCY = 2, +} eMeshFairingDepth; + +/* affect_vertices is used to define the fairing area. Indexed by vertex index, set to true when + * the vertex should be modified by fairing. */ +void BKE_bmesh_prefair_and_fair_vertices(struct BMesh *bm, + bool *affect_vertices, + const eMeshFairingDepth depth); + +/* This function can optionally use the MVert coordinates of deform_mverts to read and write the + * fairing result. When NULL, the function will use mesh->mverts directly. */ +void BKE_mesh_prefair_and_fair_vertices(struct Mesh *mesh, + struct MVert *deform_mverts, + bool *affect_vertices, + const eMeshFairingDepth depth); + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index 0067e1c8209..ae0a180311c 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -42,6 +42,7 @@ set(INC ../simulation ../../../intern/ghost ../../../intern/glew-mx + ../../../intern/eigen ../../../intern/guardedalloc ../../../intern/iksolver/extern ../../../intern/atomic @@ -170,6 +171,7 @@ set(SRC intern/mesh.c intern/mesh_convert.c intern/mesh_evaluate.c + intern/mesh_fair.cc intern/mesh_iterators.c intern/mesh_mapping.c intern/mesh_merge.c @@ -353,6 +355,7 @@ set(SRC BKE_mball_tessellate.h BKE_mesh.h BKE_mesh_iterators.h + BKE_mesh_fair.h BKE_mesh_mapping.h BKE_mesh_mirror.h BKE_mesh_remap.h diff --git a/source/blender/blenkernel/intern/mesh_fair.cc b/source/blender/blenkernel/intern/mesh_fair.cc new file mode 100644 index 00000000000..527288d06cf --- /dev/null +++ b/source/blender/blenkernel/intern/mesh_fair.cc @@ -0,0 +1,505 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Mesh Fairing algorithm designed by Brett Fedack, used in the addon "Mesh Fairing": + * https://github.com/fedackb/mesh-fairing. + */ + +/** \file + * \ingroup bke + */ + +#include "BLI_map.hh" +#include "BLI_math.h" +#include "BLI_vector.hh" + +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_object_types.h" + +#include "BKE_lib_id.h" +#include "BKE_lib_query.h" +#include "BKE_mesh.h" +#include "BKE_mesh_fair.h" +#include "BKE_mesh_mapping.h" + +#include "bmesh.h" +#include "bmesh_tools.h" + +#include "MEM_guardedalloc.h" +#include "eigen_capi.h" + +using blender::Map; +using blender::Vector; +using std::array; + +class VertexWeight { + public: + virtual float weight_at_index(const int index) = 0; + virtual ~VertexWeight() = default; +}; + +class LoopWeight { + public: + virtual float weight_at_index(const int index) = 0; + virtual ~LoopWeight() = default; +}; + +class FairingContext { + public: + /* Get coordinates of vertices which are adjacent to the loop with specified index. */ + virtual void adjacents_coords_from_loop(const int loop, + float r_adj_next[3], + float r_adj_prev[3]) = 0; + + /* Get the other vertex index for a loop. */ + virtual int other_vertex_index_from_loop(const int loop, const unsigned int v) = 0; + + int vertex_count_get() + { + return totvert_; + } + + int loop_count_get() + { + return totvert_; + } + + MeshElemMap *vertex_loop_map_get(const int v) + { + return &vlmap_[v]; + } + + float *vertex_deformation_co_get(const int v) + { + return co_[v]; + } + + virtual ~FairingContext() = default; + + void fair_vertices(bool *affected, + const eMeshFairingDepth depth, + VertexWeight *vertex_weight, + LoopWeight *loop_weight) + { + + fair_vertices_ex(affected, (int)depth, vertex_weight, loop_weight); + } + + protected: + Vector co_; + + int totvert_; + int totloop_; + + MeshElemMap *vlmap_; + int *vlmap_mem_; + + private: + void fair_setup_fairing(const int v, + const int i, + LinearSolver *solver, + float multiplier, + const int depth, + Map &vert_col_map, + VertexWeight *vertex_weight, + LoopWeight *loop_weight) + { + if (depth == 0) { + if (vert_col_map.contains(v)) { + const int j = vert_col_map.lookup(v); + EIG_linear_solver_matrix_add(solver, i, j, -multiplier); + return; + } + for (int j = 0; j < 3; j++) { + EIG_linear_solver_right_hand_side_add(solver, j, i, multiplier * co_[v][j]); + } + return; + } + + float w_ij_sum = 0; + const float w_i = vertex_weight->weight_at_index(v); + MeshElemMap *vlmap_elem = &vlmap_[v]; + for (int l = 0; l < vlmap_elem->count; l++) { + const int l_index = vlmap_elem->indices[l]; + const int other_vert = other_vertex_index_from_loop(l_index, v); + const float w_ij = loop_weight->weight_at_index(l_index); + w_ij_sum += w_ij; + fair_setup_fairing(other_vert, + i, + solver, + w_i * w_ij * multiplier, + depth - 1, + vert_col_map, + vertex_weight, + loop_weight); + } + fair_setup_fairing(v, + i, + solver, + -1 * w_i * w_ij_sum * multiplier, + depth - 1, + vert_col_map, + vertex_weight, + loop_weight); + } + + void fair_vertices_ex(bool *affected, + const int order, + VertexWeight *vertex_weight, + LoopWeight *loop_weight) + { + Map vert_col_map; + int num_affected_vertices = 0; + for (int i = 0; i < totvert_; i++) { + if (!affected[i]) { + continue; + } + vert_col_map.add(i, num_affected_vertices); + num_affected_vertices++; + } + + /* Early return, nothing to do. */ + if (num_affected_vertices == 0 || num_affected_vertices == totvert_) { + return; + } + + /* Setup fairing matrices */ + LinearSolver *solver = EIG_linear_solver_new(num_affected_vertices, num_affected_vertices, 3); + for (auto item : vert_col_map.items()) { + const int v = item.key; + const int col = item.value; + fair_setup_fairing(v, col, solver, 1.0f, order, vert_col_map, vertex_weight, loop_weight); + } + + /* Solve linear system */ + EIG_linear_solver_solve(solver); + + /* Copy the result back to the mesh */ + for (auto item : vert_col_map.items()) { + const int v = item.key; + const int col = item.value; + for (int j = 0; j < 3; j++) { + co_[v][j] = EIG_linear_solver_variable_get(solver, j, col); + } + } + + /* Free solver data */ + EIG_linear_solver_delete(solver); + } +}; + +class MeshFairingContext : public FairingContext { + public: + MeshFairingContext(Mesh *mesh, MVert *deform_mverts) + { + totvert_ = mesh->totvert; + totloop_ = mesh->totloop; + + medge_ = mesh->medge; + mpoly_ = mesh->mpoly; + mloop_ = mesh->mloop; + BKE_mesh_vert_loop_map_create(&vlmap_, + &vlmap_mem_, + mesh->mpoly, + mesh->mloop, + mesh->totvert, + mesh->totpoly, + mesh->totloop); + + /* Deformation coords. */ + co_.reserve(mesh->totvert); + if (deform_mverts) { + for (int i = 0; i < mesh->totvert; i++) { + co_[i] = deform_mverts[i].co; + } + } + else { + for (int i = 0; i < mesh->totvert; i++) { + co_[i] = mesh->mvert[i].co; + } + } + + loop_to_poly_map_.reserve(mesh->totloop); + for (int i = 0; i < mesh->totpoly; i++) { + for (int l = 0; l < mesh->mpoly[i].totloop; l++) { + loop_to_poly_map_[l + mesh->mpoly[i].loopstart] = i; + } + } + } + + ~MeshFairingContext() + { + MEM_SAFE_FREE(vlmap_); + MEM_SAFE_FREE(vlmap_mem_); + } + + virtual void adjacents_coords_from_loop(const int loop, + float r_adj_next[3], + float r_adj_prev[3]) override + { + const int vert = mloop_[loop].v; + const MPoly *p = &mpoly_[loop_to_poly_map_[loop]]; + const int corner = poly_find_loop_from_vert(p, &mloop_[p->loopstart], vert); + copy_v3_v3(r_adj_next, co_[ME_POLY_LOOP_NEXT(mloop_, p, corner)->v]); + copy_v3_v3(r_adj_prev, co_[ME_POLY_LOOP_PREV(mloop_, p, corner)->v]); + } + + virtual int other_vertex_index_from_loop(const int loop, const unsigned int v) override + { + MEdge *e = &medge_[mloop_[loop].e]; + if (e->v1 == v) { + return e->v2; + } + return e->v1; + } + + protected: + Mesh *mesh_; + MLoop *mloop_; + MPoly *mpoly_; + MEdge *medge_; + Vector loop_to_poly_map_; +}; + +class BMeshFairingContext : public FairingContext { + public: + BMeshFairingContext(BMesh *bm) + { + this->bm = bm; + totvert_ = bm->totvert; + totloop_ = bm->totloop; + + BM_mesh_elem_table_ensure(bm, BM_VERT); + BM_mesh_elem_index_ensure(bm, BM_LOOP); + + /* Deformation coords. */ + co_.reserve(bm->totvert); + for (int i = 0; i < bm->totvert; i++) { + BMVert *v = BM_vert_at_index(bm, i); + co_[i] = v->co; + } + + bmloop_.reserve(bm->totloop); + vlmap_ = (MeshElemMap *)MEM_calloc_arrayN(sizeof(MeshElemMap), bm->totvert, "bmesh loop map"); + vlmap_mem_ = (int *)MEM_malloc_arrayN(sizeof(int), bm->totloop, "bmesh loop map mempool"); + + BMVert *v; + BMLoop *l; + BMIter iter; + BMIter loop_iter; + int index_iter = 0; + + /* This initializes both the bmloop and the vlmap for bmesh in a single loop. */ + BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { + int loop_count = 0; + const int vert_index = BM_elem_index_get(v); + vlmap_[vert_index].indices = &vlmap_mem_[index_iter]; + BM_ITER_ELEM (l, &loop_iter, v, BM_LOOPS_OF_VERT) { + const int loop_index = BM_elem_index_get(l); + bmloop_[loop_index] = l; + vlmap_mem_[index_iter] = loop_index; + index_iter++; + loop_count++; + } + vlmap_[vert_index].count = loop_count; + } + } + + ~BMeshFairingContext() + { + MEM_SAFE_FREE(vlmap_); + MEM_SAFE_FREE(vlmap_mem_); + } + + virtual void adjacents_coords_from_loop(const int loop, + float r_adj_next[3], + float r_adj_prev[3]) override + { + copy_v3_v3(r_adj_next, bmloop_[loop]->next->v->co); + copy_v3_v3(r_adj_prev, bmloop_[loop]->prev->v->co); + } + + virtual int other_vertex_index_from_loop(const int loop, const unsigned int v) override + { + BMLoop *l = bmloop_[loop]; + BMVert *bmvert = BM_vert_at_index(bm, v); + BMVert *bm_other_vert = BM_edge_other_vert(l->e, bmvert); + return BM_elem_index_get(bm_other_vert); + } + + protected: + BMesh *bm; + Vector bmloop_; +}; + +class UniformVertexWeight : public VertexWeight { + public: + UniformVertexWeight(FairingContext *fairing_context) + { + const int totvert = fairing_context->vertex_count_get(); + vertex_weights_.reserve(totvert); + for (int i = 0; i < totvert; i++) { + const int tot_loop = fairing_context->vertex_loop_map_get(i)->count; + if (tot_loop != 0) { + vertex_weights_[i] = 1.0f / tot_loop; + } + else { + vertex_weights_[i] = FLT_MAX; + } + } + } + ~UniformVertexWeight() = default; + + float weight_at_index(const int index) override + { + return vertex_weights_[index]; + } + + private: + Vector vertex_weights_; +}; + +class VoronoiVertexWeight : public VertexWeight { + + public: + VoronoiVertexWeight(FairingContext *fairing_context) + { + + const int totvert = fairing_context->vertex_count_get(); + vertex_weights_.reserve(totvert); + for (int i = 0; i < totvert; i++) { + + float area = 0.0f; + float a[3]; + copy_v3_v3(a, fairing_context->vertex_deformation_co_get(i)); + const float acute_threshold = M_PI_2; + + MeshElemMap *vlmap_elem = fairing_context->vertex_loop_map_get(i); + for (int l = 0; l < vlmap_elem->count; l++) { + const int l_index = vlmap_elem->indices[l]; + + float b[3], c[3], d[3]; + fairing_context->adjacents_coords_from_loop(l_index, b, c); + + if (angle_v3v3v3(c, fairing_context->vertex_deformation_co_get(i), b) < acute_threshold) { + calc_circumcenter(d, a, b, c); + } + else { + add_v3_v3v3(d, b, c); + mul_v3_fl(d, 0.5f); + } + + float t[3]; + add_v3_v3v3(t, a, b); + mul_v3_fl(t, 0.5f); + area += area_tri_v3(a, t, d); + + add_v3_v3v3(t, a, c); + mul_v3_fl(t, 0.5f); + area += area_tri_v3(a, d, t); + } + + vertex_weights_[i] = area != 0.0f ? 1.0f / area : 1e12; + } + } + ~VoronoiVertexWeight() = default; + + float weight_at_index(const int index) override + { + return vertex_weights_[index]; + } + + private: + Vector vertex_weights_; + + void calc_circumcenter(float r[3], const float a[3], const float b[3], const float c[3]) + { + float ab[3]; + sub_v3_v3v3(ab, b, a); + + float ac[3]; + sub_v3_v3v3(ac, c, a); + + float ab_cross_ac[3]; + cross_v3_v3v3(ab_cross_ac, ab, ac); + + if (len_squared_v3(ab_cross_ac) > 0.0f) { + float d[3]; + cross_v3_v3v3(d, ab_cross_ac, ab); + mul_v3_fl(d, len_squared_v3(ac)); + + float t[3]; + cross_v3_v3v3(t, ac, ab_cross_ac); + mul_v3_fl(t, len_squared_v3(ab)); + + add_v3_v3(d, t); + + mul_v3_fl(d, 1.0f / (2.0f * len_squared_v3(ab_cross_ac))); + + add_v3_v3v3(r, a, d); + return; + } + copy_v3_v3(r, a); + } +}; + +class UniformLoopWeight : public LoopWeight { + public: + float weight_at_index(const int UNUSED(index)) override + { + return 1.0f; + } +}; + +static void prefair_and_fair_vertices(FairingContext *fairing_context, + bool *affected_vertices, + const eMeshFairingDepth depth) +{ + /* Prefair. */ + UniformVertexWeight *uniform_vertex_weights = new UniformVertexWeight(fairing_context); + UniformLoopWeight *uniform_loop_weights = new UniformLoopWeight(); + fairing_context->fair_vertices( + affected_vertices, depth, uniform_vertex_weights, uniform_loop_weights); + delete uniform_vertex_weights; + + /* Fair. */ + VoronoiVertexWeight *voronoi_vertex_weights = new VoronoiVertexWeight(fairing_context); + /* TODO: Implemente cotangent loop weights. */ + fairing_context->fair_vertices( + affected_vertices, depth, voronoi_vertex_weights, uniform_loop_weights); + + delete uniform_loop_weights; + delete voronoi_vertex_weights; +} + +void BKE_mesh_prefair_and_fair_vertices(struct Mesh *mesh, + struct MVert *deform_mverts, + bool *affect_vertices, + const eMeshFairingDepth depth) +{ + MeshFairingContext *fairing_context = new MeshFairingContext(mesh, deform_mverts); + prefair_and_fair_vertices(fairing_context, affect_vertices, depth); + delete fairing_context; +} + +void BKE_bmesh_prefair_and_fair_vertices(struct BMesh *bm, + bool *affect_vertices, + const eMeshFairingDepth depth) +{ + BMeshFairingContext *fairing_context = new BMeshFairingContext(bm); + prefair_and_fair_vertices(fairing_context, affect_vertices, depth); + delete fairing_context; +} diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt index 9bf3d2610d8..fff8d27ef5b 100644 --- a/source/blender/editors/sculpt_paint/CMakeLists.txt +++ b/source/blender/editors/sculpt_paint/CMakeLists.txt @@ -32,6 +32,7 @@ set(INC ../../windowmanager ../../../../intern/atomic ../../../../intern/clog + ../../../../intern/eigen ../../../../intern/glew-mx ../../../../intern/guardedalloc ) diff --git a/source/blender/editors/sculpt_paint/sculpt_face_set.c b/source/blender/editors/sculpt_paint/sculpt_face_set.c index ad42750bb92..1fba958d695 100644 --- a/source/blender/editors/sculpt_paint/sculpt_face_set.c +++ b/source/blender/editors/sculpt_paint/sculpt_face_set.c @@ -41,6 +41,7 @@ #include "BKE_context.h" #include "BKE_customdata.h" #include "BKE_mesh.h" +#include "BKE_mesh_fair.h" #include "BKE_mesh_mapping.h" #include "BKE_multires.h" #include "BKE_node.h" @@ -1024,6 +1025,8 @@ typedef enum eSculptFaceSetEditMode { SCULPT_FACE_SET_EDIT_GROW = 0, SCULPT_FACE_SET_EDIT_SHRINK = 1, SCULPT_FACE_SET_EDIT_DELETE_GEOMETRY = 2, + SCULPT_FACE_SET_EDIT_FAIR_POSITIONS = 3, + SCULPT_FACE_SET_EDIT_FAIR_TANGENCY = 4, } eSculptFaceSetEditMode; static EnumPropertyItem prop_sculpt_face_sets_edit_types[] = { @@ -1048,6 +1051,22 @@ static EnumPropertyItem prop_sculpt_face_sets_edit_types[] = { "Delete Geometry", "Deletes the faces that are assigned to the Face Set", }, + { + SCULPT_FACE_SET_EDIT_FAIR_POSITIONS, + "FAIR_POSITIONS", + 0, + "Fair Positions", + "Creates a smooth as possible geometry patch from the Face Set minimizing changes in " + "vertex positions", + }, + { + SCULPT_FACE_SET_EDIT_FAIR_TANGENCY, + "FAIR_TANGENCY", + 0, + "Fair Tangency", + "Creates a smooth as possible geometry patch from the Face Set minimizing changes in " + "vertex tangents", + }, {0, NULL, 0, NULL, NULL}, }; @@ -1181,6 +1200,29 @@ static void sculpt_face_set_delete_geometry(Object *ob, BM_mesh_free(bm); } +static void sculpt_face_set_edit_fair_face_set(Object *ob, + const int active_face_set_id, + const int fair_order) +{ + SculptSession *ss = ob->sculpt; + const int totvert = SCULPT_vertex_count_get(ss); + + Mesh *mesh = ob->data; + bool *fair_vertices = MEM_malloc_arrayN(sizeof(bool), totvert, "fair vertices"); + + SCULPT_boundary_info_ensure(ob); + + for (int i = 0; i < totvert; i++) { + fair_vertices[i] = !SCULPT_vertex_is_boundary(ss, i) && + SCULPT_vertex_has_face_set(ss, i, active_face_set_id) && + SCULPT_vertex_has_unique_face_set(ss, i); + } + + MVert *mvert = SCULPT_mesh_deformed_mverts_get(ss); + BKE_mesh_prefair_and_fair_vertices(mesh, mvert, fair_vertices, fair_order); + MEM_freeN(fair_vertices); +} + static void sculpt_face_set_apply_edit(Object *ob, const int active_face_set_id, const int mode, @@ -1204,6 +1246,12 @@ static void sculpt_face_set_apply_edit(Object *ob, case SCULPT_FACE_SET_EDIT_DELETE_GEOMETRY: sculpt_face_set_delete_geometry(ob, ss, active_face_set_id, modify_hidden); break; + case SCULPT_FACE_SET_EDIT_FAIR_POSITIONS: + sculpt_face_set_edit_fair_face_set(ob, active_face_set_id, MESH_FAIRING_DEPTH_POSITION); + break; + case SCULPT_FACE_SET_EDIT_FAIR_TANGENCY: + sculpt_face_set_edit_fair_face_set(ob, active_face_set_id, MESH_FAIRING_DEPTH_TANGENCY); + break; } } @@ -1230,6 +1278,16 @@ static bool sculpt_face_set_edit_is_operation_valid(SculptSession *ss, return false; } } + + if (ELEM(mode, SCULPT_FACE_SET_EDIT_FAIR_POSITIONS, SCULPT_FACE_SET_EDIT_FAIR_TANGENCY)) { + if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) { + /* TODO: Multires topology representation using grids and duplicates can't be used directly + * by the fair algorithm. Multires topology needs to be exposed in a different way or + * converted to a mesh for this operation. */ + return false; + } + } + return true; } @@ -1287,11 +1345,38 @@ static void sculpt_face_set_edit_modify_face_sets(Object *ob, MEM_freeN(nodes); } +static void sculpt_face_set_edit_modify_coordinates(bContext *C, + Object *ob, + const int active_face_set, + const eSculptFaceSetEditMode mode) +{ + Sculpt *sd = CTX_data_tool_settings(C)->sculpt; + SculptSession *ss = ob->sculpt; + PBVH *pbvh = ss->pbvh; + PBVHNode **nodes; + int totnode; + BKE_pbvh_search_gather(pbvh, NULL, NULL, &nodes, &totnode); + SCULPT_undo_push_begin(ob, "face set edit"); + for (int i = 0; i < totnode; i++) { + BKE_pbvh_node_mark_update(nodes[i]); + SCULPT_undo_push_node(ob, nodes[i], SCULPT_UNDO_COORDS); + } + sculpt_face_set_apply_edit(ob, abs(active_face_set), mode, false); + + if (ss->deform_modifiers_active || ss->shapekey_active) { + SCULPT_flush_stroke_deform(sd, ob, true); + } + SCULPT_flush_update_step(C, SCULPT_UPDATE_COORDS); + SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_COORDS); + SCULPT_undo_push_end(); + MEM_freeN(nodes); +} + static int sculpt_face_set_edit_invoke(bContext *C, wmOperator *op, const wmEvent *event) { Object *ob = CTX_data_active_object(C); SculptSession *ss = ob->sculpt; - Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); const int mode = RNA_enum_get(op->ptr, "mode"); const bool modify_hidden = RNA_boolean_get(op->ptr, "modify_hidden"); @@ -1320,6 +1405,10 @@ static int sculpt_face_set_edit_invoke(bContext *C, wmOperator *op, const wmEven case SCULPT_FACE_SET_EDIT_SHRINK: sculpt_face_set_edit_modify_face_sets(ob, active_face_set, mode, modify_hidden); break; + case SCULPT_FACE_SET_EDIT_FAIR_POSITIONS: + case SCULPT_FACE_SET_EDIT_FAIR_TANGENCY: + sculpt_face_set_edit_modify_coordinates(C, ob, active_face_set, mode); + break; } SCULPT_tag_update_overlays(C); -- cgit v1.2.3 From 1e799dd26ec1e8487d61f7cdfb592dc86881df18 Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Tue, 15 Dec 2020 21:20:57 +0100 Subject: Fix various issues with temporary, maximized File Browsers If Preferences > Interface > Temporary Editors > File Browser is set to "Maximized Area", opening a File Browser from a File or Asset Browser as regular editor would cause some issues. For example after closing the temporary File Browser, the regular browser would take over the file path and display settings from the temporary one. This is because they used to share the same area data. Some similar issues may have happend with temporary image editors. Now, this commit finally separates the space data of temporary maximized editors from the regular ones. So the editor data is entirely independent now, as it should be. --- source/blender/editors/include/ED_screen.h | 1 + source/blender/editors/screen/screen_edit.c | 187 ++++++++++++++++------------ 2 files changed, 111 insertions(+), 77 deletions(-) diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h index dc1c43c0337..20417634020 100644 --- a/source/blender/editors/include/ED_screen.h +++ b/source/blender/editors/include/ED_screen.h @@ -239,6 +239,7 @@ void ED_screen_restore_temp_type(struct bContext *C, ScrArea *area); ScrArea *ED_screen_full_newspace(struct bContext *C, ScrArea *area, int type); void ED_screen_full_prevspace(struct bContext *C, ScrArea *area); void ED_screen_full_restore(struct bContext *C, ScrArea *area); +ScrArea *ED_screen_state_maximized_create(struct bContext *C); struct ScrArea *ED_screen_state_toggle(struct bContext *C, struct wmWindow *win, struct ScrArea *area, diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c index c3dcaefab79..be52874ed0b 100644 --- a/source/blender/editors/screen/screen_edit.c +++ b/source/blender/editors/screen/screen_edit.c @@ -1133,12 +1133,11 @@ void ED_screen_scene_change(bContext *C, wmWindow *win, Scene *scene) ScrArea *ED_screen_full_newspace(bContext *C, ScrArea *area, int type) { - wmWindow *win = CTX_wm_window(C); ScrArea *newsa = NULL; SpaceLink *newsl; if (!area || area->full == NULL) { - newsa = ED_screen_state_toggle(C, win, area, SCREENMAXIMIZED); + newsa = ED_screen_state_maximized_create(C); } if (!newsa) { @@ -1149,11 +1148,11 @@ ScrArea *ED_screen_full_newspace(bContext *C, ScrArea *area, int type) newsl = newsa->spacedata.first; /* Tag the active space before changing, so we can identify it when user wants to go back. */ - if ((newsl->link_flag & SPACE_FLAG_TYPE_TEMPORARY) == 0) { + if (newsl && (newsl->link_flag & SPACE_FLAG_TYPE_TEMPORARY) == 0) { newsl->link_flag |= SPACE_FLAG_TYPE_WAS_ACTIVE; } - ED_area_newspace(C, newsa, type, newsl->link_flag & SPACE_FLAG_TYPE_TEMPORARY); + ED_area_newspace(C, newsa, type, (newsl && newsl->link_flag & SPACE_FLAG_TYPE_TEMPORARY)); return newsa; } @@ -1217,13 +1216,108 @@ void ED_screen_full_restore(bContext *C, ScrArea *area) } /** - * this function toggles: if area is maximized/full then the parent will be restored + * \param toggle_area: If this is set, its space data will be swapped with the one of the new emtpy + * area, when toggling back it can be swapped back again. + * \return The newly created screen with the non-normal area. + */ +static bScreen *screen_state_to_nonnormal(bContext *C, + wmWindow *win, + ScrArea *toggle_area, + int state) +{ + Main *bmain = CTX_data_main(C); + WorkSpace *workspace = WM_window_get_active_workspace(win); + + /* change from SCREENNORMAL to new state */ + WorkSpaceLayout *layout_new; + ScrArea *newa; + char newname[MAX_ID_NAME - 2]; + + BLI_assert(ELEM(state, SCREENMAXIMIZED, SCREENFULL)); + + bScreen *oldscreen = WM_window_get_active_screen(win); + + oldscreen->state = state; + BLI_snprintf(newname, sizeof(newname), "%s-%s", oldscreen->id.name + 2, "nonnormal"); + + layout_new = ED_workspace_layout_add(bmain, workspace, win, newname); + + bScreen *screen = BKE_workspace_layout_screen_get(layout_new); + screen->state = state; + screen->redraws_flag = oldscreen->redraws_flag; + screen->temp = oldscreen->temp; + screen->flag = oldscreen->flag; + + /* timer */ + screen->animtimer = oldscreen->animtimer; + oldscreen->animtimer = NULL; + + newa = (ScrArea *)screen->areabase.first; + + /* swap area */ + if (toggle_area) { + ED_area_data_swap(newa, toggle_area); + newa->flag = toggle_area->flag; /* mostly for AREA_FLAG_WASFULLSCREEN */ + } + + if (state == SCREENFULL) { + /* temporarily hide global areas */ + LISTBASE_FOREACH (ScrArea *, glob_area, &win->global_areas.areabase) { + glob_area->global->flag |= GLOBAL_AREA_IS_HIDDEN; + } + /* temporarily hide the side panels/header */ + LISTBASE_FOREACH (ARegion *, region, &newa->regionbase) { + region->flagfullscreen = region->flag; + + if (ELEM(region->regiontype, + RGN_TYPE_UI, + RGN_TYPE_HEADER, + RGN_TYPE_TOOL_HEADER, + RGN_TYPE_FOOTER, + RGN_TYPE_TOOLS, + RGN_TYPE_NAV_BAR, + RGN_TYPE_EXECUTE)) { + region->flag |= RGN_FLAG_HIDDEN; + } + } + } + + if (toggle_area) { + toggle_area->full = oldscreen; + } + newa->full = oldscreen; + + ED_screen_change(C, screen); + ED_area_tag_refresh(newa); + + return screen; +} + +/** + * Create a new temporary screen with a maximized, empty area. + * This can be closed with #ED_screen_state_toggle(). + * + * Use this to just create a new maximized screen/area, rather than maximizing an existing one. + * Otherwise, maximize with #ED_screen_state_toggle(). + */ +ScrArea *ED_screen_state_maximized_create(bContext *C) +{ + bScreen *screen = screen_state_to_nonnormal(C, CTX_wm_window(C), NULL, SCREENMAXIMIZED); + return screen->areabase.first; +} + +/** + * This function toggles: if area is maximized/full then the parent will be restored. + * + * Use #ED_screen_state_maximized_create() if you do not want the toggle behavior when changing to + * a maximized area. I.e. if you just want to open a new maximized screen/area, not maximize a + * specific area. In the former case, space data of the maximized and non-maximized area should be + * independent, in the latter it should be the same. * * \warning \a area may be freed. */ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *area, const short state) { - Main *bmain = CTX_data_main(C); wmWindowManager *wm = CTX_wm_manager(C); WorkSpace *workspace = WM_window_get_active_workspace(win); @@ -1257,7 +1351,7 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *area, const screen->state = SCREENNORMAL; screen->flag = oldscreen->flag; - /* find old area to restore from */ + /* Find old area we may have swapped dummy space data to. It's swapped back here. */ ScrArea *fullsa = NULL; LISTBASE_FOREACH (ScrArea *, old, &screen->areabase) { /* area to restore from is always first */ @@ -1271,13 +1365,6 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *area, const area->full = NULL; - if (fullsa == NULL) { - if (G.debug & G_DEBUG) { - printf("%s: something wrong in areafullscreen\n", __func__); - } - return NULL; - } - if (state == SCREENFULL) { /* unhide global areas */ LISTBASE_FOREACH (ScrArea *, glob_area, &win->global_areas.areabase) { @@ -1289,14 +1376,16 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *area, const } } - ED_area_data_swap(fullsa, area); + if (fullsa) { + ED_area_data_swap(fullsa, area); + ED_area_tag_refresh(fullsa); + } /* animtimer back */ screen->animtimer = oldscreen->animtimer; oldscreen->animtimer = NULL; ED_screen_change(C, screen); - ED_area_tag_refresh(fullsa); BKE_workspace_layout_remove(CTX_data_main(C), workspace, layout_old); @@ -1307,69 +1396,16 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *area, const screen->skip_handling = true; } else { - /* change from SCREENNORMAL to new state */ - WorkSpaceLayout *layout_new; - ScrArea *newa; - char newname[MAX_ID_NAME - 2]; - - BLI_assert(ELEM(state, SCREENMAXIMIZED, SCREENFULL)); - - bScreen *oldscreen = WM_window_get_active_screen(win); - - oldscreen->state = state; - BLI_snprintf(newname, sizeof(newname), "%s-%s", oldscreen->id.name + 2, "nonnormal"); - - layout_new = ED_workspace_layout_add(bmain, workspace, win, newname); - - screen = BKE_workspace_layout_screen_get(layout_new); - screen->state = state; - screen->redraws_flag = oldscreen->redraws_flag; - screen->temp = oldscreen->temp; - screen->flag = oldscreen->flag; - - /* timer */ - screen->animtimer = oldscreen->animtimer; - oldscreen->animtimer = NULL; + ScrArea *toggle_area = area; /* use random area when we have no active one, e.g. when the * mouse is outside of the window and we open a file browser */ - if (!area || area->global) { - area = oldscreen->areabase.first; + if (!toggle_area || toggle_area->global) { + bScreen *oldscreen = WM_window_get_active_screen(win); + toggle_area = oldscreen->areabase.first; } - newa = (ScrArea *)screen->areabase.first; - - /* copy area */ - ED_area_data_swap(newa, area); - newa->flag = area->flag; /* mostly for AREA_FLAG_WASFULLSCREEN */ - - if (state == SCREENFULL) { - /* temporarily hide global areas */ - LISTBASE_FOREACH (ScrArea *, glob_area, &win->global_areas.areabase) { - glob_area->global->flag |= GLOBAL_AREA_IS_HIDDEN; - } - /* temporarily hide the side panels/header */ - LISTBASE_FOREACH (ARegion *, region, &newa->regionbase) { - region->flagfullscreen = region->flag; - - if (ELEM(region->regiontype, - RGN_TYPE_UI, - RGN_TYPE_HEADER, - RGN_TYPE_TOOL_HEADER, - RGN_TYPE_FOOTER, - RGN_TYPE_TOOLS, - RGN_TYPE_NAV_BAR, - RGN_TYPE_EXECUTE)) { - region->flag |= RGN_FLAG_HIDDEN; - } - } - } - - area->full = oldscreen; - newa->full = oldscreen; - - ED_screen_change(C, screen); - ED_area_tag_refresh(newa); + screen = screen_state_to_nonnormal(C, win, toggle_area, state); } /* XXX bad code: setscreen() ends with first area active. fullscreen render assumes this too */ @@ -1413,9 +1449,6 @@ ScrArea *ED_screen_temp_space_open(bContext *C, area->flag |= AREA_FLAG_STACKED_FULLSCREEN; ((SpaceLink *)area->spacedata.first)->link_flag |= SPACE_FLAG_TYPE_TEMPORARY; } - else if (ctx_area != NULL && ctx_area->spacetype == space_type) { - area = ED_screen_state_toggle(C, CTX_wm_window(C), ctx_area, SCREENMAXIMIZED); - } else { area = ED_screen_full_newspace(C, ctx_area, (int)space_type); ((SpaceLink *)area->spacedata.first)->link_flag |= SPACE_FLAG_TYPE_TEMPORARY; -- cgit v1.2.3 From 7e8f6985d89866197be8465a8aec57f9b4ef7b51 Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Tue, 15 Dec 2020 21:27:59 +0100 Subject: Fix crash selecting custom asset preview from maximized File Browser If Preferences > Interface > Temporary Editors > File Browser is set to "Maximized Area", "Load Custom Preview" in the Asset Browser would crash after selecting the file. 1e799dd26ec1e848 was important to get this issue fixed. This commit just ensures the file-list is recreated correctly after closing the temporary File Browser, so the custom preview operator can execute on valid context. --- source/blender/windowmanager/intern/wm_event_system.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index ac27862d507..61624ad9d7c 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -2293,6 +2293,11 @@ static int wm_handler_fileselect_do(bContext *C, } wm_handler_op_context(C, handler, ctx_win->eventstate); + ScrArea *handler_area = CTX_wm_area(C); + /* Make sure new context area is ready, the operator callback may operate on it. */ + if (handler_area) { + ED_area_do_refresh(C, handler_area); + } /* Needed for #UI_popup_menu_reports. */ -- cgit v1.2.3 From 9e4a4c2e996c3741c2beaf5ed5aadc8cb8801ac3 Mon Sep 17 00:00:00 2001 From: Richard Antalik Date: Tue, 15 Dec 2020 21:42:06 +0100 Subject: VSE: Move remove gaps operator logic to module code Logic was broken into finding gaps and ofsetting strips. Functions were modified so they work on explicitly defined seqbase, so they can be used as python API functions. Functional changes: - Improve performance by calculating gap length and offseting strips at once. Previously strips were offset by one frame. - Calculate gap from start frame. Previously gap was considered only inbetween strips. Reviewed By: sergey Differential Revision: https://developer.blender.org/D9730 --- .../editors/space_sequencer/sequencer_draw.c | 2 +- .../editors/space_sequencer/sequencer_edit.c | 116 ++------------------- .../editors/space_sequencer/sequencer_intern.h | 1 - .../editors/space_sequencer/sequencer_view.c | 8 +- source/blender/sequencer/SEQ_sequencer.h | 29 +++++- source/blender/sequencer/intern/render.c | 17 +-- source/blender/sequencer/intern/strip_edit.c | 35 +++++++ source/blender/sequencer/intern/strip_time.c | 84 +++++++++++++++ source/blender/sequencer/intern/strip_time.h | 12 +++ source/blender/sequencer/intern/strip_transform.c | 30 ++++++ 10 files changed, 212 insertions(+), 122 deletions(-) diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c index 081714991ff..e31fa3205ba 100644 --- a/source/blender/editors/space_sequencer/sequencer_draw.c +++ b/source/blender/editors/space_sequencer/sequencer_draw.c @@ -2292,7 +2292,7 @@ void draw_timeline_seq(const bContext *C, ARegion *region) UI_view2d_view_ortho(v2d); /* Get timeline bound-box, needed for the scroll-bars. */ - boundbox_seq(scene, &v2d->tot); + SEQ_timeline_boundbox(scene, ed->seqbasep, &v2d->tot); draw_seq_backdrop(v2d); UI_view2d_constant_grid_draw(v2d, FPS); diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c index 953a77d22a6..184f821d411 100644 --- a/source/blender/editors/space_sequencer/sequencer_edit.c +++ b/source/blender/editors/space_sequencer/sequencer_edit.c @@ -183,117 +183,13 @@ bool sequencer_view_strips_poll(bContext *C) /** \name Remove Gaps Operator * \{ */ -static bool sequence_offset_after_frame(Scene *scene, const int delta, const int timeline_frame) -{ - Sequence *seq; - Editing *ed = BKE_sequencer_editing_get(scene, false); - bool done = false; - TimeMarker *marker; - - /* All strips >= timeline_frame are shifted. */ - - if (ed == NULL) { - return 0; - } - - for (seq = ed->seqbasep->first; seq; seq = seq->next) { - if (seq->startdisp >= timeline_frame) { - BKE_sequence_translate(scene, seq, delta); - BKE_sequence_calc(scene, seq); - BKE_sequence_invalidate_cache_preprocessed(scene, seq); - done = true; - } - } - - if (!scene->toolsettings->lock_markers) { - for (marker = scene->markers.first; marker; marker = marker->next) { - if (marker->frame >= timeline_frame) { - marker->frame += delta; - } - } - } - - return done; -} - -void boundbox_seq(Scene *scene, rctf *rect) -{ - Sequence *seq; - Editing *ed = BKE_sequencer_editing_get(scene, false); - float min[2], max[2]; - - if (ed == NULL) { - return; - } - - min[0] = SFRA; - max[0] = EFRA + 1; - min[1] = 0.0; - max[1] = 8.0; - - seq = ed->seqbasep->first; - while (seq) { - - if (min[0] > seq->startdisp - 1) { - min[0] = seq->startdisp - 1; - } - if (max[0] < seq->enddisp + 1) { - max[0] = seq->enddisp + 1; - } - if (max[1] < seq->machine + 2) { - max[1] = seq->machine + 2; - } - - seq = seq->next; - } - - rect->xmin = min[0]; - rect->xmax = max[0]; - rect->ymin = min[1]; - rect->ymax = max[1]; -} - static int sequencer_gap_remove_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); - rctf rectf; - int timeline_frame, efra, sfra; - bool first = false, done; - bool do_all = RNA_boolean_get(op->ptr, "all"); - - /* Get first and last frame. */ - boundbox_seq(scene, &rectf); - sfra = (int)rectf.xmin; - efra = (int)rectf.xmax; - - /* Check if the current frame has a gap already. */ - for (timeline_frame = CFRA; timeline_frame >= sfra; timeline_frame--) { - if (SEQ_render_evaluate_frame(scene, timeline_frame)) { - first = true; - break; - } - } + const bool do_all = RNA_boolean_get(op->ptr, "all"); + const Editing *ed = BKE_sequencer_editing_get(scene, false); - for (; timeline_frame < efra; timeline_frame++) { - /* There's still no strip to remove a gap for. */ - if (first == false) { - if (SEQ_render_evaluate_frame(scene, timeline_frame)) { - first = true; - } - } - else if (SEQ_render_evaluate_frame(scene, timeline_frame) == 0) { - done = true; - while (SEQ_render_evaluate_frame(scene, timeline_frame) == 0) { - done = sequence_offset_after_frame(scene, -1, timeline_frame); - if (done == false) { - break; - } - } - if (done == false || do_all == false) { - break; - } - } - } + SEQ_edit_remove_gaps(scene, ed->seqbasep, CFRA, do_all); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); @@ -330,9 +226,9 @@ void SEQUENCER_OT_gap_remove(struct wmOperatorType *ot) static int sequencer_gap_insert_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); - int frames = RNA_int_get(op->ptr, "frames"); - - sequence_offset_after_frame(scene, frames, CFRA); + const int frames = RNA_int_get(op->ptr, "frames"); + const Editing *ed = BKE_sequencer_editing_get(scene, false); + SEQ_offset_after_frame(scene, ed->seqbasep, frames, CFRA); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); diff --git a/source/blender/editors/space_sequencer/sequencer_intern.h b/source/blender/editors/space_sequencer/sequencer_intern.h index 1ea4fb05d53..6ccfd3a9045 100644 --- a/source/blender/editors/space_sequencer/sequencer_intern.h +++ b/source/blender/editors/space_sequencer/sequencer_intern.h @@ -71,7 +71,6 @@ struct ImBuf *sequencer_ibuf_get(struct Main *bmain, /* sequencer_edit.c */ struct View2D; void seq_rectf(struct Sequence *seq, struct rctf *rectf); -void boundbox_seq(struct Scene *scene, struct rctf *rect); struct Sequence *find_nearest_seq(struct Scene *scene, struct View2D *v2d, int *hand, diff --git a/source/blender/editors/space_sequencer/sequencer_view.c b/source/blender/editors/space_sequencer/sequencer_view.c index 75d92d5f00d..d2166705943 100644 --- a/source/blender/editors/space_sequencer/sequencer_view.c +++ b/source/blender/editors/space_sequencer/sequencer_view.c @@ -87,8 +87,14 @@ static int sequencer_view_all_exec(bContext *C, wmOperator *op) rctf box; const int smooth_viewtx = WM_operator_smooth_viewtx_get(op); + Scene *scene = CTX_data_scene(C); + const Editing *ed = BKE_sequencer_editing_get(scene, false); + + if (ed == NULL) { + return OPERATOR_FINISHED; + } - boundbox_seq(CTX_data_scene(C), &box); + SEQ_timeline_boundbox(scene, ed->seqbasep, &box); UI_view2d_smooth_view(C, region, &box, smooth_viewtx); return OPERATOR_FINISHED; } diff --git a/source/blender/sequencer/SEQ_sequencer.h b/source/blender/sequencer/SEQ_sequencer.h index 11e213d842d..a024d5e10d3 100644 --- a/source/blender/sequencer/SEQ_sequencer.h +++ b/source/blender/sequencer/SEQ_sequencer.h @@ -161,7 +161,7 @@ void SEQ_render_new_render_data(struct Main *bmain, int preview_render_size, int for_render, SeqRenderData *r_context); -int SEQ_render_evaluate_frame(struct Scene *scene, int timeline_frame); +int SEQ_render_evaluate_frame(struct ListBase *seqbase, int timeline_frame); struct StripElem *SEQ_render_give_stripelem(struct Sequence *seq, int timeline_frame); /* ********************************************************************** @@ -595,6 +595,33 @@ struct Sequence *SEQ_edit_strip_split(struct Main *bmain, struct Sequence *seq, const int timeline_frame, const eSeqSplitMethod method); +bool SEQ_edit_remove_gaps(struct Scene *scene, + struct ListBase *seqbase, + const int initial_frame, + const bool remove_all_gaps); + +/* ********************************************************************** + * strip_time.c + * + * Editing functions + * ********************************************************************** + */ + +void SEQ_timeline_boundbox(const struct Scene *scene, + const struct ListBase *seqbase, + struct rctf *rect); + +/* ********************************************************************** + * strip_transform.c + * + * Editing functions + * ********************************************************************** + */ + +void SEQ_offset_after_frame(struct Scene *scene, + struct ListBase *seqbase, + const int delta, + const int timeline_frame); #ifdef __cplusplus } diff --git a/source/blender/sequencer/intern/render.c b/source/blender/sequencer/intern/render.c index 008ea1cd3a0..155258dc2c3 100644 --- a/source/blender/sequencer/intern/render.c +++ b/source/blender/sequencer/intern/render.c @@ -337,16 +337,17 @@ static int evaluate_seq_frame_gen(Sequence **seq_arr, return totseq; } -int SEQ_render_evaluate_frame(Scene *scene, int timeline_frame) +/** + * Count number of strips in timeline at timeline_frame + * + * \param seqbase: ListBase in which strips are located + * \param timeline_frame: frame on timeline from where gaps are searched for + * \return number of strips + */ +int SEQ_render_evaluate_frame(ListBase *seqbase, int timeline_frame) { - Editing *ed = BKE_sequencer_editing_get(scene, false); Sequence *seq_arr[MAXSEQ + 1]; - - if (ed == NULL) { - return 0; - } - - return evaluate_seq_frame_gen(seq_arr, ed->seqbasep, timeline_frame, 0); + return evaluate_seq_frame_gen(seq_arr, seqbase, timeline_frame, 0); } static bool video_seq_is_rendered(Sequence *seq) diff --git a/source/blender/sequencer/intern/strip_edit.c b/source/blender/sequencer/intern/strip_edit.c index 3137a471470..a29810cc9ee 100644 --- a/source/blender/sequencer/intern/strip_edit.c +++ b/source/blender/sequencer/intern/strip_edit.c @@ -38,6 +38,8 @@ #include "BKE_scene.h" #include "BKE_sound.h" +#include "strip_time.h" + #include "SEQ_sequencer.h" int BKE_sequence_swap(Sequence *seq_a, Sequence *seq_b, const char **error_str) @@ -319,3 +321,36 @@ Sequence *SEQ_edit_strip_split(Main *bmain, BKE_sequence_calc(scene, right_seq); return right_seq; } + +/** + * Find gap after initial_frame and move strips on right side to close the gap + * + * \param scene: Scene in which strips are located + * \param seqbase: ListBase in which strips are located + * \param initial_frame: frame on timeline from where gaps are searched for + * \param remove_all_gaps: remove all gaps instead of one gap + * \return true if gap is removed, otherwise false + */ +bool SEQ_edit_remove_gaps(Scene *scene, + ListBase *seqbase, + const int initial_frame, + const bool remove_all_gaps) +{ + GapInfo gap_info = {0}; + seq_time_gap_info_get(scene, seqbase, initial_frame, &gap_info); + + if (!gap_info.gap_exists) { + return false; + } + + if (remove_all_gaps) { + while (gap_info.gap_exists) { + SEQ_offset_after_frame(scene, seqbase, -gap_info.gap_length, gap_info.gap_start_frame); + seq_time_gap_info_get(scene, seqbase, initial_frame, &gap_info); + } + } + else { + SEQ_offset_after_frame(scene, seqbase, -gap_info.gap_length, gap_info.gap_start_frame); + } + return true; +} diff --git a/source/blender/sequencer/intern/strip_time.c b/source/blender/sequencer/intern/strip_time.c index a0ae6d6f16d..015d81cc217 100644 --- a/source/blender/sequencer/intern/strip_time.c +++ b/source/blender/sequencer/intern/strip_time.c @@ -351,3 +351,87 @@ float BKE_sequence_get_fps(Scene *scene, Sequence *seq) } return 0.0f; } + +/** + * Define boundary rectangle of sequencer timeline and fill in rect data + * + * \param scene: Scene in which strips are located + * \param seqbase: ListBase in which strips are located + * \param rect: data structure describing rectangle, that will be filled in by this function + */ +void SEQ_timeline_boundbox(const Scene *scene, const ListBase *seqbase, rctf *rect) +{ + float min[2], max[2]; + min[0] = scene->r.sfra; + max[0] = scene->r.efra + 1; + min[1] = 0.0; + max[1] = 8.0; + + LISTBASE_FOREACH (Sequence *, seq, seqbase) { + if (min[0] > seq->startdisp - 1) { + min[0] = seq->startdisp - 1; + } + if (max[0] < seq->enddisp + 1) { + max[0] = seq->enddisp + 1; + } + if (max[1] < seq->machine + 2) { + max[1] = seq->machine + 2; + } + } + + rect->xmin = min[0]; + rect->xmax = max[0]; + rect->ymin = min[1]; + rect->ymax = max[1]; +} + +/** + * Find first gap between strips after initial_frame and describe it by filling data of r_gap_info + * + * \param scene: Scene in which strips are located + * \param seqbase: ListBase in which strips are located + * \param initial_frame: frame on timeline from where gaps are searched for + * \param r_gap_info: data structure describing gap, that will be filled in by this function + */ +void seq_time_gap_info_get(const Scene *scene, + ListBase *seqbase, + const int initial_frame, + GapInfo *r_gap_info) +{ + rctf rectf; + /* Get first and last frame. */ + SEQ_timeline_boundbox(scene, seqbase, &rectf); + const int sfra = (int)rectf.xmin; + const int efra = (int)rectf.xmax; + int timeline_frame = initial_frame; + r_gap_info->gap_exists = false; + + if (SEQ_render_evaluate_frame(seqbase, initial_frame) == 0) { + /* Search backward for gap_start_frame. */ + for (; timeline_frame >= sfra; timeline_frame--) { + if (SEQ_render_evaluate_frame(seqbase, timeline_frame) != 0) { + break; + } + } + r_gap_info->gap_start_frame = timeline_frame + 1; + timeline_frame = initial_frame; + } + else { + /* Search forward for gap_start_frame. */ + for (; timeline_frame <= efra; timeline_frame++) { + if (SEQ_render_evaluate_frame(seqbase, timeline_frame) == 0) { + r_gap_info->gap_start_frame = timeline_frame; + break; + } + } + } + /* Search forward for gap_end_frame. */ + for (; timeline_frame <= efra; timeline_frame++) { + if (SEQ_render_evaluate_frame(seqbase, timeline_frame) != 0) { + const int gap_end_frame = timeline_frame; + r_gap_info->gap_length = gap_end_frame - r_gap_info->gap_start_frame; + r_gap_info->gap_exists = true; + break; + } + } +} diff --git a/source/blender/sequencer/intern/strip_time.h b/source/blender/sequencer/intern/strip_time.h index e4fb7f1d2ec..e435ff1ec5d 100644 --- a/source/blender/sequencer/intern/strip_time.h +++ b/source/blender/sequencer/intern/strip_time.h @@ -29,10 +29,22 @@ extern "C" { struct Scene; struct Sequence; +struct ListBase; float seq_give_frame_index(struct Sequence *seq, float timeline_frame); void seq_update_sound_bounds_recursive(struct Scene *scene, struct Sequence *metaseq); +/* Describes gap between strips in timeline. */ +typedef struct GapInfo { + int gap_start_frame; /* Start frame of the gap. */ + int gap_length; /* Length of the gap. */ + bool gap_exists; /* False if there are no gaps. */ +} GapInfo; +void seq_time_gap_info_get(const struct Scene *scene, + struct ListBase *seqbase, + const int initial_frame, + struct GapInfo *r_gap_info); + #ifdef __cplusplus } #endif diff --git a/source/blender/sequencer/intern/strip_transform.c b/source/blender/sequencer/intern/strip_transform.c index 233f8e5b22e..4aabe87bce1 100644 --- a/source/blender/sequencer/intern/strip_transform.c +++ b/source/blender/sequencer/intern/strip_transform.c @@ -397,3 +397,33 @@ bool BKE_sequence_base_shuffle_time(ListBase *seqbasep, return offset ? false : true; } + +/** + * Move strips and markers (if not locked) that start after timeline_frame by delta frames + * + * \param scene: Scene in which strips are located + * \param seqbase: ListBase in which strips are located + * \param delta: offset in frames to be applied + * \param timeline_frame: frame on timeline from where strips are moved + */ +void SEQ_offset_after_frame(Scene *scene, + ListBase *seqbase, + const int delta, + const int timeline_frame) +{ + LISTBASE_FOREACH (Sequence *, seq, seqbase) { + if (seq->startdisp >= timeline_frame) { + BKE_sequence_translate(scene, seq, delta); + BKE_sequence_calc(scene, seq); + BKE_sequence_invalidate_cache_preprocessed(scene, seq); + } + } + + if (!scene->toolsettings->lock_markers) { + LISTBASE_FOREACH (TimeMarker *, marker, &scene->markers) { + if (marker->frame >= timeline_frame) { + marker->frame += delta; + } + } + } +} -- cgit v1.2.3 From 5535b0b8878a84325b0f99ad10260e95433facc7 Mon Sep 17 00:00:00 2001 From: Cody Winchester Date: Tue, 15 Dec 2020 22:14:05 +0100 Subject: GPencil Array - Add option for uniform random scaling This patch adds the option to make the random scaling from the grease pencil array modifier uniform. The current settings allow a separate value for each of the 3 scaling axis. The modifier also creates different seed values for each axis so there is no way to keep the random scaling uniform. This patch creates 1 random seed value and applies it to each of the scaling axis. Here is a demonstration of the previous behavior and the new optional behavior. {F9485973} {F9485981} {F9485798} Reviewed By: #grease_pencil, antoniov, pepeland Differential Revision: https://developer.blender.org/D9764 --- .../blender/gpencil_modifiers/intern/MOD_gpencilarray.c | 15 ++++++++++++--- source/blender/makesdna/DNA_gpencil_modifier_types.h | 1 + source/blender/makesrna/intern/rna_gpencil_modifier.c | 5 +++++ 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c index aa21bf192c4..0b8f150aba4 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c @@ -237,9 +237,17 @@ static void generate_geometry(GpencilModifierData *md, /* To ensure a nice distribution, we use halton sequence and offset using the seed. */ BLI_halton_3d(primes, offset, x, r); - for (int i = 0; i < 3; i++) { - rand[j][i] = fmodf(r[i] * 2.0 - 1.0 + rand_offset, 1.0f); - rand[j][i] = fmodf(sin(rand[j][i] * 12.9898 + j * 78.233) * 43758.5453, 1.0f); + if ((mmd->flag & GP_ARRAY_UNIFORM_RANDOM_SCALE) && j == 2) { + float rand_value; + rand_value = fmodf(r[0] * 2.0 - 1.0 + rand_offset, 1.0f); + rand_value = fmodf(sin(rand_value * 12.9898 + j * 78.233) * 43758.5453, 1.0f); + copy_v3_fl(rand[j] , rand_value); + } + else { + for (int i = 0; i < 3; i++) { + rand[j][i] = fmodf(r[i] * 2.0 - 1.0 + rand_offset, 1.0f); + rand[j][i] = fmodf(sin(rand[j][i] * 12.9898 + j * 78.233) * 43758.5453, 1.0f); + } } } /* Calculate Random matrix. */ @@ -425,6 +433,7 @@ static void random_panel_draw(const bContext *UNUSED(C), Panel *panel) uiItemR(layout, ptr, "random_offset", 0, IFACE_("Offset"), ICON_NONE); uiItemR(layout, ptr, "random_rotation", 0, IFACE_("Rotation"), ICON_NONE); uiItemR(layout, ptr, "random_scale", 0, IFACE_("Scale"), ICON_NONE); + uiItemR(layout, ptr, "use_uniform_random_scale", 0, NULL, ICON_NONE); uiItemR(layout, ptr, "seed", 0, NULL, ICON_NONE); } diff --git a/source/blender/makesdna/DNA_gpencil_modifier_types.h b/source/blender/makesdna/DNA_gpencil_modifier_types.h index bd5afc457ac..9ac40495887 100644 --- a/source/blender/makesdna/DNA_gpencil_modifier_types.h +++ b/source/blender/makesdna/DNA_gpencil_modifier_types.h @@ -351,6 +351,7 @@ typedef enum eArrayGpencil_Flag { GP_ARRAY_USE_OFFSET = (1 << 7), GP_ARRAY_USE_RELATIVE = (1 << 8), GP_ARRAY_USE_OB_OFFSET = (1 << 9), + GP_ARRAY_UNIFORM_RANDOM_SCALE = (1 << 10), } eArrayGpencil_Flag; typedef struct BuildGpencilModifierData { diff --git a/source/blender/makesrna/intern/rna_gpencil_modifier.c b/source/blender/makesrna/intern/rna_gpencil_modifier.c index 5f131de6a40..f0660392eaf 100644 --- a/source/blender/makesrna/intern/rna_gpencil_modifier.c +++ b/source/blender/makesrna/intern/rna_gpencil_modifier.c @@ -1560,6 +1560,11 @@ static void rna_def_modifier_gpencilarray(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_ARRAY_USE_RELATIVE); RNA_def_property_ui_text(prop, "Shift", "Enable shift"); RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); + + prop = RNA_def_property(srna, "use_uniform_random_scale", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_ARRAY_UNIFORM_RANDOM_SCALE); + RNA_def_property_ui_text(prop, "Uniform Scale", "Use the same random seed for each scale axis for a uniform scale"); + RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); } static void rna_def_modifier_gpencilbuild(BlenderRNA *brna) -- cgit v1.2.3 From 151e847b8709c44a731f3d07c9a50139d728e227 Mon Sep 17 00:00:00 2001 From: Falk David Date: Tue, 15 Dec 2020 22:28:28 +0100 Subject: GPencil: Improve interpolation of strokes with unequal lengths Use the BKE_gpencil_stroke_uniform_subdivide function to subdivide strokes before interpolation. When the target/source stroke is smaller than the other stroke, it is subdivided until the lengths match. This improves the overall quality of the interpolation of different sized strokes. Before/After video: {F9511779} Reviewed By: #grease_pencil, antoniov, pepeland, mendio Differential Revision: https://developer.blender.org/D9839 --- .../blender/editors/gpencil/gpencil_interpolate.c | 69 +++++++++++----------- 1 file changed, 34 insertions(+), 35 deletions(-) diff --git a/source/blender/editors/gpencil/gpencil_interpolate.c b/source/blender/editors/gpencil/gpencil_interpolate.c index 3617f20763e..9bca294cf30 100644 --- a/source/blender/editors/gpencil/gpencil_interpolate.c +++ b/source/blender/editors/gpencil/gpencil_interpolate.c @@ -283,8 +283,8 @@ static void gpencil_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi) tgpil = MEM_callocN(sizeof(tGPDinterpolate_layer), "GPencil Interpolate Layer"); tgpil->gpl = gpl; - tgpil->prevFrame = gpl->actframe; - tgpil->nextFrame = gpl->actframe->next; + tgpil->prevFrame = BKE_gpencil_frame_duplicate(gpl->actframe); + tgpil->nextFrame = BKE_gpencil_frame_duplicate(gpl->actframe->next); BLI_addtail(&tgpi->ilayers, tgpil); @@ -326,24 +326,25 @@ static void gpencil_interpolate_set_points(bContext *C, tGPDinterpolate *tgpi) valid = false; } - /* create new stroke */ - new_stroke = BKE_gpencil_stroke_duplicate(gps_from, true, true); - if (valid) { /* if destination stroke is smaller, resize new_stroke to size of gps_to stroke */ if (gps_from->totpoints > gps_to->totpoints) { - new_stroke->points = MEM_recallocN(new_stroke->points, - sizeof(*new_stroke->points) * gps_to->totpoints); - if (new_stroke->dvert != NULL) { - new_stroke->dvert = MEM_recallocN(new_stroke->dvert, - sizeof(*new_stroke->dvert) * gps_to->totpoints); - } - new_stroke->totpoints = gps_to->totpoints; + BKE_gpencil_stroke_uniform_subdivide(gpd, gps_to, gps_from->totpoints, true); } - /* update points position */ + if (gps_to->totpoints > gps_from->totpoints) { + BKE_gpencil_stroke_uniform_subdivide(gpd, gps_from, gps_to->totpoints, true); + } + + /* Create new stroke. */ + new_stroke = BKE_gpencil_stroke_duplicate(gps_from, true, true); + + /* Update points position. */ gpencil_interpolate_update_points(gps_from, gps_to, new_stroke, tgpil->factor); } else { + /* Create new stroke. */ + new_stroke = BKE_gpencil_stroke_duplicate(gps_from, true, true); + /* need an empty stroke to keep index correct for lookup, but resize to smallest size */ new_stroke->totpoints = 0; new_stroke->points = MEM_recallocN(new_stroke->points, sizeof(*new_stroke->points)); @@ -443,12 +444,16 @@ static void gpencil_interpolate_exit(bContext *C, wmOperator *op) /* finally, free memory used by temp data */ LISTBASE_FOREACH (tGPDinterpolate_layer *, tgpil, &tgpi->ilayers) { + BKE_gpencil_free_strokes(tgpil->prevFrame); + BKE_gpencil_free_strokes(tgpil->nextFrame); BKE_gpencil_free_strokes(tgpil->interFrame); - MEM_freeN(tgpil->interFrame); + MEM_SAFE_FREE(tgpil->prevFrame); + MEM_SAFE_FREE(tgpil->nextFrame); + MEM_SAFE_FREE(tgpil->interFrame); } BLI_freelistN(&tgpi->ilayers); - MEM_freeN(tgpi); + MEM_SAFE_FREE(tgpi); } DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, NULL); @@ -992,8 +997,8 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op) } /* store extremes */ - prevFrame = gpl->actframe; - nextFrame = gpl->actframe->next; + prevFrame = BKE_gpencil_frame_duplicate(gpl->actframe); + nextFrame = BKE_gpencil_frame_duplicate(gpl->actframe->next); /* Loop over intermediary frames and create the interpolation */ for (cframe = prevFrame->framenum + step; cframe < nextFrame->framenum; cframe += step) { @@ -1049,28 +1054,17 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op) interFrame->key_type = BEZT_KEYTYPE_BREAKDOWN; } - /* create new stroke */ - bGPDstroke *new_stroke = BKE_gpencil_stroke_duplicate(gps_from, true, true); - /* if destination stroke is smaller, resize new_stroke to size of gps_to stroke */ if (gps_from->totpoints > gps_to->totpoints) { - /* free weights of removed points */ - if (new_stroke->dvert != NULL) { - BKE_defvert_array_free_elems(new_stroke->dvert + gps_to->totpoints, - gps_from->totpoints - gps_to->totpoints); - } - - new_stroke->points = MEM_recallocN(new_stroke->points, - sizeof(*new_stroke->points) * gps_to->totpoints); - - if (new_stroke->dvert != NULL) { - new_stroke->dvert = MEM_recallocN(new_stroke->dvert, - sizeof(*new_stroke->dvert) * gps_to->totpoints); - } - - new_stroke->totpoints = gps_to->totpoints; + BKE_gpencil_stroke_uniform_subdivide(gpd, gps_to, gps_from->totpoints, true); + } + if (gps_to->totpoints > gps_from->totpoints) { + BKE_gpencil_stroke_uniform_subdivide(gpd, gps_from, gps_to->totpoints, true); } + /* create new stroke */ + bGPDstroke *new_stroke = BKE_gpencil_stroke_duplicate(gps_from, true, true); + /* update points position */ gpencil_interpolate_update_points(gps_from, gps_to, new_stroke, factor); @@ -1081,6 +1075,11 @@ static int gpencil_interpolate_seq_exec(bContext *C, wmOperator *op) BLI_addtail(&interFrame->strokes, new_stroke); } } + + BKE_gpencil_free_strokes(prevFrame); + BKE_gpencil_free_strokes(nextFrame); + MEM_SAFE_FREE(prevFrame); + MEM_SAFE_FREE(nextFrame); } /* notifiers */ -- cgit v1.2.3 From dd9d12bf45edac33fb414b9d7e4a0a716b2fa4d0 Mon Sep 17 00:00:00 2001 From: Peter Fog Date: Tue, 15 Dec 2020 22:01:58 +0100 Subject: VSE: Paste strips after playhead by default Paste copied strips after playhead, because this is more intuitive. Previous functionality is still available by enabling "Keep Offset" property, or under shortcut Ctrl+Shift+V. Reviewed By: ISS Differential Revision: https://developer.blender.org/D9734 --- .../keyconfig/keymap_data/blender_default.py | 2 ++ .../editors/space_sequencer/sequencer_edit.c | 26 ++++++++++++++++++++-- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/release/scripts/presets/keyconfig/keymap_data/blender_default.py b/release/scripts/presets/keyconfig/keymap_data/blender_default.py index 5a5957b8bf1..86b2f6f9005 100644 --- a/release/scripts/presets/keyconfig/keymap_data/blender_default.py +++ b/release/scripts/presets/keyconfig/keymap_data/blender_default.py @@ -2501,6 +2501,8 @@ def km_sequencer(params): ("sequencer.delete", {"type": 'DEL', "value": 'PRESS'}, None), ("sequencer.copy", {"type": 'C', "value": 'PRESS', "ctrl": True}, None), ("sequencer.paste", {"type": 'V', "value": 'PRESS', "ctrl": True}, None), + ("sequencer.paste", {"type": 'V', "value": 'PRESS', "ctrl": True, "shift": True}, + {"properties": [("keep_offset", True)]}), ("sequencer.images_separate", {"type": 'Y', "value": 'PRESS'}, None), ("sequencer.meta_toggle", {"type": 'TAB', "value": 'PRESS'}, None), ("sequencer.meta_make", {"type": 'G', "value": 'PRESS', "ctrl": True}, None), diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c index 184f821d411..1e3529a9607 100644 --- a/source/blender/editors/space_sequencer/sequencer_edit.c +++ b/source/blender/editors/space_sequencer/sequencer_edit.c @@ -2527,7 +2527,7 @@ void ED_sequencer_deselect_all(Scene *scene) SEQ_CURRENT_END; } -static int sequencer_paste_exec(bContext *C, wmOperator *UNUSED(op)) +static int sequencer_paste_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); @@ -2536,8 +2536,25 @@ static int sequencer_paste_exec(bContext *C, wmOperator *UNUSED(op)) int ofs; Sequence *iseq, *iseq_first; + if (BLI_listbase_count(&seqbase_clipboard) == 0) { + BKE_report(op->reports, RPT_INFO, "No strips to paste"); + return OPERATOR_CANCELLED; + } + ED_sequencer_deselect_all(scene); - ofs = scene->r.cfra - seqbase_clipboard_frame; + if (RNA_boolean_get(op->ptr, "keep_offset")) { + ofs = scene->r.cfra - seqbase_clipboard_frame; + } + else { + int min_seq_startdisp = INT_MAX; + LISTBASE_FOREACH (Sequence *, seq, &seqbase_clipboard) { + if (seq->startdisp < min_seq_startdisp) { + min_seq_startdisp = seq->startdisp; + } + } + /* Paste strips after playhead. */ + ofs = scene->r.cfra - min_seq_startdisp; + } /* Copy strips, temporarily restoring pointers to actual data-blocks. This * must happen on the clipboard itself, so that copying does user counting @@ -2585,6 +2602,11 @@ void SEQUENCER_OT_paste(wmOperatorType *ot) /* Flags. */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* Properties. */ + PropertyRNA *prop = RNA_def_boolean( + ot->srna, "keep_offset", false, "Keep Offset", "Keep strip offset to playhead when pasting"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); } /** \} */ -- cgit v1.2.3 From f44dea05583889107f640bbf45f546409432303f Mon Sep 17 00:00:00 2001 From: Peter Fog Date: Tue, 15 Dec 2020 22:13:26 +0100 Subject: VSE: Reorder Tools in Sequencer/Preview When in Sequencer/Preview mode, the Sampler was on top, which normally is the place of Select, and Annotation seems to be after Sampler in the bottom in the various editors. Reviewed By: ISS Differential Revision: https://developer.blender.org/D9821 --- release/scripts/startup/bl_ui/space_toolsystem_toolbar.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py index a69e3974193..0411d5c64bc 100644 --- a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py +++ b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py @@ -2903,10 +2903,10 @@ class SEQUENCER_PT_tools_active(ToolSelectPanelHelper, Panel): _defs_sequencer_generic.blade, ], 'SEQUENCER_PREVIEW': [ - _defs_sequencer_generic.sample, *_tools_select, - *_tools_annotate, _defs_sequencer_generic.blade, + _defs_sequencer_generic.sample, + *_tools_annotate, ], } -- cgit v1.2.3 From fad80a95fd08ec87a37f30f0b94a7061d4e382f2 Mon Sep 17 00:00:00 2001 From: Peter Fog Date: Tue, 15 Dec 2020 23:15:32 +0100 Subject: VSE: Add Overlay popover panels Add panels with overlay settings for strips and preview and overlay enable/disable button. Entries from the View menus moved to the overlay panels, which will simplify cluttered View menus. Additional options have been added: - Strip Name - Strip Source(ex. path) - Strip Duration So users can now select what info they need to see on the strips. When No text is displayed, waveforms are drawn in full height. Reviewed By: ISS, HooglyBoogly, pablovazquez Differential Revision: https://developer.blender.org/D9751 --- release/scripts/startup/bl_ui/space_sequencer.py | 113 ++++++-- source/blender/blenkernel/BKE_blender_version.h | 2 +- source/blender/blenloader/intern/versioning_290.c | 39 ++- .../blenloader/intern/versioning_defaults.c | 3 +- .../editors/space_sequencer/sequencer_draw.c | 288 +++++++++++---------- .../editors/space_sequencer/space_sequencer.c | 5 +- source/blender/makesdna/DNA_space_types.h | 4 + source/blender/makesrna/intern/rna_space.c | 22 +- 8 files changed, 306 insertions(+), 170 deletions(-) diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py index 3f92fce81f6..8ef961960ff 100644 --- a/release/scripts/startup/bl_ui/space_sequencer.py +++ b/release/scripts/startup/bl_ui/space_sequencer.py @@ -139,12 +139,11 @@ class SEQUENCER_HT_header(Header): SEQUENCER_MT_editor_menus.draw_collapsible(context, layout) - if st.view_type in {'PREVIEW', 'SEQUENCER_PREVIEW'}: + layout.separator_spacer() - layout.separator_spacer() + if st.view_type in {'PREVIEW', 'SEQUENCER_PREVIEW'}: layout.prop(st, "display_mode", text="", icon_only=True) - layout.prop(st, "preview_channels", text="", icon_only=True) gpd = context.gpencil_data @@ -158,6 +157,13 @@ class SEQUENCER_HT_header(Header): row.prop(tool_settings, "proportional_edit_falloff", icon_only=True) + row = layout.row(align=True) + row.prop(st, "show_strip_overlay", text="", icon='OVERLAY') + sub = row.row(align=True) + sub.popover(panel="SEQUENCER_PT_overlay", text="") + sub.active = st.show_strip_overlay + + class SEQUENCER_MT_editor_menus(Menu): bl_idname = "SEQUENCER_MT_editor_menus" bl_label = "" @@ -176,6 +182,83 @@ class SEQUENCER_MT_editor_menus(Menu): layout.menu("SEQUENCER_MT_strip") +class SEQUENCER_PT_overlay(Panel): + bl_space_type = 'SEQUENCE_EDITOR' + bl_region_type = 'HEADER' + bl_label = "Overlays" + bl_ui_units_x = 7 + + def draw(self, _context): + pass + + +class SEQUENCER_PT_overlay(Panel): + bl_space_type = 'SEQUENCE_EDITOR' + bl_region_type = 'HEADER' + bl_label = "Overlays" + bl_ui_units_x = 7 + + def draw(self, _context): + pass + + +class SEQUENCER_PT_preview_overlay(Panel): + bl_space_type = 'SEQUENCE_EDITOR' + bl_region_type = 'HEADER' + bl_parent_id = 'SEQUENCER_PT_overlay' + bl_label = "Preview Overlays" + + @classmethod + def poll(cls, context): + st = context.space_data + return st.view_type in {'PREVIEW', 'SEQUENCER_PREVIEW'} and st.display_mode == 'IMAGE' + + + def draw(self, context): + ed = context.scene.sequence_editor + st = context.space_data + layout = self.layout + + layout.active = st.show_strip_overlay + layout.prop(ed, "show_overlay", text="Frame Overlay") + layout.prop(st, "show_safe_areas", text="Safe Areas") + layout.prop(st, "show_metadata", text="Metadata") + layout.prop(st, "show_annotation", text="Annotations") + + +class SEQUENCER_PT_sequencer_overlay(Panel): + bl_space_type = 'SEQUENCE_EDITOR' + bl_region_type = 'HEADER' + bl_parent_id = 'SEQUENCER_PT_overlay' + bl_label = "Sequencer Overlays" + + @classmethod + def poll(cls, context): + st = context.space_data + return st.view_type in {'SEQUENCER', 'SEQUENCER_PREVIEW'} + + + def draw(self, context): + st = context.space_data + layout = self.layout + + layout.active = st.show_strip_overlay + + layout.prop(st, "show_strip_name", text="Name") + layout.prop(st, "show_strip_source", text="Source") + layout.prop(st, "show_strip_duration", text="Duration") + + layout.separator() + + layout.prop(st, "show_strip_offset", text="Offsets") + layout.prop(st, "show_fcurves", text="F-Curves") + + layout.separator() + + layout.prop_menu_enum(st, "waveform_display_type") + + + class SEQUENCER_MT_view_cache(Menu): bl_label = "Cache" @@ -294,6 +377,12 @@ class SEQUENCER_MT_view(Menu): layout.operator("view2d.zoom_border", text="Zoom") layout.menu("SEQUENCER_MT_preview_zoom") + if st.display_mode == 'IMAGE': + layout.prop(st, "use_zoom_to_fit") + elif st.display_mode == 'WAVEFORM': + layout.separator() + layout.prop(st, "show_separate_color", text="Show Separate Color Channels") + layout.separator() layout.menu("SEQUENCER_MT_proxy") @@ -318,22 +407,8 @@ class SEQUENCER_MT_view(Menu): layout.separator() layout.prop(st, "show_seconds") - layout.prop(st, "show_strip_offset") - layout.prop(st, "show_fcurves") layout.prop(st, "show_markers") layout.menu("SEQUENCER_MT_view_cache", text="Show Cache") - layout.prop_menu_enum(st, "waveform_display_type", text="Show Waveforms") - - if is_preview: - layout.separator() - if st.display_mode == 'IMAGE': - layout.prop(st, "use_zoom_to_fit") - layout.prop(ed, "show_overlay", text="Show Frame Overlay") - layout.prop(st, "show_safe_areas", text="Show Safe Areas") - layout.prop(st, "show_metadata", text="Show Metadata") - layout.prop(st, "show_annotation", text="Show Annotations") - elif st.display_mode == 'WAVEFORM': - layout.prop(st, "show_separate_color", text="Show Separate Color Channels") layout.separator() @@ -2222,6 +2297,10 @@ classes = ( SEQUENCER_PT_active_tool, SEQUENCER_PT_strip, + SEQUENCER_PT_overlay, + SEQUENCER_PT_preview_overlay, + SEQUENCER_PT_sequencer_overlay, + SEQUENCER_PT_effect, SEQUENCER_PT_scene, SEQUENCER_PT_mask, diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index afb6112b954..ca95ca8bda0 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -39,7 +39,7 @@ extern "C" { /* Blender file format version. */ #define BLENDER_FILE_VERSION BLENDER_VERSION -#define BLENDER_FILE_SUBVERSION 6 +#define BLENDER_FILE_SUBVERSION 7 /* Minimum Blender version that supports reading file written with the current * version. Older Blender versions will test this and show a warning if the file diff --git a/source/blender/blenloader/intern/versioning_290.c b/source/blender/blenloader/intern/versioning_290.c index d00c5225299..685bb762f29 100644 --- a/source/blender/blenloader/intern/versioning_290.c +++ b/source/blender/blenloader/intern/versioning_290.c @@ -1234,18 +1234,7 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain) } } - /** - * Versioning code until next subversion bump goes here. - * - * \note Be sure to check when bumping the version: - * - "versioning_userdef.c", #blo_do_versions_userdef - * - "versioning_userdef.c", #do_versions_theme - * - * \note Keep this message at the bottom of the function. - */ - { - /* Keep this block, even when empty. */ - + if (!MAIN_VERSION_ATLEAST(bmain, 292, 7)) { /* Make all IDProperties used as interface of geometry node trees overridable. */ LISTBASE_FOREACH (Object *, ob, &bmain->objects) { LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) { @@ -1301,5 +1290,31 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain) } } } + + /* Overlay elements in the sequencer. */ + LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) { + LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { + LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) { + if (sl->spacetype == SPACE_SEQ) { + SpaceSeq *sseq = (SpaceSeq *)sl; + sseq->flag |= (SEQ_SHOW_STRIP_OVERLAY | SEQ_SHOW_STRIP_NAME | SEQ_SHOW_STRIP_SOURCE | + SEQ_SHOW_STRIP_DURATION); + } + } + } + } + } + + /** + * Versioning code until next subversion bump goes here. + * + * \note Be sure to check when bumping the version: + * - "versioning_userdef.c", #blo_do_versions_userdef + * - "versioning_userdef.c", #do_versions_theme + * + * \note Keep this message at the bottom of the function. + */ + { + /* Keep this block, even when empty. */ } } diff --git a/source/blender/blenloader/intern/versioning_defaults.c b/source/blender/blenloader/intern/versioning_defaults.c index f89a5be27de..2d75b046366 100644 --- a/source/blender/blenloader/intern/versioning_defaults.c +++ b/source/blender/blenloader/intern/versioning_defaults.c @@ -182,7 +182,8 @@ static void blo_update_defaults_screen(bScreen *screen, } else if (area->spacetype == SPACE_SEQ) { SpaceSeq *seq = area->spacedata.first; - seq->flag |= SEQ_SHOW_MARKERS | SEQ_SHOW_FCURVES | SEQ_ZOOM_TO_FIT; + seq->flag |= SEQ_SHOW_MARKERS | SEQ_SHOW_FCURVES | SEQ_ZOOM_TO_FIT | SEQ_SHOW_STRIP_OVERLAY | + SEQ_SHOW_STRIP_SOURCE | SEQ_SHOW_STRIP_NAME | SEQ_SHOW_STRIP_DURATION; } else if (area->spacetype == SPACE_TEXT) { /* Show syntax and line numbers in Script workspace text editor. */ diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c index e31fa3205ba..ac1b9e6d0a0 100644 --- a/source/blender/editors/space_sequencer/sequencer_draw.c +++ b/source/blender/editors/space_sequencer/sequencer_draw.c @@ -227,16 +227,16 @@ void color3ubv_from_seq(Scene *curscene, Sequence *seq, uchar col[3]) * \param x1, x2, y1, y2: The starting and end X value to draw the wave, same for y1 and y2. * \param stepsize: The width of a pixel. */ -static void draw_seq_waveform(View2D *v2d, - const bContext *C, - SpaceSeq *sseq, - Scene *scene, - Sequence *seq, - float x1, - float y1, - float x2, - float y2, - float stepsize) +static void draw_seq_waveform_overlay(View2D *v2d, + const bContext *C, + SpaceSeq *sseq, + Scene *scene, + Sequence *seq, + float x1, + float y1, + float x2, + float y2, + float stepsize) { /* Offset x1 and x2 values, to match view min/max, if strip is out of bounds. */ int x1_offset = max_ff(v2d->cur.xmin, x1); @@ -603,121 +603,113 @@ static void draw_seq_outline(Sequence *seq, } } -/* Draw info text on a sequence strip. */ -static void draw_seq_text(View2D *v2d, - Sequence *seq, - SpaceSeq *sseq, - float x1, - float x2, - float y1, - float y2, - bool seq_active, - bool y_threshold) +const char *draw_seq_text_get_name(SpaceSeq *sseq, Sequence *seq) { - rctf rect; - char str[32 + FILE_MAX]; - size_t str_len; const char *name = seq->name + 2; - uchar col[4]; - - /* All strings should include name. */ if (name[0] == '\0') { name = BKE_sequence_give_name(seq); } + return name; +} - if (ELEM(seq->type, SEQ_TYPE_META, SEQ_TYPE_ADJUSTMENT)) { - str_len = BLI_snprintf(str, sizeof(str), "%s | %d", name, seq->len); +static void draw_seq_text_get_source(SpaceSeq *sseq, + Sequence *seq, + char *r_source, + size_t source_len) +{ + /* Set source for the most common types. */ + if (ELEM(seq->type, SEQ_TYPE_IMAGE, SEQ_TYPE_MOVIE)) { + BLI_snprintf(r_source, source_len, "%s%s", seq->strip->dir, seq->strip->stripdata->name); } - else if (seq->type == SEQ_TYPE_SCENE) { - if (seq->scene) { - if (seq->scene_camera) { - str_len = BLI_snprintf(str, - sizeof(str), - "%s: %s (%s) | %d", - name, - seq->scene->id.name + 2, - ((ID *)seq->scene_camera)->name + 2, - seq->len); - } - else { - str_len = BLI_snprintf( - str, sizeof(str), "%s: %s | %d", name, seq->scene->id.name + 2, seq->len); - } - } - else { - str_len = BLI_snprintf(str, sizeof(str), "%s | %d", name, seq->len); + else if (seq->type == SEQ_TYPE_SOUND_RAM) { + if (seq->sound) { + BLI_snprintf(r_source, source_len, "%s", seq->sound->filepath); } } - else if (seq->type == SEQ_TYPE_MOVIECLIP) { - if (seq->clip && !STREQ(name, seq->clip->id.name + 2)) { - str_len = BLI_snprintf( - str, sizeof(str), "%s: %s | %d", name, seq->clip->id.name + 2, seq->len); - } - else { - str_len = BLI_snprintf(str, sizeof(str), "%s | %d", name, seq->len); - } + else if (seq->type == SEQ_TYPE_MULTICAM) { + BLI_snprintf(r_source, source_len, "Channel: %d", seq->multicam_source); } - else if (seq->type == SEQ_TYPE_MASK) { - if (seq->mask && !STREQ(name, seq->mask->id.name + 2)) { - str_len = BLI_snprintf( - str, sizeof(str), "%s: %s | %d", name, seq->mask->id.name + 2, seq->len); + else if (seq->type == SEQ_TYPE_TEXT) { + TextVars *textdata = seq->effectdata; + BLI_snprintf(r_source, source_len, "%s", textdata->text); + } + else if (seq->type == SEQ_TYPE_SCENE) { + if (seq->scene_camera) { + BLI_snprintf(r_source, + source_len, + "%s (%s)", + seq->scene->id.name + 2, + ((ID *)seq->scene_camera)->name + 2); } else { - str_len = BLI_snprintf(str, sizeof(str), "%s | %d", name, seq->len); + BLI_snprintf(r_source, source_len, "%s", seq->scene->id.name + 2); } } - else if (seq->type == SEQ_TYPE_MULTICAM) { - str_len = BLI_snprintf(str, sizeof(str), "Cam %s: %d", name, seq->multicam_source); - } - else if (seq->type == SEQ_TYPE_IMAGE) { - str_len = BLI_snprintf(str, - sizeof(str), - "%s: %s%s | %d", - name, - seq->strip->dir, - seq->strip->stripdata->name, - seq->len); + else if (seq->type == SEQ_TYPE_MOVIECLIP) { + BLI_snprintf(r_source, source_len, "%s", seq->clip->id.name + 2); } - else if (seq->type == SEQ_TYPE_TEXT) { - TextVars *textdata = seq->effectdata; - str_len = BLI_snprintf(str, sizeof(str), "%s | %d", textdata->text, seq->startdisp); + else if (seq->type == SEQ_TYPE_MASK) { + BLI_snprintf(r_source, source_len, "%s", seq->mask->id.name + 2); } - else if (seq->type & SEQ_TYPE_EFFECT) { - str_len = BLI_snprintf(str, sizeof(str), "%s | %d", name, seq->len); + else { + *r_source = '\0'; } - else if (seq->type == SEQ_TYPE_SOUND_RAM) { - /* If a waveform is drawn, avoid to draw text when there is not enough vertical space. */ - if (!y_threshold && (sseq->flag & SEQ_NO_WAVEFORMS) == 0 && - ((sseq->flag & SEQ_ALL_WAVEFORMS) || (seq->flag & SEQ_AUDIO_DRAW_WAVEFORM))) { +} - str[0] = 0; - str_len = 0; - } - else if (seq->sound) { - str_len = BLI_snprintf( - str, sizeof(str), "%s: %s | %d", name, seq->sound->filepath, seq->len); +static size_t draw_seq_text_get_overlay_string(SpaceSeq *sseq, + Sequence *seq, + char *r_overlay_string, + size_t overlay_string_len) +{ + const char *name = draw_seq_text_get_name(sseq, seq); + char source[FILE_MAX]; + int strip_duration = seq->enddisp - seq->startdisp; + draw_seq_text_get_source(sseq, seq, source, sizeof(source)); + + bool show_name = sseq->flag & SEQ_SHOW_STRIP_NAME; + bool show_source = (sseq->flag & (SEQ_SHOW_STRIP_SOURCE)) && source[0] != '\0'; + bool show_duration = sseq->flag & SEQ_SHOW_STRIP_DURATION; + + size_t string_len = 0; + if (show_name) { + string_len = BLI_snprintf(r_overlay_string, overlay_string_len, "%s", name); + if (show_source || show_duration) { + string_len += BLI_snprintf(r_overlay_string + string_len, overlay_string_len, " | "); } - else { - str_len = BLI_snprintf(str, sizeof(str), "%s | %d", name, seq->len); + } + if (show_source) { + string_len += BLI_snprintf(r_overlay_string + string_len, overlay_string_len, "%s", source); + if (show_duration) { + string_len += BLI_snprintf(r_overlay_string + string_len, overlay_string_len, " | "); } } - else if (seq->type == SEQ_TYPE_MOVIE) { - str_len = BLI_snprintf(str, - sizeof(str), - "%s: %s%s | %d", - name, - seq->strip->dir, - seq->strip->stripdata->name, - seq->len); + if (show_duration) { + string_len += BLI_snprintf( + r_overlay_string + string_len, overlay_string_len, "%d", strip_duration); } - else { - /* Should never get here!, but might with files from future. */ - BLI_assert(0); + return string_len; +} + +/* Draw info text on a sequence strip. */ +static void draw_seq_text_overlay(View2D *v2d, + Sequence *seq, + SpaceSeq *sseq, + float x1, + float x2, + float y1, + float y2, + bool seq_active) +{ + char overlay_string[FILE_MAX]; + size_t overlay_string_len = draw_seq_text_get_overlay_string( + sseq, seq, overlay_string, sizeof(overlay_string)); - str_len = BLI_snprintf(str, sizeof(str), "%s | %d", name, seq->len); + if (overlay_string_len == 0) { + return; } /* White text for the active strip. */ + uchar col[4]; col[0] = col[1] = col[2] = seq_active ? 255 : 10; col[3] = 255; @@ -731,15 +723,16 @@ static void draw_seq_text(View2D *v2d, } } + rctf rect; rect.xmin = x1; rect.ymin = y1; rect.xmax = x2; rect.ymax = y2; - UI_view2d_text_cache_add_rectf(v2d, &rect, str, str_len, col); + UI_view2d_text_cache_add_rectf(v2d, &rect, overlay_string, overlay_string_len, col); } -static void draw_sequence_extensions(Scene *scene, Sequence *seq, uint pos, float pixely) +static void draw_sequence_extensions_overlay(Scene *scene, Sequence *seq, uint pos, float pixely) { float x1, x2, y1, y2; uchar col[4], blend_col[3]; @@ -988,7 +981,7 @@ static void fcurve_batch_add_verts(GPUVertBuf *vbo, * - Volume for sound strips. * - Opacity for the other types. */ -static void draw_seq_fcurve( +static void draw_seq_fcurve_overlay( Scene *scene, View2D *v2d, Sequence *seq, float x1, float y1, float x2, float y2, float pixelx) { FCurve *fcu; @@ -1085,11 +1078,21 @@ static void draw_seq_strip(const bContext *C, x2 = (seq->endstill) ? (seq->start + seq->len) : seq->enddisp; y2 = seq->machine + SEQ_STRIP_OFSTOP; - /* Calculate height needed for drawing text on strip. */ - float text_margin_y = y2 - min_ff(0.40f, 20 * U.dpi_fac * pixely); + float text_margin_y; + bool y_threshold; + if ((sseq->flag & SEQ_SHOW_STRIP_NAME) || (sseq->flag & SEQ_SHOW_STRIP_SOURCE) || + (sseq->flag & SEQ_SHOW_STRIP_DURATION)) { - /* Is there enough space for drawing something else than text? */ - bool y_threshold = ((y2 - y1) / pixely) > 20 * U.dpi_fac; + /* Calculate height needed for drawing text on strip. */ + text_margin_y = y2 - min_ff(0.40f, 20 * U.dpi_fac * pixely); + + /* Is there enough space for drawing something else than text? */ + y_threshold = ((y2 - y1) / pixely) > 20 * U.dpi_fac; + } + else { + text_margin_y = y2; + y_threshold = 1; + } uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); @@ -1102,12 +1105,13 @@ static void draw_seq_strip(const bContext *C, } /* Draw strip offsets when flag is enabled or during "solo preview". */ - if (!is_single_image && (seq->startofs || seq->endofs) && pixely > 0) { - if ((sseq->draw_flag & SEQ_DRAW_OFFSET_EXT) || (seq == special_seq_update)) { - draw_sequence_extensions(scene, seq, pos, pixely); + if ((sseq->flag & SEQ_SHOW_STRIP_OVERLAY)) { + if (!is_single_image && (seq->startofs || seq->endofs) && pixely > 0) { + if ((sseq->draw_flag & SEQ_DRAW_OFFSET_EXT) || (seq == special_seq_update)) { + draw_sequence_extensions_overlay(scene, seq, pos, pixely); + } } } - immUnbindProgram(); x1 = seq->startdisp; @@ -1118,24 +1122,24 @@ static void draw_seq_strip(const bContext *C, drawmeta_contents(scene, seq, x1, y1, x2, y2); } - if (sseq->flag & SEQ_SHOW_FCURVES) { - draw_seq_fcurve(scene, v2d, seq, x1, y1, x2, y2, pixelx); + if ((sseq->flag & SEQ_SHOW_STRIP_OVERLAY) && (sseq->flag & SEQ_SHOW_FCURVES)) { + draw_seq_fcurve_overlay(scene, v2d, seq, x1, y1, x2, y2, pixelx); } /* Draw sound strip waveform. */ - if ((seq->type == SEQ_TYPE_SOUND_RAM) && (sseq->flag & SEQ_NO_WAVEFORMS) == 0) { - draw_seq_waveform(v2d, - C, - sseq, - scene, - seq, - x1, - y_threshold ? y1 + 0.05f : y1, - x2, - y_threshold ? text_margin_y : y2, - BLI_rctf_size_x(®ion->v2d.cur) / region->winx); + if ((seq->type == SEQ_TYPE_SOUND_RAM) && ((sseq->flag & SEQ_SHOW_STRIP_OVERLAY)) && + (sseq->flag & SEQ_NO_WAVEFORMS) == 0) { + draw_seq_waveform_overlay(v2d, + C, + sseq, + scene, + seq, + x1, + y_threshold ? y1 + 0.05f : y1, + x2, + y_threshold ? text_margin_y : y2, + BLI_rctf_size_x(®ion->v2d.cur) / region->winx); } - /* Draw locked state. */ if (seq->flag & SEQ_LOCK) { draw_seq_locked(x1, y1, x2, y2); @@ -1162,11 +1166,21 @@ static void draw_seq_strip(const bContext *C, calculate_seq_text_offsets(v2d, seq, &x1, &x2, pixelx); - /* Don't draw strip if there is not enough vertical or horizontal space. */ - if (((x2 - x1) > 32 * pixelx * U.dpi_fac) && ((y2 - y1) > 8 * pixely * U.dpi_fac)) { - /* Depending on the vertical space, draw text on top or in the center of strip. */ - draw_seq_text( - v2d, seq, sseq, x1, x2, y_threshold ? text_margin_y : y1, y2, seq_active, y_threshold); + /* If a waveform is drawn, avoid drawing text when there is not enough vertical space. */ + if (seq->type == SEQ_TYPE_SOUND_RAM) { + if (!y_threshold && (sseq->flag & SEQ_NO_WAVEFORMS) == 0 && + ((sseq->flag & SEQ_ALL_WAVEFORMS) || (seq->flag & SEQ_AUDIO_DRAW_WAVEFORM))) { + return; + } + } + + if (sseq->flag & SEQ_SHOW_STRIP_OVERLAY) { + /* Don't draw strip if there is not enough vertical or horizontal space. */ + if (((x2 - x1) > 32 * pixelx * U.dpi_fac) && ((y2 - y1) > 8 * pixely * U.dpi_fac)) { + /* Depending on the vertical space, draw text on top or in the center of strip. */ + draw_seq_text_overlay( + v2d, seq, sseq, x1, x2, y_threshold ? text_margin_y : y1, y2, seq_active); + } } } @@ -1360,7 +1374,7 @@ static void sequencer_display_size(Scene *scene, float r_viewrect[2]) r_viewrect[0] *= scene->r.xasp / scene->r.yasp; } -static void sequencer_draw_gpencil(const bContext *C) +static void sequencer_draw_gpencil_overlay(const bContext *C) { /* Draw grease-pencil (image aligned). */ ED_annotation_draw_2dimage(C); @@ -1373,7 +1387,9 @@ static void sequencer_draw_gpencil(const bContext *C) } /* Draw content and safety borders borders. */ -static void sequencer_draw_borders(const SpaceSeq *sseq, const View2D *v2d, const Scene *scene) +static void sequencer_draw_borders_overlay(const SpaceSeq *sseq, + const View2D *v2d, + const Scene *scene) { float x1 = v2d->tot.xmin; float y1 = v2d->tot.ymin; @@ -1825,17 +1841,17 @@ void sequencer_draw_preview(const bContext *C, C, scene, region, sseq, ibuf, scope, draw_overlay, draw_backdrop); /* Draw over image. */ - if (sseq->flag & SEQ_SHOW_METADATA) { + if (sseq->flag & SEQ_SHOW_METADATA && sseq->flag & SEQ_SHOW_STRIP_OVERLAY) { ED_region_image_metadata_draw(0.0, 0.0, ibuf, &v2d->tot, 1.0, 1.0); } } - if (show_imbuf) { - sequencer_draw_borders(sseq, v2d, scene); + if (show_imbuf && (sseq->flag & SEQ_SHOW_STRIP_OVERLAY)) { + sequencer_draw_borders_overlay(sseq, v2d, scene); } - if (draw_gpencil && show_imbuf) { - sequencer_draw_gpencil(C); + if (draw_gpencil && show_imbuf && (sseq->flag & SEQ_SHOW_STRIP_OVERLAY)) { + sequencer_draw_gpencil_overlay(C); } #if 0 sequencer_draw_maskedit(C, scene, region, sseq); diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c index 45c7bac54f8..64b51b70a12 100644 --- a/source/blender/editors/space_sequencer/space_sequencer.c +++ b/source/blender/editors/space_sequencer/space_sequencer.c @@ -99,7 +99,8 @@ static SpaceLink *sequencer_create(const ScrArea *UNUSED(area), const Scene *sce sseq->view = SEQ_VIEW_SEQUENCE; sseq->mainb = SEQ_DRAW_IMG_IMBUF; sseq->flag = SEQ_SHOW_GPENCIL | SEQ_USE_ALPHA | SEQ_SHOW_MARKERS | SEQ_SHOW_FCURVES | - SEQ_ZOOM_TO_FIT; + SEQ_ZOOM_TO_FIT | SEQ_SHOW_STRIP_OVERLAY | SEQ_SHOW_STRIP_NAME | + SEQ_SHOW_STRIP_SOURCE | SEQ_SHOW_STRIP_DURATION; /* Tool header. */ region = MEM_callocN(sizeof(ARegion), "tool header for sequencer"); @@ -706,7 +707,7 @@ static void sequencer_preview_region_draw(const bContext *C, ARegion *region) SpaceSeq *sseq = area->spacedata.first; Scene *scene = CTX_data_scene(C); wmWindowManager *wm = CTX_wm_manager(C); - const bool draw_overlay = (scene->ed && (scene->ed->over_flag & SEQ_EDIT_OVERLAY_SHOW)); + const bool draw_overlay = (scene->ed && (scene->ed->over_flag & SEQ_EDIT_OVERLAY_SHOW) && (sseq->flag & SEQ_SHOW_STRIP_OVERLAY)); /* XXX temp fix for wrong setting in sseq->mainb */ if (sseq->mainb == SEQ_DRAW_SEQUENCE) { diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index 4161faca386..4276e8b568e 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -621,6 +621,10 @@ typedef enum eSpaceSeq_Flag { SEQ_SHOW_METADATA = (1 << 10), SEQ_SHOW_MARKERS = (1 << 11), /* show markers region */ SEQ_ZOOM_TO_FIT = (1 << 12), + SEQ_SHOW_STRIP_OVERLAY = (1 << 13), + SEQ_SHOW_STRIP_NAME = (1 << 14), + SEQ_SHOW_STRIP_SOURCE = (1 << 15), + SEQ_SHOW_STRIP_DURATION = (1 << 16), } eSpaceSeq_Flag; /* SpaceSeq.view */ diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index 0e779c8cc97..ca12bbbbb7a 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -5176,7 +5176,7 @@ static void rna_def_space_sequencer(BlenderRNA *brna) prop = RNA_def_property(srna, "waveform_display_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_bitflag_sdna(prop, NULL, "flag"); RNA_def_property_enum_items(prop, waveform_type_display_items); - RNA_def_property_ui_text(prop, "Waveform Displaying", "How Waveforms are drawn"); + RNA_def_property_ui_text(prop, "Waveform Display", "How Waveforms are drawn"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL); prop = RNA_def_property(srna, "use_zoom_to_fit", PROP_BOOLEAN, PROP_NONE); @@ -5229,6 +5229,26 @@ static void rna_def_space_sequencer(BlenderRNA *brna) RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_SHOW_FCURVES); RNA_def_property_ui_text(prop, "Show F-Curves", "Display strip opacity/volume curve"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL); + + prop = RNA_def_property(srna, "show_strip_overlay", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_SHOW_STRIP_OVERLAY); + RNA_def_property_ui_text(prop, "Show Overlay", ""); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL); + + prop = RNA_def_property(srna, "show_strip_name", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_SHOW_STRIP_NAME); + RNA_def_property_ui_text(prop, "Show Name", ""); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL); + + prop = RNA_def_property(srna, "show_strip_source", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_SHOW_STRIP_SOURCE); + RNA_def_property_ui_text(prop, "Show Source", "Display path to source file, or name of source datablock"); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL); + + prop = RNA_def_property(srna, "show_strip_duration", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_SHOW_STRIP_DURATION); + RNA_def_property_ui_text(prop, "Show Duration", ""); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL); } static void rna_def_space_text(BlenderRNA *brna) -- cgit v1.2.3 From 977bd7937a07a5cbb269c1cda6e95ef0931a0704 Mon Sep 17 00:00:00 2001 From: Richard Antalik Date: Wed, 16 Dec 2020 00:20:20 +0100 Subject: Fix warnings introduced in previous commit --- source/blender/editors/space_sequencer/sequencer_draw.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c index ac1b9e6d0a0..5ad1e2399f5 100644 --- a/source/blender/editors/space_sequencer/sequencer_draw.c +++ b/source/blender/editors/space_sequencer/sequencer_draw.c @@ -603,7 +603,7 @@ static void draw_seq_outline(Sequence *seq, } } -const char *draw_seq_text_get_name(SpaceSeq *sseq, Sequence *seq) +static const char *draw_seq_text_get_name(Sequence *seq) { const char *name = seq->name + 2; if (name[0] == '\0') { @@ -612,10 +612,7 @@ const char *draw_seq_text_get_name(SpaceSeq *sseq, Sequence *seq) return name; } -static void draw_seq_text_get_source(SpaceSeq *sseq, - Sequence *seq, - char *r_source, - size_t source_len) +static void draw_seq_text_get_source(Sequence *seq, char *r_source, size_t source_len) { /* Set source for the most common types. */ if (ELEM(seq->type, SEQ_TYPE_IMAGE, SEQ_TYPE_MOVIE)) { @@ -661,10 +658,10 @@ static size_t draw_seq_text_get_overlay_string(SpaceSeq *sseq, char *r_overlay_string, size_t overlay_string_len) { - const char *name = draw_seq_text_get_name(sseq, seq); + const char *name = draw_seq_text_get_name(seq); char source[FILE_MAX]; int strip_duration = seq->enddisp - seq->startdisp; - draw_seq_text_get_source(sseq, seq, source, sizeof(source)); + draw_seq_text_get_source(seq, source, sizeof(source)); bool show_name = sseq->flag & SEQ_SHOW_STRIP_NAME; bool show_source = (sseq->flag & (SEQ_SHOW_STRIP_SOURCE)) && source[0] != '\0'; -- cgit v1.2.3 From 87fdb714383326255fa656809d637403b9bb2adb Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 16 Dec 2020 16:12:50 +1100 Subject: Cleanup: use static declarations --- source/blender/editors/space_file/space_file.c | 2 +- source/blender/editors/space_outliner/outliner_context.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c index 09b7e5b348c..d4f6618e82a 100644 --- a/source/blender/editors/space_file/space_file.c +++ b/source/blender/editors/space_file/space_file.c @@ -779,7 +779,7 @@ static void file_space_subtype_item_extend(bContext *UNUSED(C), RNA_enum_items_add(item, totitem, rna_enum_space_file_browse_mode_items); } -const char *file_context_dir[] = {"active_file", "active_id", NULL}; +static const char *file_context_dir[] = {"active_file", "active_id", NULL}; static int /*eContextResult*/ file_context(const bContext *C, const char *member, diff --git a/source/blender/editors/space_outliner/outliner_context.c b/source/blender/editors/space_outliner/outliner_context.c index e7dc2780c37..a314a640e42 100644 --- a/source/blender/editors/space_outliner/outliner_context.c +++ b/source/blender/editors/space_outliner/outliner_context.c @@ -50,7 +50,7 @@ static void outliner_context_selected_ids(const SpaceOutliner *space_outliner, CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION); } -const char *outliner_context_dir[] = {"selected_ids", NULL}; +static const char *outliner_context_dir[] = {"selected_ids", NULL}; int /*eContextResult*/ outliner_context(const bContext *C, const char *member, -- cgit v1.2.3 From 588f107f1155817afe4316549c84ca649be16600 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 16 Dec 2020 16:13:05 +1100 Subject: Cleanup: clang-format --- source/blender/editors/space_sequencer/space_sequencer.c | 3 ++- source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c | 2 +- source/blender/makesrna/intern/rna_gpencil_modifier.c | 3 ++- source/blender/makesrna/intern/rna_space.c | 3 ++- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c index 64b51b70a12..2bf4741e4f5 100644 --- a/source/blender/editors/space_sequencer/space_sequencer.c +++ b/source/blender/editors/space_sequencer/space_sequencer.c @@ -707,7 +707,8 @@ static void sequencer_preview_region_draw(const bContext *C, ARegion *region) SpaceSeq *sseq = area->spacedata.first; Scene *scene = CTX_data_scene(C); wmWindowManager *wm = CTX_wm_manager(C); - const bool draw_overlay = (scene->ed && (scene->ed->over_flag & SEQ_EDIT_OVERLAY_SHOW) && (sseq->flag & SEQ_SHOW_STRIP_OVERLAY)); + const bool draw_overlay = (scene->ed && (scene->ed->over_flag & SEQ_EDIT_OVERLAY_SHOW) && + (sseq->flag & SEQ_SHOW_STRIP_OVERLAY)); /* XXX temp fix for wrong setting in sseq->mainb */ if (sseq->mainb == SEQ_DRAW_SEQUENCE) { diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c b/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c index 0b8f150aba4..b8fa88327fc 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencilarray.c @@ -241,7 +241,7 @@ static void generate_geometry(GpencilModifierData *md, float rand_value; rand_value = fmodf(r[0] * 2.0 - 1.0 + rand_offset, 1.0f); rand_value = fmodf(sin(rand_value * 12.9898 + j * 78.233) * 43758.5453, 1.0f); - copy_v3_fl(rand[j] , rand_value); + copy_v3_fl(rand[j], rand_value); } else { for (int i = 0; i < 3; i++) { diff --git a/source/blender/makesrna/intern/rna_gpencil_modifier.c b/source/blender/makesrna/intern/rna_gpencil_modifier.c index f0660392eaf..89eb989a442 100644 --- a/source/blender/makesrna/intern/rna_gpencil_modifier.c +++ b/source/blender/makesrna/intern/rna_gpencil_modifier.c @@ -1563,7 +1563,8 @@ static void rna_def_modifier_gpencilarray(BlenderRNA *brna) prop = RNA_def_property(srna, "use_uniform_random_scale", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_ARRAY_UNIFORM_RANDOM_SCALE); - RNA_def_property_ui_text(prop, "Uniform Scale", "Use the same random seed for each scale axis for a uniform scale"); + RNA_def_property_ui_text( + prop, "Uniform Scale", "Use the same random seed for each scale axis for a uniform scale"); RNA_def_property_update(prop, 0, "rna_GpencilModifier_update"); } diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index ca12bbbbb7a..7405bc541c9 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -5242,7 +5242,8 @@ static void rna_def_space_sequencer(BlenderRNA *brna) prop = RNA_def_property(srna, "show_strip_source", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", SEQ_SHOW_STRIP_SOURCE); - RNA_def_property_ui_text(prop, "Show Source", "Display path to source file, or name of source datablock"); + RNA_def_property_ui_text( + prop, "Show Source", "Display path to source file, or name of source datablock"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_SEQUENCER, NULL); prop = RNA_def_property(srna, "show_strip_duration", PROP_BOOLEAN, PROP_NONE); -- cgit v1.2.3 From b347c4e9ca896c7f1149502962add1163db1e82c Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 16 Dec 2020 16:19:04 +1100 Subject: Cleanup: remove redundant struct declarations --- source/blender/blenkernel/BKE_animsys.h | 2 -- source/blender/blenkernel/BKE_attribute.h | 1 - source/blender/blenkernel/BKE_attribute_access.hh | 2 -- source/blender/blenkernel/BKE_cryptomatte.h | 1 - source/blender/blenkernel/BKE_editmesh.h | 2 -- source/blender/blenkernel/BKE_gpencil.h | 2 -- source/blender/blenkernel/BKE_gpencil_geom.h | 1 - source/blender/blenkernel/BKE_ipo.h | 1 - source/blender/blenkernel/BKE_lattice.h | 1 - source/blender/blenkernel/BKE_lib_id.h | 1 - source/blender/blenkernel/BKE_lib_remap.h | 2 -- source/blender/blenkernel/BKE_mesh.h | 1 - source/blender/blenkernel/BKE_paint.h | 1 - source/blender/blenkernel/BKE_pbvh.h | 1 - source/blender/blenkernel/BKE_screen.h | 1 - source/blender/blenkernel/BKE_speaker.h | 1 - source/blender/blenkernel/intern/multires_unsubdivide.h | 2 -- source/blender/blenlib/BLI_threads.h | 1 - source/blender/blenloader/intern/readfile.h | 3 --- source/blender/depsgraph/DEG_depsgraph_build.h | 1 - source/blender/depsgraph/intern/builder/deg_builder_relations.h | 1 - source/blender/depsgraph/intern/eval/deg_eval_flush.h | 2 -- source/blender/draw/engines/gpencil/gpencil_engine.h | 3 --- source/blender/draw/engines/image/image_private.h | 2 -- source/blender/draw/intern/DRW_render.h | 1 - source/blender/draw/intern/draw_common.h | 2 -- source/blender/editors/include/ED_armature.h | 1 - source/blender/editors/include/ED_gpencil.h | 1 - source/blender/editors/include/ED_image.h | 2 -- source/blender/editors/include/ED_object.h | 1 - source/blender/editors/include/ED_transform.h | 2 -- source/blender/editors/include/ED_transform_snap_object_context.h | 1 - source/blender/editors/include/ED_util_imbuf.h | 1 - source/blender/editors/include/ED_uvedit.h | 1 - source/blender/editors/include/ED_view3d.h | 5 ----- source/blender/editors/include/UI_interface.h | 1 - source/blender/editors/sculpt_paint/paint_intern.h | 1 - source/blender/editors/sculpt_paint/sculpt_intern.h | 1 - source/blender/editors/space_buttons/buttons_intern.h | 1 - source/blender/editors/space_outliner/tree/tree_element_nla.hh | 1 - source/blender/editors/transform/transform.h | 2 +- source/blender/editors/transform/transform_convert.h | 3 --- source/blender/editors/transform/transform_snap.h | 2 -- source/blender/editors/uvedit/uvedit_intern.h | 1 - source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h | 2 -- source/blender/gpu/GPU_shader.h | 2 -- source/blender/gpu/GPU_texture.h | 8 -------- source/blender/gpu/intern/gpu_codegen.h | 3 --- source/blender/gpu/intern/gpu_node_graph.h | 2 -- source/blender/gpu/intern/gpu_uniform_buffer_private.hh | 2 ++ source/blender/io/alembic/exporter/abc_hierarchy_iterator.h | 1 - source/blender/io/alembic/exporter/abc_writer_abstract.h | 1 - source/blender/io/alembic/exporter/abc_writer_hair.h | 3 --- source/blender/io/alembic/intern/abc_reader_archive.h | 1 - source/blender/io/common/IO_abstract_hierarchy_iterator.h | 2 -- source/blender/io/usd/intern/usd_exporter_context.h | 1 - source/blender/io/usd/intern/usd_hierarchy_iterator.h | 1 - source/blender/io/usd/intern/usd_writer_abstract.h | 1 - source/blender/io/usd/usd.h | 1 - source/blender/makesdna/DNA_mesh_types.h | 2 -- source/blender/makesdna/DNA_object_types.h | 2 -- source/blender/python/BPY_extern.h | 1 - source/blender/sequencer/intern/multiview.h | 7 ------- source/blender/sequencer/intern/prefetch.h | 2 -- source/blender/sequencer/intern/render.h | 1 - source/blender/sequencer/intern/utils.h | 1 - source/blender/windowmanager/wm.h | 1 - 67 files changed, 3 insertions(+), 112 deletions(-) diff --git a/source/blender/blenkernel/BKE_animsys.h b/source/blender/blenkernel/BKE_animsys.h index e812d04c7d1..8d904bd6019 100644 --- a/source/blender/blenkernel/BKE_animsys.h +++ b/source/blender/blenkernel/BKE_animsys.h @@ -45,8 +45,6 @@ struct NlaKeyframingContext; struct PathResolvedRNA; struct PointerRNA; struct PropertyRNA; -struct ReportList; -struct Scene; struct bAction; struct bActionGroup; struct bContext; diff --git a/source/blender/blenkernel/BKE_attribute.h b/source/blender/blenkernel/BKE_attribute.h index 55a841d8fd1..574d9904dc4 100644 --- a/source/blender/blenkernel/BKE_attribute.h +++ b/source/blender/blenkernel/BKE_attribute.h @@ -35,7 +35,6 @@ extern "C" { struct CustomData; struct CustomDataLayer; struct ID; -struct PointerRNA; struct ReportList; /* Attribute.domain */ diff --git a/source/blender/blenkernel/BKE_attribute_access.hh b/source/blender/blenkernel/BKE_attribute_access.hh index c4a704ef385..564e912551a 100644 --- a/source/blender/blenkernel/BKE_attribute_access.hh +++ b/source/blender/blenkernel/BKE_attribute_access.hh @@ -26,8 +26,6 @@ #include "BLI_color.hh" #include "BLI_float3.hh" -struct Mesh; - namespace blender::bke { using fn::CPPType; diff --git a/source/blender/blenkernel/BKE_cryptomatte.h b/source/blender/blenkernel/BKE_cryptomatte.h index 71b15e47203..d984b3824b1 100644 --- a/source/blender/blenkernel/BKE_cryptomatte.h +++ b/source/blender/blenkernel/BKE_cryptomatte.h @@ -31,7 +31,6 @@ extern "C" { struct Object; struct Material; -struct ID; struct Main; uint32_t BKE_cryptomatte_hash(const char *name, int name_len); diff --git a/source/blender/blenkernel/BKE_editmesh.h b/source/blender/blenkernel/BKE_editmesh.h index 0c84ad70845..2fb713a4299 100644 --- a/source/blender/blenkernel/BKE_editmesh.h +++ b/source/blender/blenkernel/BKE_editmesh.h @@ -35,9 +35,7 @@ struct BMLoop; struct BMesh; struct BoundBox; struct Depsgraph; -struct EditMeshData; struct Mesh; -struct MeshStatVis; struct Object; struct Scene; diff --git a/source/blender/blenkernel/BKE_gpencil.h b/source/blender/blenkernel/BKE_gpencil.h index 6dc8d1ef06e..9177931cf9b 100644 --- a/source/blender/blenkernel/BKE_gpencil.h +++ b/source/blender/blenkernel/BKE_gpencil.h @@ -36,7 +36,6 @@ struct ListBase; struct MDeformVert; struct Main; struct Material; -struct MaterialGPencilStyle; struct Object; struct Scene; struct SpaceImage; @@ -46,7 +45,6 @@ struct bDeformGroup; struct bGPDframe; struct bGPDlayer; struct bGPDlayer_Mask; -struct bGPDspoint; struct bGPDstroke; struct bGPDcurve; struct bGPdata; diff --git a/source/blender/blenkernel/BKE_gpencil_geom.h b/source/blender/blenkernel/BKE_gpencil_geom.h index 111f9030463..8cb7137e1f0 100644 --- a/source/blender/blenkernel/BKE_gpencil_geom.h +++ b/source/blender/blenkernel/BKE_gpencil_geom.h @@ -33,7 +33,6 @@ struct Main; struct Object; struct Scene; struct bGPDframe; -struct bGPDlayer; struct bGPDspoint; struct bGPDstroke; struct bGPdata; diff --git a/source/blender/blenkernel/BKE_ipo.h b/source/blender/blenkernel/BKE_ipo.h index 40b9f738bfd..f4871c83caf 100644 --- a/source/blender/blenkernel/BKE_ipo.h +++ b/source/blender/blenkernel/BKE_ipo.h @@ -26,7 +26,6 @@ extern "C" { #endif -struct Ipo; struct Main; void do_versions_ipos_to_animato(struct Main *main); diff --git a/source/blender/blenkernel/BKE_lattice.h b/source/blender/blenkernel/BKE_lattice.h index f4c1a6fdcb4..02fa8b306d3 100644 --- a/source/blender/blenkernel/BKE_lattice.h +++ b/source/blender/blenkernel/BKE_lattice.h @@ -38,7 +38,6 @@ struct Main; struct Mesh; struct Object; struct Scene; -struct bGPDstroke; void BKE_lattice_resize(struct Lattice *lt, int u, int v, int w, struct Object *ltOb); struct Lattice *BKE_lattice_add(struct Main *bmain, const char *name); diff --git a/source/blender/blenkernel/BKE_lib_id.h b/source/blender/blenkernel/BKE_lib_id.h index 9f3536c9314..b0971278dc7 100644 --- a/source/blender/blenkernel/BKE_lib_id.h +++ b/source/blender/blenkernel/BKE_lib_id.h @@ -51,7 +51,6 @@ extern "C" { #endif -struct BlendDataReader; struct BlendWriter; struct GHash; struct ID; diff --git a/source/blender/blenkernel/BKE_lib_remap.h b/source/blender/blenkernel/BKE_lib_remap.h index fb14e340d8b..a8d75213d39 100644 --- a/source/blender/blenkernel/BKE_lib_remap.h +++ b/source/blender/blenkernel/BKE_lib_remap.h @@ -38,8 +38,6 @@ extern "C" { #endif -struct wmWindowManager; - /* BKE_libblock_free, delete are declared in BKE_lib_id.h for convenience. */ /* Also IDRemap->flag. */ diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h index 0f34549a3cd..2d8dc852d7c 100644 --- a/source/blender/blenkernel/BKE_mesh.h +++ b/source/blender/blenkernel/BKE_mesh.h @@ -26,7 +26,6 @@ #include "BLI_utildefines.h" struct BLI_Stack; -struct BMEditMesh; struct BMesh; struct BMeshCreateParams; struct BMeshFromMeshParams; diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h index 0a50dde1874..f679533e1a9 100644 --- a/source/blender/blenkernel/BKE_paint.h +++ b/source/blender/blenkernel/BKE_paint.h @@ -55,7 +55,6 @@ struct Paint; struct PaintCurve; struct Palette; struct PaletteColor; -struct ReportList; struct Scene; struct StrokeCache; struct SubdivCCG; diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h index fd600a41796..0fa44067b16 100644 --- a/source/blender/blenkernel/BKE_pbvh.h +++ b/source/blender/blenkernel/BKE_pbvh.h @@ -48,7 +48,6 @@ struct PBVH; struct PBVHNode; struct SubdivCCG; struct TaskParallelSettings; -struct TaskParallelTLS; typedef struct PBVH PBVH; typedef struct PBVHNode PBVHNode; diff --git a/source/blender/blenkernel/BKE_screen.h b/source/blender/blenkernel/BKE_screen.h index 473a684eaba..7b5df98d148 100644 --- a/source/blender/blenkernel/BKE_screen.h +++ b/source/blender/blenkernel/BKE_screen.h @@ -51,7 +51,6 @@ struct View3D; struct View3DShading; struct WorkSpace; struct bContext; -struct bContextDataResult; struct bScreen; struct uiLayout; struct uiList; diff --git a/source/blender/blenkernel/BKE_speaker.h b/source/blender/blenkernel/BKE_speaker.h index e288c9f3eb4..9defa887d3c 100644 --- a/source/blender/blenkernel/BKE_speaker.h +++ b/source/blender/blenkernel/BKE_speaker.h @@ -26,7 +26,6 @@ extern "C" { #endif struct Main; -struct Speaker; void *BKE_speaker_add(struct Main *bmain, const char *name); diff --git a/source/blender/blenkernel/intern/multires_unsubdivide.h b/source/blender/blenkernel/intern/multires_unsubdivide.h index 39c6da0b6c8..0a03387282f 100644 --- a/source/blender/blenkernel/intern/multires_unsubdivide.h +++ b/source/blender/blenkernel/intern/multires_unsubdivide.h @@ -26,10 +26,8 @@ #include "BLI_sys_types.h" struct BMesh; -struct Depsgraph; struct Mesh; struct MultiresModifierData; -struct Object; typedef struct MultiresUnsubdivideGrid { /* For sanity checks. */ diff --git a/source/blender/blenlib/BLI_threads.h b/source/blender/blenlib/BLI_threads.h index d19b5393aa7..eefde1afefb 100644 --- a/source/blender/blenlib/BLI_threads.h +++ b/source/blender/blenlib/BLI_threads.h @@ -35,7 +35,6 @@ extern "C" { #define BLENDER_MAX_THREADS 1024 struct ListBase; -struct TaskScheduler; /* Threading API */ diff --git a/source/blender/blenloader/intern/readfile.h b/source/blender/blenloader/intern/readfile.h index 3e7cdb30e1f..c724cc32051 100644 --- a/source/blender/blenloader/intern/readfile.h +++ b/source/blender/blenloader/intern/readfile.h @@ -34,16 +34,13 @@ #include "zlib.h" struct BLOCacheStorage; -struct GSet; struct IDNameLib_Map; struct Key; struct MemFile; struct Object; struct OldNewMap; -struct PartEff; struct ReportList; struct UserDef; -struct View3D; typedef struct IDNameLib_Map IDNameLib_Map; diff --git a/source/blender/depsgraph/DEG_depsgraph_build.h b/source/blender/depsgraph/DEG_depsgraph_build.h index f894bdabba4..4e618d8625d 100644 --- a/source/blender/depsgraph/DEG_depsgraph_build.h +++ b/source/blender/depsgraph/DEG_depsgraph_build.h @@ -39,7 +39,6 @@ struct Main; struct Object; struct Scene; struct Simulation; -struct ViewLayer; struct bNodeTree; #include "BLI_sys_types.h" diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.h b/source/blender/depsgraph/intern/builder/deg_builder_relations.h index cbfb51c59a6..5587379089c 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.h @@ -45,7 +45,6 @@ #include "intern/node/deg_node_id.h" #include "intern/node/deg_node_operation.h" -struct Base; struct CacheFile; struct Camera; struct Collection; diff --git a/source/blender/depsgraph/intern/eval/deg_eval_flush.h b/source/blender/depsgraph/intern/eval/deg_eval_flush.h index 1f58c54dbf4..ec661360fdf 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_flush.h +++ b/source/blender/depsgraph/intern/eval/deg_eval_flush.h @@ -25,8 +25,6 @@ #pragma once -struct Main; - namespace blender { namespace deg { diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.h b/source/blender/draw/engines/gpencil/gpencil_engine.h index 04128dc157e..d0bd56b42dd 100644 --- a/source/blender/draw/engines/gpencil/gpencil_engine.h +++ b/source/blender/draw/engines/gpencil/gpencil_engine.h @@ -39,10 +39,7 @@ extern DrawEngineType draw_engine_gpencil_type; struct GPENCIL_Data; struct GPENCIL_StorageList; struct GPUBatch; -struct GPUVertBuf; -struct GPUVertFormat; struct GpencilBatchCache; -struct MaterialGPencilStyle; struct Object; struct RenderEngine; struct RenderLayer; diff --git a/source/blender/draw/engines/image/image_private.h b/source/blender/draw/engines/image/image_private.h index d5821cc5d70..76a94e68da1 100644 --- a/source/blender/draw/engines/image/image_private.h +++ b/source/blender/draw/engines/image/image_private.h @@ -25,11 +25,9 @@ extern "C" { #endif /* Forward declarations */ -struct GPUBatch; struct GPUTexture; struct ImBuf; struct Image; -struct rcti; /* *********** LISTS *********** */ diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h index fbe71900915..4df2ba1e913 100644 --- a/source/blender/draw/intern/DRW_render.h +++ b/source/blender/draw/intern/DRW_render.h @@ -64,7 +64,6 @@ #include "DEG_depsgraph.h" struct GPUBatch; -struct GPUFrameBuffer; struct GPUMaterial; struct GPUShader; struct GPUTexture; diff --git a/source/blender/draw/intern/draw_common.h b/source/blender/draw/intern/draw_common.h index 23dd47d4ab5..a059ac32311 100644 --- a/source/blender/draw/intern/draw_common.h +++ b/source/blender/draw/intern/draw_common.h @@ -22,10 +22,8 @@ #pragma once -struct DRWPass; struct DRWShadingGroup; struct FluidModifierData; -struct GPUMaterial; struct ModifierData; struct Object; struct ParticleSystem; diff --git a/source/blender/editors/include/ED_armature.h b/source/blender/editors/include/ED_armature.h index 3501acd4fdf..0c4576096fb 100644 --- a/source/blender/editors/include/ED_armature.h +++ b/source/blender/editors/include/ED_armature.h @@ -31,7 +31,6 @@ struct Base; struct Bone; struct Depsgraph; struct EditBone; -struct IDProperty; struct ListBase; struct Main; struct Mesh; diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h index be2f714dfe1..1b7caf27ecf 100644 --- a/source/blender/editors/include/ED_gpencil.h +++ b/source/blender/editors/include/ED_gpencil.h @@ -51,7 +51,6 @@ struct ScrArea; struct SnapObjectContext; struct ToolSettings; struct View3D; -struct ViewLayer; struct bContext; struct Material; diff --git a/source/blender/editors/include/ED_image.h b/source/blender/editors/include/ED_image.h index c1d3a17b9b6..b139b0765a3 100644 --- a/source/blender/editors/include/ED_image.h +++ b/source/blender/editors/include/ED_image.h @@ -34,12 +34,10 @@ struct ARegion; struct ImBuf; struct Image; struct ImageUser; -struct LinkNodePair; struct Main; struct ReportList; struct Scene; struct SpaceImage; -struct ViewLayer; struct bContext; struct wmOperator; struct wmWindowManager; diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h index 2e9b711c99a..f9358f62274 100644 --- a/source/blender/editors/include/ED_object.h +++ b/source/blender/editors/include/ED_object.h @@ -53,7 +53,6 @@ struct uiLayout; struct wmKeyConfig; struct wmOperator; struct wmOperatorType; -struct wmWindowManager; /* object_edit.c */ /* context.object */ diff --git a/source/blender/editors/include/ED_transform.h b/source/blender/editors/include/ED_transform.h index 0ea86e006e0..ca3e351a052 100644 --- a/source/blender/editors/include/ED_transform.h +++ b/source/blender/editors/include/ED_transform.h @@ -32,7 +32,6 @@ extern "C" { struct Object; struct bContext; struct wmKeyConfig; -struct wmMsgBus; struct wmOperatorType; void ED_keymap_transform(struct wmKeyConfig *keyconf); @@ -108,7 +107,6 @@ bool calculateTransformCenter(struct bContext *C, struct Object; struct Scene; -struct wmGizmoGroup; struct wmGizmoGroupType; /* UNUSED */ diff --git a/source/blender/editors/include/ED_transform_snap_object_context.h b/source/blender/editors/include/ED_transform_snap_object_context.h index ebaa32941f2..b7174964ef6 100644 --- a/source/blender/editors/include/ED_transform_snap_object_context.h +++ b/source/blender/editors/include/ED_transform_snap_object_context.h @@ -31,7 +31,6 @@ struct BMVert; struct ARegion; struct Depsgraph; struct ListBase; -struct Main; struct Object; struct Scene; struct View3D; diff --git a/source/blender/editors/include/ED_util_imbuf.h b/source/blender/editors/include/ED_util_imbuf.h index d142d3d6425..4bbaa68e849 100644 --- a/source/blender/editors/include/ED_util_imbuf.h +++ b/source/blender/editors/include/ED_util_imbuf.h @@ -31,7 +31,6 @@ extern "C" { #endif struct ARegion; -struct Main; struct bContext; struct wmEvent; struct wmOperator; diff --git a/source/blender/editors/include/ED_uvedit.h b/source/blender/editors/include/ED_uvedit.h index d08bc0b0b3d..4de97411059 100644 --- a/source/blender/editors/include/ED_uvedit.h +++ b/source/blender/editors/include/ED_uvedit.h @@ -33,7 +33,6 @@ struct BMEditMesh; struct BMFace; struct BMLoop; struct BMesh; -struct Depsgraph; struct Image; struct ImageUser; struct Main; diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h index 13687bf0450..a4856845a65 100644 --- a/source/blender/editors/include/ED_view3d.h +++ b/source/blender/editors/include/ED_view3d.h @@ -41,8 +41,6 @@ struct Camera; struct CustomData_MeshMasks; struct Depsgraph; struct EditBone; -struct GPUOffScreen; -struct GPUViewport; struct ID; struct MVert; struct Main; @@ -55,7 +53,6 @@ struct RenderEngineType; struct Scene; struct ScrArea; struct View3D; -struct View3DShading; struct ViewContext; struct ViewLayer; struct bContext; @@ -64,8 +61,6 @@ struct bScreen; struct rctf; struct rcti; struct wmGizmo; -struct wmOperator; -struct wmOperatorType; struct wmWindow; struct wmWindowManager; diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 83e94664c0b..7c128cbf1e6 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -50,7 +50,6 @@ struct PointerRNA; struct PropertyRNA; struct ReportList; struct ResultBLF; -struct ScrArea; struct bContext; struct bContextStore; struct bNode; diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h index 175d98ba9aa..3ca0d853d6a 100644 --- a/source/blender/editors/sculpt_paint/paint_intern.h +++ b/source/blender/editors/sculpt_paint/paint_intern.h @@ -43,7 +43,6 @@ struct wmEvent; struct wmKeyConfig; struct wmOperator; struct wmOperatorType; -struct wmWindowManager; enum ePaintMode; enum ePaintSymmetryFlags; diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h index bd5ba15b493..853b221e92a 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.h +++ b/source/blender/editors/sculpt_paint/sculpt_intern.h @@ -39,7 +39,6 @@ struct AutomaskingCache; struct KeyBlock; struct Object; -struct SculptPoseIKChainSegment; struct SculptUndoNode; struct bContext; diff --git a/source/blender/editors/space_buttons/buttons_intern.h b/source/blender/editors/space_buttons/buttons_intern.h index 0a0846cf216..74e7bc11c26 100644 --- a/source/blender/editors/space_buttons/buttons_intern.h +++ b/source/blender/editors/space_buttons/buttons_intern.h @@ -35,7 +35,6 @@ struct bContext; struct bContextDataResult; struct bNode; struct bNodeTree; -struct uiLayout; struct wmOperatorType; struct SpaceProperties_Runtime { diff --git a/source/blender/editors/space_outliner/tree/tree_element_nla.hh b/source/blender/editors/space_outliner/tree/tree_element_nla.hh index 3ca62b13bd8..c94287ce576 100644 --- a/source/blender/editors/space_outliner/tree/tree_element_nla.hh +++ b/source/blender/editors/space_outliner/tree/tree_element_nla.hh @@ -23,7 +23,6 @@ #include "tree_element.hh" struct NlaTrack; -struct NlaStrip; namespace blender::ed::outliner { diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index 227330e8524..91bf2bf8aac 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -52,12 +52,12 @@ struct SnapObjectContext; struct TransDataContainer; struct TransInfo; struct TransSnap; -struct TransformOrientation; struct ViewLayer; struct bContext; struct wmEvent; struct wmKeyConfig; struct wmKeyMap; +struct wmOperator; struct wmTimer; /** #TransInfo.redraw */ diff --git a/source/blender/editors/transform/transform_convert.h b/source/blender/editors/transform/transform_convert.h index b753572ea7b..59fcd016020 100644 --- a/source/blender/editors/transform/transform_convert.h +++ b/source/blender/editors/transform/transform_convert.h @@ -29,12 +29,9 @@ struct FCurve; struct ListBase; struct Object; struct TransData; -struct TransDataContainer; struct TransDataCurveHandleFlags; struct TransInfo; struct bContext; -struct bKinematicConstraint; -struct bPoseChannel; /* transform_convert.c */ void transform_autoik_update(TransInfo *t, short mode); diff --git a/source/blender/editors/transform/transform_snap.h b/source/blender/editors/transform/transform_snap.h index 5bee572c603..db8ec943bfd 100644 --- a/source/blender/editors/transform/transform_snap.h +++ b/source/blender/editors/transform/transform_snap.h @@ -25,8 +25,6 @@ /* For enum. */ #include "DNA_space_types.h" -struct SnapObjectParams; - bool peelObjectsTransform(struct TransInfo *t, const float mval[2], const bool use_peel_object, diff --git a/source/blender/editors/uvedit/uvedit_intern.h b/source/blender/editors/uvedit/uvedit_intern.h index 306f8a2c561..28567234fab 100644 --- a/source/blender/editors/uvedit/uvedit_intern.h +++ b/source/blender/editors/uvedit/uvedit_intern.h @@ -25,7 +25,6 @@ struct BMFace; struct BMLoop; -struct Image; struct Object; struct Scene; struct SpaceImage; diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h index e5a6d9e6a8f..30e54f44499 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h @@ -23,9 +23,7 @@ #pragma once -struct GHash; struct MDeformVert; -struct Main; struct Material; struct Object; struct bGPDlayer; diff --git a/source/blender/gpu/GPU_shader.h b/source/blender/gpu/GPU_shader.h index 27a7ea1e6a5..55716b584c3 100644 --- a/source/blender/gpu/GPU_shader.h +++ b/source/blender/gpu/GPU_shader.h @@ -27,8 +27,6 @@ extern "C" { #endif -struct GPUTexture; -struct GPUUniformBuf; struct GPUVertBuf; /** Opaque type hidding blender::gpu::Shader */ diff --git a/source/blender/gpu/GPU_texture.h b/source/blender/gpu/GPU_texture.h index e9c081abd22..91119bd05a1 100644 --- a/source/blender/gpu/GPU_texture.h +++ b/source/blender/gpu/GPU_texture.h @@ -28,14 +28,6 @@ #include "GPU_state.h" struct GPUVertBuf; -struct ImBuf; -struct Image; -struct ImageUser; -struct MovieClip; -struct MovieClipUser; -struct PreviewImage; - -struct GPUFrameBuffer; /** Opaque type hiding blender::gpu::Texture. */ typedef struct GPUTexture GPUTexture; diff --git a/source/blender/gpu/intern/gpu_codegen.h b/source/blender/gpu/intern/gpu_codegen.h index 5d130d75d2c..f3d58a55814 100644 --- a/source/blender/gpu/intern/gpu_codegen.h +++ b/source/blender/gpu/intern/gpu_codegen.h @@ -31,10 +31,7 @@ extern "C" { struct GPUMaterial; struct GPUNodeGraph; -struct GPUOutput; struct GPUShader; -struct GSet; -struct ListBase; typedef struct GPUPass { struct GPUPass *next; diff --git a/source/blender/gpu/intern/gpu_node_graph.h b/source/blender/gpu/intern/gpu_node_graph.h index 0ef95d94c0d..929191cff73 100644 --- a/source/blender/gpu/intern/gpu_node_graph.h +++ b/source/blender/gpu/intern/gpu_node_graph.h @@ -33,8 +33,6 @@ struct GPUNode; struct GPUOutput; -struct GPUShader; -struct GPUVertAttrLayers; struct ListBase; typedef enum eGPUDataSource { diff --git a/source/blender/gpu/intern/gpu_uniform_buffer_private.hh b/source/blender/gpu/intern/gpu_uniform_buffer_private.hh index 00d10776864..18ea6d18caf 100644 --- a/source/blender/gpu/intern/gpu_uniform_buffer_private.hh +++ b/source/blender/gpu/intern/gpu_uniform_buffer_private.hh @@ -24,6 +24,8 @@ #include "BLI_sys_types.h" +struct GPUUniformBuf; + namespace blender { namespace gpu { diff --git a/source/blender/io/alembic/exporter/abc_hierarchy_iterator.h b/source/blender/io/alembic/exporter/abc_hierarchy_iterator.h index a0d9257b822..2098b8b2505 100644 --- a/source/blender/io/alembic/exporter/abc_hierarchy_iterator.h +++ b/source/blender/io/alembic/exporter/abc_hierarchy_iterator.h @@ -29,7 +29,6 @@ #include struct Depsgraph; -struct ID; struct Object; namespace blender::io::alembic { diff --git a/source/blender/io/alembic/exporter/abc_writer_abstract.h b/source/blender/io/alembic/exporter/abc_writer_abstract.h index d23e69cf73e..4997e498199 100644 --- a/source/blender/io/alembic/exporter/abc_writer_abstract.h +++ b/source/blender/io/alembic/exporter/abc_writer_abstract.h @@ -29,7 +29,6 @@ #include "DNA_material_types.h" struct IDProperty; -struct Material; struct Object; namespace blender::io::alembic { diff --git a/source/blender/io/alembic/exporter/abc_writer_hair.h b/source/blender/io/alembic/exporter/abc_writer_hair.h index 3759ffa4310..901fd70601f 100644 --- a/source/blender/io/alembic/exporter/abc_writer_hair.h +++ b/source/blender/io/alembic/exporter/abc_writer_hair.h @@ -23,9 +23,6 @@ #include #include -struct ParticleSettings; -struct ParticleSystem; - namespace blender::io::alembic { class ABCHairWriter : public ABCAbstractWriter { diff --git a/source/blender/io/alembic/intern/abc_reader_archive.h b/source/blender/io/alembic/intern/abc_reader_archive.h index 2a4fd6bd8fb..67000194aa1 100644 --- a/source/blender/io/alembic/intern/abc_reader_archive.h +++ b/source/blender/io/alembic/intern/abc_reader_archive.h @@ -28,7 +28,6 @@ #include struct Main; -struct Scene; namespace blender::io::alembic { diff --git a/source/blender/io/common/IO_abstract_hierarchy_iterator.h b/source/blender/io/common/IO_abstract_hierarchy_iterator.h index e066ca8ba8f..300c555ac8f 100644 --- a/source/blender/io/common/IO_abstract_hierarchy_iterator.h +++ b/source/blender/io/common/IO_abstract_hierarchy_iterator.h @@ -43,13 +43,11 @@ #include #include -struct Base; struct Depsgraph; struct DupliObject; struct ID; struct Object; struct ParticleSystem; -struct ViewLayer; namespace blender::io { diff --git a/source/blender/io/usd/intern/usd_exporter_context.h b/source/blender/io/usd/intern/usd_exporter_context.h index 41ff34b327e..66e87f0eed1 100644 --- a/source/blender/io/usd/intern/usd_exporter_context.h +++ b/source/blender/io/usd/intern/usd_exporter_context.h @@ -24,7 +24,6 @@ #include struct Depsgraph; -struct Object; namespace blender::io::usd { diff --git a/source/blender/io/usd/intern/usd_hierarchy_iterator.h b/source/blender/io/usd/intern/usd_hierarchy_iterator.h index 922ab761bd9..cd19becbb07 100644 --- a/source/blender/io/usd/intern/usd_hierarchy_iterator.h +++ b/source/blender/io/usd/intern/usd_hierarchy_iterator.h @@ -28,7 +28,6 @@ #include struct Depsgraph; -struct ID; struct Object; namespace blender::io::usd { diff --git a/source/blender/io/usd/intern/usd_writer_abstract.h b/source/blender/io/usd/intern/usd_writer_abstract.h index 6a3b8d515dc..2143164e3dd 100644 --- a/source/blender/io/usd/intern/usd_writer_abstract.h +++ b/source/blender/io/usd/intern/usd_writer_abstract.h @@ -33,7 +33,6 @@ #include "DNA_material_types.h" struct Material; -struct Object; namespace blender::io::usd { diff --git a/source/blender/io/usd/usd.h b/source/blender/io/usd/usd.h index b9ea90736ff..40e2d0d8674 100644 --- a/source/blender/io/usd/usd.h +++ b/source/blender/io/usd/usd.h @@ -25,7 +25,6 @@ extern "C" { #endif -struct Scene; struct bContext; struct USDExportParams { diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h index 04fbc030ed9..c2337b28e54 100644 --- a/source/blender/makesdna/DNA_mesh_types.h +++ b/source/blender/makesdna/DNA_mesh_types.h @@ -35,7 +35,6 @@ struct AnimData; struct BVHCache; struct Ipo; struct Key; -struct LinkNode; struct MCol; struct MEdge; struct MFace; @@ -44,7 +43,6 @@ struct MLoopCol; struct MLoopTri; struct MLoopUV; struct MPoly; -struct MPropCol; struct MVert; struct Material; struct Mesh; diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h index 0a3a2cd0b64..25447d8f20a 100644 --- a/source/blender/makesdna/DNA_object_types.h +++ b/source/blender/makesdna/DNA_object_types.h @@ -38,9 +38,7 @@ extern "C" { struct AnimData; struct BoundBox; -struct DerivedMesh; struct FluidsimSettings; -struct GpencilBatchCache; struct Ipo; struct Material; struct Mesh; diff --git a/source/blender/python/BPY_extern.h b/source/blender/python/BPY_extern.h index 46b4dbc96d7..366d801a888 100644 --- a/source/blender/python/BPY_extern.h +++ b/source/blender/python/BPY_extern.h @@ -26,7 +26,6 @@ struct ID; /* DNA_ID.h */ struct ListBase; /* DNA_listBase.h */ struct Object; /* DNA_object_types.h */ struct PathResolvedRNA; -struct ReportList; struct Text; /* defined in DNA_text_types.h */ struct bConstraint; /* DNA_constraint_types.h */ struct bConstraintOb; /* DNA_constraint_types.h */ diff --git a/source/blender/sequencer/intern/multiview.h b/source/blender/sequencer/intern/multiview.h index e1f998d18e2..bbc66c6f84c 100644 --- a/source/blender/sequencer/intern/multiview.h +++ b/source/blender/sequencer/intern/multiview.h @@ -27,14 +27,7 @@ extern "C" { #endif -struct Editing; -struct ImBuf; -struct Main; -struct Mask; struct Scene; -struct Sequence; -struct StripColorBalance; -struct StripElem; /* ********************************************************************** * sequencer.c diff --git a/source/blender/sequencer/intern/prefetch.h b/source/blender/sequencer/intern/prefetch.h index aa47a9dbcfc..6b9d936133d 100644 --- a/source/blender/sequencer/intern/prefetch.h +++ b/source/blender/sequencer/intern/prefetch.h @@ -27,8 +27,6 @@ extern "C" { #endif -struct ImBuf; -struct Main; struct Scene; struct Sequence; struct SeqRenderData; diff --git a/source/blender/sequencer/intern/render.h b/source/blender/sequencer/intern/render.h index d5affeb547b..46748415187 100644 --- a/source/blender/sequencer/intern/render.h +++ b/source/blender/sequencer/intern/render.h @@ -27,7 +27,6 @@ extern "C" { #endif -struct Editing; struct ImBuf; struct ListBase; struct Scene; diff --git a/source/blender/sequencer/intern/utils.h b/source/blender/sequencer/intern/utils.h index fe6041ec5e8..f30ea753d37 100644 --- a/source/blender/sequencer/intern/utils.h +++ b/source/blender/sequencer/intern/utils.h @@ -28,7 +28,6 @@ extern "C" { #endif struct Scene; -struct anim; bool sequencer_seq_generates_image(struct Sequence *seq); void seq_open_anim_file(struct Scene *scene, struct Sequence *seq, bool openfile); diff --git a/source/blender/windowmanager/wm.h b/source/blender/windowmanager/wm.h index baa47098bd3..c26acfc9802 100644 --- a/source/blender/windowmanager/wm.h +++ b/source/blender/windowmanager/wm.h @@ -23,7 +23,6 @@ #pragma once -struct ARegion; struct ReportList; struct wmWindow; -- cgit v1.2.3 From a869a61c88e37ce8a16676162ef7db3c62449b46 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 16 Dec 2020 16:26:23 +1100 Subject: Cleanup: sort struct blocks --- source/blender/blenkernel/BKE_action.h | 4 ++-- source/blender/blenkernel/BKE_anim_visualization.h | 4 ++-- source/blender/blenkernel/BKE_asset.h | 2 +- source/blender/blenkernel/BKE_collision.h | 2 +- source/blender/blenkernel/BKE_constraint.h | 8 ++++---- source/blender/blenkernel/BKE_cryptomatte.h | 4 ++-- source/blender/blenkernel/BKE_geometry_set.h | 4 ++-- source/blender/blenkernel/BKE_geometry_set.hh | 4 ++-- source/blender/blenkernel/BKE_gpencil.h | 2 +- source/blender/blenkernel/BKE_gpencil_curve.h | 4 ++-- source/blender/blenkernel/BKE_gpencil_geom.h | 2 +- source/blender/blenkernel/BKE_gpencil_modifier.h | 6 +++--- source/blender/blenkernel/BKE_modifier.h | 2 +- source/blender/blenkernel/BKE_paint.h | 6 +++--- source/blender/blenkernel/BKE_particle.h | 2 +- source/blender/blenkernel/BKE_pointcache.h | 6 +++--- source/blender/blenkernel/BKE_shader_fx.h | 6 +++--- source/blender/draw/engines/eevee/eevee_lightcache.h | 4 ++-- source/blender/editors/include/ED_fileselect.h | 2 +- source/blender/editors/space_file/filelist.h | 2 +- source/blender/editors/space_outliner/outliner_intern.h | 2 +- source/blender/makesdna/DNA_gpencil_types.h | 2 +- source/blender/makesdna/DNA_node_types.h | 2 +- source/blender/makesdna/DNA_object_types.h | 2 +- source/blender/modifiers/MOD_nodes.h | 2 +- source/blender/sequencer/SEQ_sequencer.h | 6 +++--- source/blender/sequencer/intern/effects.h | 2 +- source/blender/sequencer/intern/image_cache.h | 2 +- source/blender/sequencer/intern/prefetch.h | 2 +- source/blender/sequencer/intern/proxy.h | 2 +- source/blender/sequencer/intern/strip_time.h | 2 +- 31 files changed, 51 insertions(+), 51 deletions(-) diff --git a/source/blender/blenkernel/BKE_action.h b/source/blender/blenkernel/BKE_action.h index d8605941974..717cfa607ad 100644 --- a/source/blender/blenkernel/BKE_action.h +++ b/source/blender/blenkernel/BKE_action.h @@ -30,10 +30,10 @@ extern "C" { #endif -struct BlendWriter; struct BlendDataReader; -struct BlendLibReader; struct BlendExpander; +struct BlendLibReader; +struct BlendWriter; struct bArmature; /* The following structures are defined in DNA_action_types.h, and DNA_anim_types.h */ diff --git a/source/blender/blenkernel/BKE_anim_visualization.h b/source/blender/blenkernel/BKE_anim_visualization.h index decb2e0b210..4e86abeed8d 100644 --- a/source/blender/blenkernel/BKE_anim_visualization.h +++ b/source/blender/blenkernel/BKE_anim_visualization.h @@ -26,14 +26,14 @@ extern "C" { #endif +struct BlendDataReader; +struct BlendWriter; struct Object; struct ReportList; struct Scene; struct bAnimVizSettings; struct bMotionPath; struct bPoseChannel; -struct BlendWriter; -struct BlendDataReader; /* ---------------------------------------------------- */ /* Animation Visualization */ diff --git a/source/blender/blenkernel/BKE_asset.h b/source/blender/blenkernel/BKE_asset.h index 20df6109c13..38cd5747343 100644 --- a/source/blender/blenkernel/BKE_asset.h +++ b/source/blender/blenkernel/BKE_asset.h @@ -27,8 +27,8 @@ extern "C" { #endif -struct BlendWriter; struct BlendDataReader; +struct BlendWriter; struct ID; struct PreviewImage; diff --git a/source/blender/blenkernel/BKE_collision.h b/source/blender/blenkernel/BKE_collision.h index a10a4e3c7fd..ff1bca896b1 100644 --- a/source/blender/blenkernel/BKE_collision.h +++ b/source/blender/blenkernel/BKE_collision.h @@ -26,9 +26,9 @@ extern "C" { #endif +struct BVHTree; struct Collection; struct CollisionModifierData; -struct BVHTree; struct Depsgraph; struct MVert; struct MVertTri; diff --git a/source/blender/blenkernel/BKE_constraint.h b/source/blender/blenkernel/BKE_constraint.h index 7a14787c191..afad1e26159 100644 --- a/source/blender/blenkernel/BKE_constraint.h +++ b/source/blender/blenkernel/BKE_constraint.h @@ -23,6 +23,10 @@ * \ingroup bke */ +struct BlendDataReader; +struct BlendExpander; +struct BlendLibReader; +struct BlendWriter; struct Depsgraph; struct ID; struct ListBase; @@ -31,10 +35,6 @@ struct Scene; struct bConstraint; struct bConstraintTarget; struct bPoseChannel; -struct BlendWriter; -struct BlendDataReader; -struct BlendLibReader; -struct BlendExpander; /* ---------------------------------------------------------------------------- */ #ifdef __cplusplus diff --git a/source/blender/blenkernel/BKE_cryptomatte.h b/source/blender/blenkernel/BKE_cryptomatte.h index d984b3824b1..433c25084ad 100644 --- a/source/blender/blenkernel/BKE_cryptomatte.h +++ b/source/blender/blenkernel/BKE_cryptomatte.h @@ -29,9 +29,9 @@ extern "C" { #endif -struct Object; -struct Material; struct Main; +struct Material; +struct Object; uint32_t BKE_cryptomatte_hash(const char *name, int name_len); uint32_t BKE_cryptomatte_object_hash(const struct Object *object); diff --git a/source/blender/blenkernel/BKE_geometry_set.h b/source/blender/blenkernel/BKE_geometry_set.h index 87bb96be145..37a3ed82bb8 100644 --- a/source/blender/blenkernel/BKE_geometry_set.h +++ b/source/blender/blenkernel/BKE_geometry_set.h @@ -24,9 +24,9 @@ extern "C" { #endif -struct Object; -struct GeometrySet; struct Collection; +struct GeometrySet; +struct Object; void BKE_geometry_set_free(struct GeometrySet *geometry_set); diff --git a/source/blender/blenkernel/BKE_geometry_set.hh b/source/blender/blenkernel/BKE_geometry_set.hh index 617e0c45ae4..90d444aa270 100644 --- a/source/blender/blenkernel/BKE_geometry_set.hh +++ b/source/blender/blenkernel/BKE_geometry_set.hh @@ -32,10 +32,10 @@ #include "BKE_attribute_access.hh" #include "BKE_geometry_set.h" +struct Collection; struct Mesh; -struct PointCloud; struct Object; -struct Collection; +struct PointCloud; /* Each geometry component has a specific type. The type determines what kind of data the component * stores. Functions modifying a geometry will usually just modify a subset of the component types. diff --git a/source/blender/blenkernel/BKE_gpencil.h b/source/blender/blenkernel/BKE_gpencil.h index 9177931cf9b..df5711f5120 100644 --- a/source/blender/blenkernel/BKE_gpencil.h +++ b/source/blender/blenkernel/BKE_gpencil.h @@ -42,11 +42,11 @@ struct SpaceImage; struct ToolSettings; struct ViewLayer; struct bDeformGroup; +struct bGPDcurve; struct bGPDframe; struct bGPDlayer; struct bGPDlayer_Mask; struct bGPDstroke; -struct bGPDcurve; struct bGPdata; #define GPENCIL_SIMPLIFY(scene) ((scene->r.simplify_gpencil & SIMPLIFY_GPENCIL_ENABLE)) diff --git a/source/blender/blenkernel/BKE_gpencil_curve.h b/source/blender/blenkernel/BKE_gpencil_curve.h index 1821972469c..2d42bb36949 100644 --- a/source/blender/blenkernel/BKE_gpencil_curve.h +++ b/source/blender/blenkernel/BKE_gpencil_curve.h @@ -30,10 +30,10 @@ extern "C" { struct Main; struct Object; struct Scene; -struct bGPdata; +struct bGPDcurve; struct bGPDlayer; struct bGPDstroke; -struct bGPDcurve; +struct bGPdata; void BKE_gpencil_convert_curve(struct Main *bmain, struct Scene *scene, diff --git a/source/blender/blenkernel/BKE_gpencil_geom.h b/source/blender/blenkernel/BKE_gpencil_geom.h index 8cb7137e1f0..1c86df73d3c 100644 --- a/source/blender/blenkernel/BKE_gpencil_geom.h +++ b/source/blender/blenkernel/BKE_gpencil_geom.h @@ -32,11 +32,11 @@ struct Depsgraph; struct Main; struct Object; struct Scene; +struct bGPDcurve; struct bGPDframe; struct bGPDspoint; struct bGPDstroke; struct bGPdata; -struct bGPDcurve; /* Object boundbox. */ bool BKE_gpencil_data_minmax(const struct bGPdata *gpd, float r_min[3], float r_max[3]); diff --git a/source/blender/blenkernel/BKE_gpencil_modifier.h b/source/blender/blenkernel/BKE_gpencil_modifier.h index ccf65a585ef..61ccf3d60f6 100644 --- a/source/blender/blenkernel/BKE_gpencil_modifier.h +++ b/source/blender/blenkernel/BKE_gpencil_modifier.h @@ -27,6 +27,9 @@ extern "C" { #endif struct ARegionType; +struct BlendDataReader; +struct BlendLibReader; +struct BlendWriter; struct Depsgraph; struct GpencilModifierData; struct ID; @@ -35,9 +38,6 @@ struct Main; struct ModifierUpdateDepsgraphContext; struct Object; struct Scene; -struct BlendWriter; -struct BlendDataReader; -struct BlendLibReader; /* NOTE: bakeModifier() called from UI: * needs to create new data-blocks, hence the need for this. */ struct bGPDframe; diff --git a/source/blender/blenkernel/BKE_modifier.h b/source/blender/blenkernel/BKE_modifier.h index 38b449cd92d..685a8ed98e2 100644 --- a/source/blender/blenkernel/BKE_modifier.h +++ b/source/blender/blenkernel/BKE_modifier.h @@ -35,6 +35,7 @@ struct BlendWriter; struct CustomData_MeshMasks; struct DepsNodeHandle; struct Depsgraph; +struct GeometrySet; struct ID; struct ListBase; struct Main; @@ -43,7 +44,6 @@ struct ModifierData; struct Object; struct Scene; struct bArmature; -struct GeometrySet; typedef enum { /* Should not be used, only for None modifier type */ diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h index f679533e1a9..aaed2649ad9 100644 --- a/source/blender/blenkernel/BKE_paint.h +++ b/source/blender/blenkernel/BKE_paint.h @@ -34,6 +34,9 @@ extern "C" { struct BMFace; struct BMesh; +struct BlendDataReader; +struct BlendLibReader; +struct BlendWriter; struct Brush; struct CurveMapping; struct Depsgraph; @@ -66,9 +69,6 @@ struct ViewLayer; struct bContext; struct bToolRef; struct tPaletteColorHSV; -struct BlendWriter; -struct BlendDataReader; -struct BlendLibReader; extern const char PAINT_CURSOR_SCULPT[3]; extern const char PAINT_CURSOR_VERTEX_PAINT[3]; diff --git a/source/blender/blenkernel/BKE_particle.h b/source/blender/blenkernel/BKE_particle.h index 2ac39be7eb3..3913ede9049 100644 --- a/source/blender/blenkernel/BKE_particle.h +++ b/source/blender/blenkernel/BKE_particle.h @@ -42,9 +42,9 @@ struct ParticleSystemModifierData; struct BVHTreeRay; struct BVHTreeRayHit; -struct BlendWriter; struct BlendDataReader; struct BlendLibReader; +struct BlendWriter; struct CustomData_MeshMasks; struct Depsgraph; struct EdgeHash; diff --git a/source/blender/blenkernel/BKE_pointcache.h b/source/blender/blenkernel/BKE_pointcache.h index d3ae043588d..170eb4ba662 100644 --- a/source/blender/blenkernel/BKE_pointcache.h +++ b/source/blender/blenkernel/BKE_pointcache.h @@ -77,7 +77,10 @@ extern "C" { #define PTCACHE_READ_OLD 3 /* Structs */ +struct BlendDataReader; +struct BlendWriter; struct ClothModifierData; +struct DynamicPaintSurface; struct FluidModifierData; struct ListBase; struct Main; @@ -89,9 +92,6 @@ struct RigidBodyWorld; struct Scene; struct SoftBody; struct ViewLayer; -struct BlendWriter; -struct BlendDataReader; -struct DynamicPaintSurface; /* temp structure for read/write */ typedef struct PTCacheData { diff --git a/source/blender/blenkernel/BKE_shader_fx.h b/source/blender/blenkernel/BKE_shader_fx.h index b5b5f61a6a6..23bd62c70bc 100644 --- a/source/blender/blenkernel/BKE_shader_fx.h +++ b/source/blender/blenkernel/BKE_shader_fx.h @@ -27,14 +27,14 @@ extern "C" { #endif struct ARegionType; +struct BlendDataReader; +struct BlendLibReader; +struct BlendWriter; struct ID; struct ListBase; struct ModifierUpdateDepsgraphContext; struct Object; struct ShaderFxData; -struct BlendWriter; -struct BlendDataReader; -struct BlendLibReader; #define SHADER_FX_ACTIVE(_fx, _is_render) \ ((((_fx)->mode & eShaderFxMode_Realtime) && (_is_render == false)) || \ diff --git a/source/blender/draw/engines/eevee/eevee_lightcache.h b/source/blender/draw/engines/eevee/eevee_lightcache.h index 17392c0de0b..fde0c80ab37 100644 --- a/source/blender/draw/engines/eevee/eevee_lightcache.h +++ b/source/blender/draw/engines/eevee/eevee_lightcache.h @@ -24,14 +24,14 @@ #include "BLI_sys_types.h" /* for bool */ +struct BlendDataReader; +struct BlendWriter; struct EEVEE_Data; struct EEVEE_ViewLayerData; struct LightCache; struct Scene; struct SceneEEVEE; struct ViewLayer; -struct BlendWriter; -struct BlendDataReader; /* Light Bake */ struct wmJob *EEVEE_lightbake_job_create(struct wmWindowManager *wm, diff --git a/source/blender/editors/include/ED_fileselect.h b/source/blender/editors/include/ED_fileselect.h index 3288cf11cb0..6c66a6162b8 100644 --- a/source/blender/editors/include/ED_fileselect.h +++ b/source/blender/editors/include/ED_fileselect.h @@ -28,8 +28,8 @@ extern "C" { #endif struct ARegion; -struct FileSelectParams; struct FileAssetSelectParams; +struct FileSelectParams; struct Scene; struct ScrArea; struct SpaceFile; diff --git a/source/blender/editors/space_file/filelist.h b/source/blender/editors/space_file/filelist.h index 59bd5bb50d7..16984bb6e43 100644 --- a/source/blender/editors/space_file/filelist.h +++ b/source/blender/editors/space_file/filelist.h @@ -29,8 +29,8 @@ extern "C" { struct BlendHandle; struct FileList; -struct FileSelection; struct FileSelectAssetLibraryUID; +struct FileSelection; struct wmWindowManager; struct FileDirEntry; diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h index ccb481197e4..339cc3068d0 100644 --- a/source/blender/editors/space_outliner/outliner_intern.h +++ b/source/blender/editors/space_outliner/outliner_intern.h @@ -32,7 +32,6 @@ extern "C" { /* internal exports only */ struct ARegion; -struct bContextDataResult; struct EditBone; struct ID; struct ListBase; @@ -43,6 +42,7 @@ struct TreeElement; struct TreeStoreElem; struct ViewLayer; struct bContext; +struct bContextDataResult; struct bPoseChannel; struct wmKeyConfig; struct wmOperatorType; diff --git a/source/blender/makesdna/DNA_gpencil_types.h b/source/blender/makesdna/DNA_gpencil_types.h index 212f0bfa1c9..949b0bb5bf5 100644 --- a/source/blender/makesdna/DNA_gpencil_types.h +++ b/source/blender/makesdna/DNA_gpencil_types.h @@ -32,8 +32,8 @@ extern "C" { #endif struct AnimData; -struct MDeformVert; struct Curve; +struct MDeformVert; #define GP_DEFAULT_PIX_FACTOR 1.0f #define GP_DEFAULT_GRID_LINES 4 diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index d512d8ffe34..9cf64743843 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -33,6 +33,7 @@ extern "C" { #endif struct AnimData; +struct Collection; struct ID; struct Image; struct ListBase; @@ -43,7 +44,6 @@ struct bNodePreview; struct bNodeTreeExec; struct bNodeType; struct uiBlock; -struct Collection; #define NODE_MAXSTR 64 diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h index 25447d8f20a..8b13db8a012 100644 --- a/source/blender/makesdna/DNA_object_types.h +++ b/source/blender/makesdna/DNA_object_types.h @@ -39,6 +39,7 @@ extern "C" { struct AnimData; struct BoundBox; struct FluidsimSettings; +struct GeometrySet; struct Ipo; struct Material; struct Mesh; @@ -49,7 +50,6 @@ struct RigidBodyOb; struct SculptSession; struct SoftBody; struct bGPdata; -struct GeometrySet; /* Vertex Groups - Name Info */ typedef struct bDeformGroup { diff --git a/source/blender/modifiers/MOD_nodes.h b/source/blender/modifiers/MOD_nodes.h index 9c75e7e3416..907dbe9c5f4 100644 --- a/source/blender/modifiers/MOD_nodes.h +++ b/source/blender/modifiers/MOD_nodes.h @@ -17,8 +17,8 @@ #pragma once struct Main; -struct Object; struct NodesModifierData; +struct Object; #ifdef __cplusplus extern "C" { diff --git a/source/blender/sequencer/SEQ_sequencer.h b/source/blender/sequencer/SEQ_sequencer.h index a024d5e10d3..8c4863d98ed 100644 --- a/source/blender/sequencer/SEQ_sequencer.h +++ b/source/blender/sequencer/SEQ_sequencer.h @@ -27,6 +27,9 @@ extern "C" { #endif +struct BlendDataReader; +struct BlendLibReader; +struct BlendWriter; struct Depsgraph; struct Editing; struct GPUOffScreen; @@ -44,9 +47,6 @@ struct StripElem; struct TextVars; struct bContext; struct bSound; -struct BlendWriter; -struct BlendDataReader; -struct BlendLibReader; /* Wipe effect */ enum { diff --git a/source/blender/sequencer/intern/effects.h b/source/blender/sequencer/intern/effects.h index 58e0a97d4c5..6a94c0ea9d9 100644 --- a/source/blender/sequencer/intern/effects.h +++ b/source/blender/sequencer/intern/effects.h @@ -28,8 +28,8 @@ extern "C" { #endif struct Scene; -struct Sequence; struct SeqRenderData; +struct Sequence; /* ********************************************************************** * sequencer.c diff --git a/source/blender/sequencer/intern/image_cache.h b/source/blender/sequencer/intern/image_cache.h index 0fcf0548628..2cb35670a2c 100644 --- a/source/blender/sequencer/intern/image_cache.h +++ b/source/blender/sequencer/intern/image_cache.h @@ -30,8 +30,8 @@ extern "C" { struct ImBuf; struct Main; struct Scene; -struct Sequence; struct SeqRenderData; +struct Sequence; #ifdef __cplusplus } diff --git a/source/blender/sequencer/intern/prefetch.h b/source/blender/sequencer/intern/prefetch.h index 6b9d936133d..1633ee297f8 100644 --- a/source/blender/sequencer/intern/prefetch.h +++ b/source/blender/sequencer/intern/prefetch.h @@ -28,8 +28,8 @@ extern "C" { #endif struct Scene; -struct Sequence; struct SeqRenderData; +struct Sequence; #ifdef __cplusplus } diff --git a/source/blender/sequencer/intern/proxy.h b/source/blender/sequencer/intern/proxy.h index a362a318a5a..a65fdcd42fe 100644 --- a/source/blender/sequencer/intern/proxy.h +++ b/source/blender/sequencer/intern/proxy.h @@ -27,10 +27,10 @@ extern "C" { #endif -struct anim; struct ImBuf; struct SeqRenderData; struct Sequence; +struct anim; #define PROXY_MAXFILE (2 * FILE_MAXDIR + FILE_MAXFILE) struct ImBuf *seq_proxy_fetch(const struct SeqRenderData *context, diff --git a/source/blender/sequencer/intern/strip_time.h b/source/blender/sequencer/intern/strip_time.h index e435ff1ec5d..ca9a935bc96 100644 --- a/source/blender/sequencer/intern/strip_time.h +++ b/source/blender/sequencer/intern/strip_time.h @@ -27,9 +27,9 @@ extern "C" { #endif +struct ListBase; struct Scene; struct Sequence; -struct ListBase; float seq_give_frame_index(struct Sequence *seq, float timeline_frame); void seq_update_sound_bounds_recursive(struct Scene *scene, struct Sequence *metaseq); -- cgit v1.2.3 From f34ca933a806b83be957f69835c7a6033fe5ca2c Mon Sep 17 00:00:00 2001 From: Vincent Blankfield Date: Wed, 16 Dec 2020 16:28:44 +1100 Subject: UI: include the category for add-ons search This lead to some confusion, see T83747. Now the category is included in the search when the category is "All". Ref D9848 --- release/scripts/startup/bl_ui/space_userpref.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py index ae45b9799f1..1d59fe4bfa2 100644 --- a/release/scripts/startup/bl_ui/space_userpref.py +++ b/release/scripts/startup/bl_ui/space_userpref.py @@ -1881,12 +1881,12 @@ class USERPREF_PT_addons(AddOnPanel, Panel): is_visible = is_visible and is_enabled if is_visible: - if search and search not in info["name"].lower(): - if info["author"]: - if search not in info["author"].lower(): - continue - else: - continue + if search and not ( + (search in info["name"].lower()) or + (info["author"] and (search in info["author"].lower())) or + ((filter == "All") and (search in info["category"].lower())) + ): + continue # Skip 2.7x add-ons included with Blender, unless in debug mode. is_addon_27x = info.get("blender", (0,)) < (2, 80) -- cgit v1.2.3 From e671c548e66e95d4fd1884c81c2dab1ae4a1a219 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 16 Dec 2020 18:02:40 +1100 Subject: Cleanup: pep8 --- release/scripts/startup/bl_operators/assets.py | 1 + .../scripts/startup/bl_operators/geometry_nodes.py | 3 +++ .../startup/bl_operators/object_quick_effects.py | 1 + .../bl_ui/properties_grease_pencil_common.py | 1 + .../startup/bl_ui/properties_paint_common.py | 1 - release/scripts/startup/bl_ui/space_filebrowser.py | 23 ++++++++++++++++++---- release/scripts/startup/bl_ui/space_image.py | 4 +--- release/scripts/startup/bl_ui/space_node.py | 1 - release/scripts/startup/bl_ui/space_properties.py | 6 ++++-- release/scripts/startup/bl_ui/space_sequencer.py | 6 +----- release/scripts/startup/bl_ui/space_time.py | 1 + release/scripts/startup/bl_ui/space_userpref.py | 2 +- release/scripts/startup/bl_ui/space_view3d.py | 1 + .../scripts/startup/bl_ui/space_view3d_toolbar.py | 1 + 14 files changed, 35 insertions(+), 17 deletions(-) diff --git a/release/scripts/startup/bl_operators/assets.py b/release/scripts/startup/bl_operators/assets.py index c317df78aa5..317555280e5 100644 --- a/release/scripts/startup/bl_operators/assets.py +++ b/release/scripts/startup/bl_operators/assets.py @@ -22,6 +22,7 @@ from bpy_extras.asset_utils import ( SpaceAssetInfo, ) + class ASSET_OT_tag_add(bpy.types.Operator): """Add a new keyword tag to the active asset""" diff --git a/release/scripts/startup/bl_operators/geometry_nodes.py b/release/scripts/startup/bl_operators/geometry_nodes.py index 7d7e3793dba..b94104d10a9 100644 --- a/release/scripts/startup/bl_operators/geometry_nodes.py +++ b/release/scripts/startup/bl_operators/geometry_nodes.py @@ -18,6 +18,7 @@ import bpy + def geometry_node_group_empty_new(context): group = bpy.data.node_groups.new("Geometry Nodes", 'GeometryNodeTree') group.inputs.new('NodeSocketGeometry', "Geometry") @@ -33,6 +34,7 @@ def geometry_node_group_empty_new(context): return group + def geometry_modifier_poll(context) -> bool: ob = context.object @@ -42,6 +44,7 @@ def geometry_modifier_poll(context) -> bool: return True + class NewGeometryNodesModifier(bpy.types.Operator): """Create a new modifier with a new geometry node group""" diff --git a/release/scripts/startup/bl_operators/object_quick_effects.py b/release/scripts/startup/bl_operators/object_quick_effects.py index 8c275da28ac..0600536cb66 100644 --- a/release/scripts/startup/bl_operators/object_quick_effects.py +++ b/release/scripts/startup/bl_operators/object_quick_effects.py @@ -573,6 +573,7 @@ class QuickLiquid(Operator): return {'FINISHED'} + classes = ( QuickExplode, QuickFur, diff --git a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py index 8201ce080b1..c663a736441 100644 --- a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py +++ b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py @@ -893,6 +893,7 @@ class GreasePencilLayerDisplayPanel: row = layout.row(align=True) row.prop(gpl, "use_solo_mode", text="Show Only on Keyframed") + class GreasePencilFlipTintColors(Operator): bl_label = "Flip Colors" bl_idname = "gpencil.tint_flip" diff --git a/release/scripts/startup/bl_ui/properties_paint_common.py b/release/scripts/startup/bl_ui/properties_paint_common.py index 7e9e15c30da..86221ebce59 100644 --- a/release/scripts/startup/bl_ui/properties_paint_common.py +++ b/release/scripts/startup/bl_ui/properties_paint_common.py @@ -550,7 +550,6 @@ def brush_settings(layout, context, brush, popover=False): if context.preferences.experimental.use_sculpt_tools_tilt and capabilities.has_tilt: layout.prop(brush, "tilt_strength_factor", slider=True) - row = layout.row(align=True) row.prop(brush, "hardness", slider=True) row.prop(brush, "invert_hardness_pressure", text="") diff --git a/release/scripts/startup/bl_ui/space_filebrowser.py b/release/scripts/startup/bl_ui/space_filebrowser.py index 527a5bc623e..15e2e3d02e0 100644 --- a/release/scripts/startup/bl_ui/space_filebrowser.py +++ b/release/scripts/startup/bl_ui/space_filebrowser.py @@ -267,7 +267,11 @@ class FILEBROWSER_PT_bookmarks_system(Panel): @classmethod def poll(cls, context): - return not context.preferences.filepaths.hide_system_bookmarks and panel_poll_is_upper_region(context.region) and not panel_poll_is_asset_browsing(context) + return ( + not context.preferences.filepaths.hide_system_bookmarks and + panel_poll_is_upper_region(context.region) and + not panel_poll_is_asset_browsing(context) + ) def draw(self, context): layout = self.layout @@ -301,7 +305,10 @@ class FILEBROWSER_PT_bookmarks_favorites(Panel): @classmethod def poll(cls, context): - return panel_poll_is_upper_region(context.region) and not panel_poll_is_asset_browsing(context) + return ( + panel_poll_is_upper_region(context.region) and + not panel_poll_is_asset_browsing(context) + ) def draw(self, context): layout = self.layout @@ -338,7 +345,11 @@ class FILEBROWSER_PT_bookmarks_recents(Panel): @classmethod def poll(cls, context): - return not context.preferences.filepaths.hide_recent_locations and panel_poll_is_upper_region(context.region) and not panel_poll_is_asset_browsing(context) + return ( + not context.preferences.filepaths.hide_recent_locations and + panel_poll_is_upper_region(context.region) and + not panel_poll_is_asset_browsing(context) + ) def draw(self, context): layout = self.layout @@ -362,7 +373,11 @@ class FILEBROWSER_PT_advanced_filter(Panel): @classmethod def poll(cls, context): # only useful in append/link (library) context currently... - return context.space_data.params.use_library_browsing and panel_poll_is_upper_region(context.region) and not panel_poll_is_asset_browsing(context) + return ( + context.space_data.params.use_library_browsing and + panel_poll_is_upper_region(context.region) and + not panel_poll_is_asset_browsing(context) + ) def draw(self, context): layout = self.layout diff --git a/release/scripts/startup/bl_ui/space_image.py b/release/scripts/startup/bl_ui/space_image.py index f4e88b70281..342b72acb8c 100644 --- a/release/scripts/startup/bl_ui/space_image.py +++ b/release/scripts/startup/bl_ui/space_image.py @@ -1465,7 +1465,7 @@ class IMAGE_PT_overlay(Panel): bl_ui_units_x = 13 def draw(self, context): - pass + pass class IMAGE_PT_overlay_uv_edit(Panel): @@ -1496,7 +1496,6 @@ class IMAGE_PT_overlay_uv_edit(Panel): subrow.prop(uvedit, "display_stretch_type", text="") - class IMAGE_PT_overlay_uv_edit_geometry(Panel): bl_space_type = 'IMAGE_EDITOR' bl_region_type = 'HEADER' @@ -1529,7 +1528,6 @@ class IMAGE_PT_overlay_uv_edit_geometry(Panel): row.prop(uvedit, "show_faces", text="Faces") - class IMAGE_PT_overlay_texture_paint(Panel): bl_space_type = 'IMAGE_EDITOR' bl_region_type = 'HEADER' diff --git a/release/scripts/startup/bl_ui/space_node.py b/release/scripts/startup/bl_ui/space_node.py index 1c4d1919f43..e6af83b61f4 100644 --- a/release/scripts/startup/bl_ui/space_node.py +++ b/release/scripts/startup/bl_ui/space_node.py @@ -168,7 +168,6 @@ class NODE_HT_header(Header): else: row.template_ID(snode, "node_tree", new="node.new_geometry_nodes_modifier") - else: # Custom node tree is edited as independent ID block NODE_MT_editor_menus.draw_collapsible(context, layout) diff --git a/release/scripts/startup/bl_ui/space_properties.py b/release/scripts/startup/bl_ui/space_properties.py index 0f64ab63d6b..765cab1ace2 100644 --- a/release/scripts/startup/bl_ui/space_properties.py +++ b/release/scripts/startup/bl_ui/space_properties.py @@ -61,8 +61,10 @@ class PROPERTIES_PT_navigation_bar(Panel): layout.scale_x = 1.4 layout.scale_y = 1.4 if view.search_filter: - layout.prop_tabs_enum(view, "context", data_highlight=view, - property_highlight="tab_search_results", icon_only=True) + layout.prop_tabs_enum( + view, "context", data_highlight=view, + property_highlight="tab_search_results", icon_only=True, + ) else: layout.prop_tabs_enum(view, "context", icon_only=True) diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py index 8ef961960ff..84602057e18 100644 --- a/release/scripts/startup/bl_ui/space_sequencer.py +++ b/release/scripts/startup/bl_ui/space_sequencer.py @@ -156,7 +156,6 @@ class SEQUENCER_HT_header(Header): if tool_settings.use_proportional_edit: row.prop(tool_settings, "proportional_edit_falloff", icon_only=True) - row = layout.row(align=True) row.prop(st, "show_strip_overlay", text="", icon='OVERLAY') sub = row.row(align=True) @@ -213,7 +212,6 @@ class SEQUENCER_PT_preview_overlay(Panel): st = context.space_data return st.view_type in {'PREVIEW', 'SEQUENCER_PREVIEW'} and st.display_mode == 'IMAGE' - def draw(self, context): ed = context.scene.sequence_editor st = context.space_data @@ -224,7 +222,7 @@ class SEQUENCER_PT_preview_overlay(Panel): layout.prop(st, "show_safe_areas", text="Safe Areas") layout.prop(st, "show_metadata", text="Metadata") layout.prop(st, "show_annotation", text="Annotations") - + class SEQUENCER_PT_sequencer_overlay(Panel): bl_space_type = 'SEQUENCE_EDITOR' @@ -237,7 +235,6 @@ class SEQUENCER_PT_sequencer_overlay(Panel): st = context.space_data return st.view_type in {'SEQUENCER', 'SEQUENCER_PREVIEW'} - def draw(self, context): st = context.space_data layout = self.layout @@ -258,7 +255,6 @@ class SEQUENCER_PT_sequencer_overlay(Panel): layout.prop_menu_enum(st, "waveform_display_type") - class SEQUENCER_MT_view_cache(Menu): bl_label = "Cache" diff --git a/release/scripts/startup/bl_ui/space_time.py b/release/scripts/startup/bl_ui/space_time.py index 16b02db9377..3b9ce5311f3 100644 --- a/release/scripts/startup/bl_ui/space_time.py +++ b/release/scripts/startup/bl_ui/space_time.py @@ -297,6 +297,7 @@ class TIME_PT_keyframing_settings(TimelinePanelButtons, Panel): col.label(text="New Keyframe Type") col.prop(tool_settings, "keyframe_type", text="") + class TIME_PT_auto_keyframing(TimelinePanelButtons, Panel): bl_label = "Auto Keyframing" bl_options = {'HIDE_HEADER'} diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py index 1d59fe4bfa2..1d9d4fbf393 100644 --- a/release/scripts/startup/bl_ui/space_userpref.py +++ b/release/scripts/startup/bl_ui/space_userpref.py @@ -211,7 +211,7 @@ class USERPREF_PT_interface_display(InterfacePanel, CenterAlignMixIn, Panel): col.separator() col = layout.column(heading="Tooltips", align=True) - col.prop(view, "show_tooltips", text = "User Tooltips") + col.prop(view, "show_tooltips", text="User Tooltips") sub = col.column() sub.active = view.show_tooltips sub.prop(view, "show_tooltips_python") diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index c97d5601a10..8b5183faf62 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -5306,6 +5306,7 @@ class VIEW3D_MT_sculpt_mask_edit_pie(Menu): op.filter_type = 'CONTRAST_DECREASE' op.auto_iteration_count = False + class VIEW3D_MT_sculpt_automasking_pie(Menu): bl_label = "Automasking" diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py index 293d55a6015..577f9678a62 100644 --- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py +++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py @@ -966,6 +966,7 @@ class VIEW3D_PT_tools_weightpaint_symmetry(Panel, View3DPaintPanel): row.active = mesh.use_mirror_vertex_group_x row.prop(mesh, "use_mirror_topology") + class VIEW3D_PT_tools_weightpaint_symmetry_for_topbar(Panel): bl_space_type = 'TOPBAR' bl_region_type = 'HEADER' -- cgit v1.2.3 From d23a5b1d88df513aff1dc1ba09730221567f2857 Mon Sep 17 00:00:00 2001 From: Ankit Meel Date: Wed, 16 Dec 2020 13:02:28 +0530 Subject: BLI: constexpr Span, IndexRange, StringRef(Null/Base) Motivated by `std::string_view` being usable in const (compile-time) context. One functional change was needed for StringRef: `std::char_traits::length(str)` instead of `strlen`. Reviewed By: JacquesLucke, LazyDodo Differential Revision: https://developer.blender.org/D9788 --- source/blender/blenlib/BLI_index_range.hh | 45 ++++---- source/blender/blenlib/BLI_span.hh | 124 ++++++++++---------- source/blender/blenlib/BLI_string_ref.hh | 126 +++++++++++---------- .../blender/blenlib/tests/BLI_index_range_test.cc | 7 ++ source/blender/blenlib/tests/BLI_span_test.cc | 15 +++ .../blender/blenlib/tests/BLI_string_ref_test.cc | 8 ++ 6 files changed, 180 insertions(+), 145 deletions(-) diff --git a/source/blender/blenlib/BLI_index_range.hh b/source/blender/blenlib/BLI_index_range.hh index 2b060c986cd..4121542c887 100644 --- a/source/blender/blenlib/BLI_index_range.hh +++ b/source/blender/blenlib/BLI_index_range.hh @@ -73,21 +73,22 @@ class IndexRange { int64_t size_ = 0; public: - IndexRange() = default; + constexpr IndexRange() = default; - explicit IndexRange(int64_t size) : start_(0), size_(size) + constexpr explicit IndexRange(int64_t size) : start_(0), size_(size) { BLI_assert(size >= 0); } - IndexRange(int64_t start, int64_t size) : start_(start), size_(size) + constexpr IndexRange(int64_t start, int64_t size) : start_(start), size_(size) { BLI_assert(start >= 0); BLI_assert(size >= 0); } template - IndexRange(const tbb::blocked_range &range) : start_(range.begin()), size_(range.size()) + constexpr IndexRange(const tbb::blocked_range &range) + : start_(range.begin()), size_(range.size()) { } @@ -96,33 +97,33 @@ class IndexRange { int64_t current_; public: - Iterator(int64_t current) : current_(current) + constexpr Iterator(int64_t current) : current_(current) { } - Iterator &operator++() + constexpr Iterator &operator++() { current_++; return *this; } - bool operator!=(const Iterator &iterator) const + constexpr bool operator!=(const Iterator &iterator) const { return current_ != iterator.current_; } - int64_t operator*() const + constexpr int64_t operator*() const { return current_; } }; - Iterator begin() const + constexpr Iterator begin() const { return Iterator(start_); } - Iterator end() const + constexpr Iterator end() const { return Iterator(start_ + size_); } @@ -130,7 +131,7 @@ class IndexRange { /** * Access an element in the range. */ - int64_t operator[](int64_t index) const + constexpr int64_t operator[](int64_t index) const { BLI_assert(index >= 0); BLI_assert(index < this->size()); @@ -140,7 +141,7 @@ class IndexRange { /** * Two ranges compare equal when they contain the same numbers. */ - friend bool operator==(IndexRange a, IndexRange b) + constexpr friend bool operator==(IndexRange a, IndexRange b) { return (a.size_ == b.size_) && (a.start_ == b.start_ || a.size_ == 0); } @@ -148,7 +149,7 @@ class IndexRange { /** * Get the amount of numbers in the range. */ - int64_t size() const + constexpr int64_t size() const { return size_; } @@ -156,7 +157,7 @@ class IndexRange { /** * Create a new range starting at the end of the current one. */ - IndexRange after(int64_t n) const + constexpr IndexRange after(int64_t n) const { BLI_assert(n >= 0); return IndexRange(start_ + size_, n); @@ -165,7 +166,7 @@ class IndexRange { /** * Create a new range that ends at the start of the current one. */ - IndexRange before(int64_t n) const + constexpr IndexRange before(int64_t n) const { BLI_assert(n >= 0); return IndexRange(start_ - n, n); @@ -175,7 +176,7 @@ class IndexRange { * Get the first element in the range. * Asserts when the range is empty. */ - int64_t first() const + constexpr int64_t first() const { BLI_assert(this->size() > 0); return start_; @@ -185,7 +186,7 @@ class IndexRange { * Get the last element in the range. * Asserts when the range is empty. */ - int64_t last() const + constexpr int64_t last() const { BLI_assert(this->size() > 0); return start_ + size_ - 1; @@ -194,7 +195,7 @@ class IndexRange { /** * Get the element one after the end. The returned value is undefined when the range is empty. */ - int64_t one_after_last() const + constexpr int64_t one_after_last() const { return start_ + size_; } @@ -202,7 +203,7 @@ class IndexRange { /** * Get the first element in the range. The returned value is undefined when the range is empty. */ - int64_t start() const + constexpr int64_t start() const { return start_; } @@ -210,7 +211,7 @@ class IndexRange { /** * Returns true when the range contains a certain number, otherwise false. */ - bool contains(int64_t value) const + constexpr bool contains(int64_t value) const { return value >= start_ && value < start_ + size_; } @@ -218,7 +219,7 @@ class IndexRange { /** * Returns a new range, that contains a sub-interval of the current one. */ - IndexRange slice(int64_t start, int64_t size) const + constexpr IndexRange slice(int64_t start, int64_t size) const { BLI_assert(start >= 0); BLI_assert(size >= 0); @@ -226,7 +227,7 @@ class IndexRange { BLI_assert(new_start + size <= start_ + size_ || size == 0); return IndexRange(new_start, size); } - IndexRange slice(IndexRange range) const + constexpr IndexRange slice(IndexRange range) const { return this->slice(range.start(), range.size()); } diff --git a/source/blender/blenlib/BLI_span.hh b/source/blender/blenlib/BLI_span.hh index 5b4d2769f57..3f410efe908 100644 --- a/source/blender/blenlib/BLI_span.hh +++ b/source/blender/blenlib/BLI_span.hh @@ -93,15 +93,15 @@ template class Span { /** * Create a reference to an empty array. */ - Span() = default; + constexpr Span() = default; - Span(const T *start, int64_t size) : data_(start), size_(size) + constexpr Span(const T *start, int64_t size) : data_(start), size_(size) { BLI_assert(size >= 0); } template> * = nullptr> - Span(const U *start, int64_t size) : data_(static_cast(start)), size_(size) + constexpr Span(const U *start, int64_t size) : data_(static_cast(start)), size_(size) { BLI_assert(size >= 0); } @@ -117,16 +117,17 @@ template class Span { * Span span = {1, 2, 3, 4}; * call_function_with_array(span); */ - Span(const std::initializer_list &list) + constexpr Span(const std::initializer_list &list) : Span(list.begin(), static_cast(list.size())) { } - Span(const std::vector &vector) : Span(vector.data(), static_cast(vector.size())) + constexpr Span(const std::vector &vector) + : Span(vector.data(), static_cast(vector.size())) { } - template Span(const std::array &array) : Span(array.data(), N) + template constexpr Span(const std::array &array) : Span(array.data(), N) { } @@ -135,7 +136,7 @@ template class Span { * Span -> Span */ template> * = nullptr> - Span(Span array) : data_(static_cast(array.data())), size_(array.size()) + constexpr Span(Span array) : data_(static_cast(array.data())), size_(array.size()) { } @@ -143,7 +144,7 @@ template class Span { * Returns a contiguous part of the array. This invokes undefined behavior when the slice does * not stay within the bounds of the array. */ - Span slice(int64_t start, int64_t size) const + constexpr Span slice(int64_t start, int64_t size) const { BLI_assert(start >= 0); BLI_assert(size >= 0); @@ -151,7 +152,7 @@ template class Span { return Span(data_ + start, size); } - Span slice(IndexRange range) const + constexpr Span slice(IndexRange range) const { return this->slice(range.start(), range.size()); } @@ -160,7 +161,7 @@ template class Span { * Returns a new Span with n elements removed from the beginning. This invokes undefined * behavior when the array is too small. */ - Span drop_front(int64_t n) const + constexpr Span drop_front(int64_t n) const { BLI_assert(n >= 0); BLI_assert(n <= this->size()); @@ -171,7 +172,7 @@ template class Span { * Returns a new Span with n elements removed from the beginning. This invokes undefined * behavior when the array is too small. */ - Span drop_back(int64_t n) const + constexpr Span drop_back(int64_t n) const { BLI_assert(n >= 0); BLI_assert(n <= this->size()); @@ -182,7 +183,7 @@ template class Span { * Returns a new Span that only contains the first n elements. This invokes undefined * behavior when the array is too small. */ - Span take_front(int64_t n) const + constexpr Span take_front(int64_t n) const { BLI_assert(n >= 0); BLI_assert(n <= this->size()); @@ -193,7 +194,7 @@ template class Span { * Returns a new Span that only contains the last n elements. This invokes undefined * behavior when the array is too small. */ - Span take_back(int64_t n) const + constexpr Span take_back(int64_t n) const { BLI_assert(n >= 0); BLI_assert(n <= this->size()); @@ -204,25 +205,25 @@ template class Span { * Returns the pointer to the beginning of the referenced array. This may be nullptr when the * size is zero. */ - const T *data() const + constexpr const T *data() const { return data_; } - const T *begin() const + constexpr const T *begin() const { return data_; } - const T *end() const + constexpr const T *end() const { return data_ + size_; } - std::reverse_iterator rbegin() const + constexpr std::reverse_iterator rbegin() const { return std::reverse_iterator(this->end()); } - std::reverse_iterator rend() const + constexpr std::reverse_iterator rend() const { return std::reverse_iterator(this->begin()); } @@ -231,7 +232,7 @@ template class Span { * Access an element in the array. This invokes undefined behavior when the index is out of * bounds. */ - const T &operator[](int64_t index) const + constexpr const T &operator[](int64_t index) const { BLI_assert(index >= 0); BLI_assert(index < size_); @@ -241,7 +242,7 @@ template class Span { /** * Returns the number of elements in the referenced array. */ - int64_t size() const + constexpr int64_t size() const { return size_; } @@ -249,7 +250,7 @@ template class Span { /** * Returns true if the size is zero. */ - bool is_empty() const + constexpr bool is_empty() const { return size_ == 0; } @@ -257,7 +258,7 @@ template class Span { /** * Returns the number of bytes referenced by this Span. */ - int64_t size_in_bytes() const + constexpr int64_t size_in_bytes() const { return sizeof(T) * size_; } @@ -266,7 +267,7 @@ template class Span { * Does a linear search to see of the value is in the array. * Returns true if it is, otherwise false. */ - bool contains(const T &value) const + constexpr bool contains(const T &value) const { for (const T &element : *this) { if (element == value) { @@ -280,7 +281,7 @@ template class Span { * Does a constant time check to see if the pointer points to a value in the referenced array. * Return true if it is, otherwise false. */ - bool contains_ptr(const T *ptr) const + constexpr bool contains_ptr(const T *ptr) const { return (this->begin() <= ptr) && (ptr < this->end()); } @@ -289,7 +290,7 @@ template class Span { * Does a linear search to count how often the value is in the array. * Returns the number of occurrences. */ - int64_t count(const T &value) const + constexpr int64_t count(const T &value) const { int64_t counter = 0; for (const T &element : *this) { @@ -304,7 +305,7 @@ template class Span { * Return a reference to the first element in the array. This invokes undefined behavior when the * array is empty. */ - const T &first() const + constexpr const T &first() const { BLI_assert(size_ > 0); return data_[0]; @@ -314,7 +315,7 @@ template class Span { * Returns a reference to the last element in the array. This invokes undefined behavior when the * array is empty. */ - const T &last() const + constexpr const T &last() const { BLI_assert(size_ > 0); return data_[size_ - 1]; @@ -324,7 +325,7 @@ template class Span { * Returns the element at the given index. If the index is out of range, return the fallback * value. */ - T get(int64_t index, const T &fallback) const + constexpr T get(int64_t index, const T &fallback) const { if (index < size_ && index >= 0) { return data_[index]; @@ -336,7 +337,7 @@ template class Span { * Check if the array contains duplicates. Does a linear search for every element. So the total * running time is O(n^2). Only use this for small arrays. */ - bool has_duplicates__linear_search() const + constexpr bool has_duplicates__linear_search() const { /* The size should really be smaller than that. If it is not, the calling code should be * changed. */ @@ -358,7 +359,7 @@ template class Span { * called on small arrays, because it has a running time of O(n*m) where n and m are the sizes of * the arrays. */ - bool intersects__linear_search(Span other) const + constexpr bool intersects__linear_search(Span other) const { /* The size should really be smaller than that. If it is not, the calling code should be * changed. */ @@ -377,7 +378,7 @@ template class Span { * Returns the index of the first occurrence of the given value. This invokes undefined behavior * when the value is not in the array. */ - int64_t first_index(const T &search_value) const + constexpr int64_t first_index(const T &search_value) const { const int64_t index = this->first_index_try(search_value); BLI_assert(index >= 0); @@ -387,7 +388,7 @@ template class Span { /** * Returns the index of the first occurrence of the given value or -1 if it does not exist. */ - int64_t first_index_try(const T &search_value) const + constexpr int64_t first_index_try(const T &search_value) const { for (int64_t i = 0; i < size_; i++) { if (data_[i] == search_value) { @@ -401,7 +402,7 @@ template class Span { * Utility to make it more convenient to iterate over all indices that can be used with this * array. */ - IndexRange index_range() const + constexpr IndexRange index_range() const { return IndexRange(size_); } @@ -409,7 +410,7 @@ template class Span { /** * Returns a new Span to the same underlying memory buffer. No conversions are done. */ - template Span cast() const + template Span constexpr cast() const { BLI_assert((size_ * sizeof(T)) % sizeof(NewT) == 0); int64_t new_size = size_ * sizeof(T) / sizeof(NewT); @@ -450,21 +451,22 @@ template class MutableSpan { int64_t size_; public: - MutableSpan() = default; + constexpr MutableSpan() = default; - MutableSpan(T *start, const int64_t size) : data_(start), size_(size) + constexpr MutableSpan(T *start, const int64_t size) : data_(start), size_(size) { } - MutableSpan(std::vector &vector) : MutableSpan(vector.data(), vector.size()) + constexpr MutableSpan(std::vector &vector) : MutableSpan(vector.data(), vector.size()) { } - template MutableSpan(std::array &array) : MutableSpan(array.data(), N) + template + constexpr MutableSpan(std::array &array) : MutableSpan(array.data(), N) { } - operator Span() const + constexpr operator Span() const { return Span(data_, size_); } @@ -472,7 +474,7 @@ template class MutableSpan { /** * Returns the number of elements in the array. */ - int64_t size() const + constexpr int64_t size() const { return size_; } @@ -480,7 +482,7 @@ template class MutableSpan { /** * Replace all elements in the referenced array with the given value. */ - void fill(const T &value) + constexpr void fill(const T &value) { initialized_fill_n(data_, size_, value); } @@ -489,7 +491,7 @@ template class MutableSpan { * Replace a subset of all elements with the given value. This invokes undefined behavior when * one of the indices is out of bounds. */ - void fill_indices(Span indices, const T &value) + constexpr void fill_indices(Span indices, const T &value) { for (int64_t i : indices) { BLI_assert(i < size_); @@ -501,30 +503,30 @@ template class MutableSpan { * Returns a pointer to the beginning of the referenced array. This may be nullptr, when the size * is zero. */ - T *data() const + constexpr T *data() const { return data_; } - T *begin() const + constexpr T *begin() const { return data_; } - T *end() const + constexpr T *end() const { return data_ + size_; } - std::reverse_iterator rbegin() const + constexpr std::reverse_iterator rbegin() const { return std::reverse_iterator(this->end()); } - std::reverse_iterator rend() const + constexpr std::reverse_iterator rend() const { return std::reverse_iterator(this->begin()); } - T &operator[](const int64_t index) const + constexpr T &operator[](const int64_t index) const { BLI_assert(index < this->size()); return data_[index]; @@ -534,7 +536,7 @@ template class MutableSpan { * Returns a contiguous part of the array. This invokes undefined behavior when the slice would * go out of bounds. */ - MutableSpan slice(const int64_t start, const int64_t length) const + constexpr MutableSpan slice(const int64_t start, const int64_t length) const { BLI_assert(start + length <= this->size()); return MutableSpan(data_ + start, length); @@ -544,7 +546,7 @@ template class MutableSpan { * Returns a new MutableSpan with n elements removed from the beginning. This invokes * undefined behavior when the array is too small. */ - MutableSpan drop_front(const int64_t n) const + constexpr MutableSpan drop_front(const int64_t n) const { BLI_assert(n <= this->size()); return this->slice(n, this->size() - n); @@ -554,7 +556,7 @@ template class MutableSpan { * Returns a new MutableSpan with n elements removed from the end. This invokes undefined * behavior when the array is too small. */ - MutableSpan drop_back(const int64_t n) const + constexpr MutableSpan drop_back(const int64_t n) const { BLI_assert(n <= this->size()); return this->slice(0, this->size() - n); @@ -564,7 +566,7 @@ template class MutableSpan { * Returns a new MutableSpan that only contains the first n elements. This invokes undefined * behavior when the array is too small. */ - MutableSpan take_front(const int64_t n) const + constexpr MutableSpan take_front(const int64_t n) const { BLI_assert(n <= this->size()); return this->slice(0, n); @@ -574,7 +576,7 @@ template class MutableSpan { * Return a new MutableSpan that only contains the last n elements. This invokes undefined * behavior when the array is too small. */ - MutableSpan take_back(const int64_t n) const + constexpr MutableSpan take_back(const int64_t n) const { BLI_assert(n <= this->size()); return this->slice(this->size() - n, n); @@ -584,7 +586,7 @@ template class MutableSpan { * Returns an (immutable) Span that references the same array. This is usually not needed, * due to implicit conversions. However, sometimes automatic type deduction needs some help. */ - Span as_span() const + constexpr Span as_span() const { return Span(data_, size_); } @@ -593,7 +595,7 @@ template class MutableSpan { * Utility to make it more convenient to iterate over all indices that can be used with this * array. */ - IndexRange index_range() const + constexpr IndexRange index_range() const { return IndexRange(size_); } @@ -602,7 +604,7 @@ template class MutableSpan { * Returns a reference to the last element. This invokes undefined behavior when the array is * empty. */ - T &last() const + constexpr T &last() const { BLI_assert(size_ > 0); return data_[size_ - 1]; @@ -612,7 +614,7 @@ template class MutableSpan { * Does a linear search to count how often the value is in the array. * Returns the number of occurrences. */ - int64_t count(const T &value) const + constexpr int64_t count(const T &value) const { int64_t counter = 0; for (const T &element : *this) { @@ -628,7 +630,7 @@ template class MutableSpan { * destination contains uninitialized data and T is not trivially copy constructible. * The size of both spans is expected to be the same. */ - void copy_from(Span values) + constexpr void copy_from(Span values) { BLI_assert(size_ == values.size()); initialized_copy_n(values.data(), size_, data_); @@ -637,7 +639,7 @@ template class MutableSpan { /** * Returns a new span to the same underlying memory buffer. No conversions are done. */ - template MutableSpan cast() const + template constexpr MutableSpan cast() const { BLI_assert((size_ * sizeof(T)) % sizeof(NewT) == 0); int64_t new_size = size_ * sizeof(T) / sizeof(NewT); @@ -648,7 +650,7 @@ template class MutableSpan { /** * Utilities to check that arrays have the same size in debug builds. */ -template void assert_same_size(const T1 &v1, const T2 &v2) +template constexpr void assert_same_size(const T1 &v1, const T2 &v2) { UNUSED_VARS_NDEBUG(v1, v2); #ifdef DEBUG @@ -659,7 +661,7 @@ template void assert_same_size(const T1 &v1, const T2 } template -void assert_same_size(const T1 &v1, const T2 &v2, const T3 &v3) +constexpr void assert_same_size(const T1 &v1, const T2 &v2, const T3 &v3) { UNUSED_VARS_NDEBUG(v1, v2, v3); #ifdef DEBUG diff --git a/source/blender/blenlib/BLI_string_ref.hh b/source/blender/blenlib/BLI_string_ref.hh index 8597e54d03b..a2562c6100a 100644 --- a/source/blender/blenlib/BLI_string_ref.hh +++ b/source/blender/blenlib/BLI_string_ref.hh @@ -64,7 +64,7 @@ class StringRefBase { const char *data_; int64_t size_; - StringRefBase(const char *data, const int64_t size) : data_(data), size_(size) + constexpr StringRefBase(const char *data, const int64_t size) : data_(data), size_(size) { } @@ -75,12 +75,12 @@ class StringRefBase { /** * Return the (byte-)length of the referenced string, without any null-terminator. */ - int64_t size() const + constexpr int64_t size() const { return size_; } - bool is_empty() const + constexpr bool is_empty() const { return size_ == 0; } @@ -88,12 +88,12 @@ class StringRefBase { /** * Return a pointer to the start of the string. */ - const char *data() const + constexpr const char *data() const { return data_; } - operator Span() const + constexpr operator Span() const { return Span(data_, size_); } @@ -107,22 +107,22 @@ class StringRefBase { return std::string(data_, static_cast(size_)); } - operator std::string_view() const + constexpr operator std::string_view() const { return std::string_view(data_, static_cast(size_)); } - const char *begin() const + constexpr const char *begin() const { return data_; } - const char *end() const + constexpr const char *end() const { return data_ + size_; } - IndexRange index_range() const + constexpr IndexRange index_range() const { return IndexRange(size_); } @@ -165,19 +165,19 @@ class StringRefBase { /** * Returns true when the string begins with the given prefix. Otherwise false. */ - bool startswith(StringRef prefix) const; + constexpr bool startswith(StringRef prefix) const; /** * Returns true when the string ends with the given suffix. Otherwise false. */ - bool endswith(StringRef suffix) const; + constexpr bool endswith(StringRef suffix) const; - StringRef substr(int64_t start, const int64_t size) const; + constexpr StringRef substr(int64_t start, const int64_t size) const; /** * Get the first char in the string. This invokes undefined behavior when the string is empty. */ - const char &front() const + constexpr const char &front() const { BLI_assert(size_ >= 1); return data_[0]; @@ -186,7 +186,7 @@ class StringRefBase { /** * Get the last char in the string. This invokes undefined behavior when the string is empty. */ - const char &back() const + constexpr const char &back() const { BLI_assert(size_ >= 1); return data_[size_ - 1]; @@ -196,18 +196,18 @@ class StringRefBase { * The behavior of those functions matches the standard library implementation of * std::string_view. */ - int64_t find(char c, int64_t pos = 0) const; - int64_t find(StringRef str, int64_t pos = 0) const; - int64_t rfind(char c, int64_t pos = INT64_MAX) const; - int64_t rfind(StringRef str, int64_t pos = INT64_MAX) const; - int64_t find_first_of(StringRef chars, int64_t pos = 0) const; - int64_t find_first_of(char c, int64_t pos = 0) const; - int64_t find_last_of(StringRef chars, int64_t pos = INT64_MAX) const; - int64_t find_last_of(char c, int64_t pos = INT64_MAX) const; - int64_t find_first_not_of(StringRef chars, int64_t pos = 0) const; - int64_t find_first_not_of(char c, int64_t pos = 0) const; - int64_t find_last_not_of(StringRef chars, int64_t pos = INT64_MAX) const; - int64_t find_last_not_of(char c, int64_t pos = INT64_MAX) const; + constexpr int64_t find(char c, int64_t pos = 0) const; + constexpr int64_t find(StringRef str, int64_t pos = 0) const; + constexpr int64_t rfind(char c, int64_t pos = INT64_MAX) const; + constexpr int64_t rfind(StringRef str, int64_t pos = INT64_MAX) const; + constexpr int64_t find_first_of(StringRef chars, int64_t pos = 0) const; + constexpr int64_t find_first_of(char c, int64_t pos = 0) const; + constexpr int64_t find_last_of(StringRef chars, int64_t pos = INT64_MAX) const; + constexpr int64_t find_last_of(char c, int64_t pos = INT64_MAX) const; + constexpr int64_t find_first_not_of(StringRef chars, int64_t pos = 0) const; + constexpr int64_t find_first_not_of(char c, int64_t pos = 0) const; + constexpr int64_t find_last_not_of(StringRef chars, int64_t pos = INT64_MAX) const; + constexpr int64_t find_last_not_of(char c, int64_t pos = INT64_MAX) const; }; /** @@ -216,7 +216,7 @@ class StringRefBase { class StringRefNull : public StringRefBase { public: - StringRefNull() : StringRefBase("", 0) + constexpr StringRefNull() : StringRefBase("", 0) { } @@ -226,7 +226,7 @@ class StringRefNull : public StringRefBase { */ StringRefNull(const char *str) : StringRefBase(str, static_cast(strlen(str))) { - BLI_assert(str != NULL); + BLI_assert(str != nullptr); BLI_assert(data_[size_] == '\0'); } @@ -234,7 +234,7 @@ class StringRefNull : public StringRefBase { * Construct a StringRefNull from a null terminated c-string. This invokes undefined behavior * when the given size is not the correct size of the string. */ - StringRefNull(const char *str, const int64_t size) : StringRefBase(str, size) + constexpr StringRefNull(const char *str, const int64_t size) : StringRefBase(str, size) { BLI_assert(static_cast(strlen(str)) == size); } @@ -250,7 +250,7 @@ class StringRefNull : public StringRefBase { /** * Get the char at the given index. */ - char operator[](const int64_t index) const + constexpr char operator[](const int64_t index) const { BLI_assert(index >= 0); /* Use '<=' instead of just '<', so that the null character can be accessed as well. */ @@ -263,7 +263,7 @@ class StringRefNull : public StringRefBase { * * This is like ->data(), but can only be called on a StringRefNull. */ - const char *c_str() const + constexpr const char *c_str() const { return data_; } @@ -274,25 +274,26 @@ class StringRefNull : public StringRefBase { */ class StringRef : public StringRefBase { public: - StringRef() : StringRefBase(nullptr, 0) + constexpr StringRef() : StringRefBase(nullptr, 0) { } /** * StringRefNull can be converted into StringRef, but not the other way around. */ - StringRef(StringRefNull other) : StringRefBase(other.data(), other.size()) + constexpr StringRef(StringRefNull other) : StringRefBase(other.data(), other.size()) { } /** * Create a StringRef from a null-terminated c-string. */ - StringRef(const char *str) : StringRefBase(str, str ? static_cast(strlen(str)) : 0) + constexpr StringRef(const char *str) + : StringRefBase(str, str ? static_cast(std::char_traits::length(str)) : 0) { } - StringRef(const char *str, const int64_t length) : StringRefBase(str, length) + constexpr StringRef(const char *str, const int64_t length) : StringRefBase(str, length) { } @@ -300,7 +301,7 @@ class StringRef : public StringRefBase { * Create a StringRef from a start and end pointer. This invokes undefined behavior when the * second point points to a smaller address than the first one. */ - StringRef(const char *begin, const char *one_after_end) + constexpr StringRef(const char *begin, const char *one_after_end) : StringRefBase(begin, static_cast(one_after_end - begin)) { BLI_assert(begin <= one_after_end); @@ -314,7 +315,8 @@ class StringRef : public StringRefBase { { } - StringRef(std::string_view view) : StringRefBase(view.data(), static_cast(view.size())) + constexpr StringRef(std::string_view view) + : StringRefBase(view.data(), static_cast(view.size())) { } @@ -323,7 +325,7 @@ class StringRef : public StringRefBase { * * This is similar to std::string_view::remove_prefix. */ - StringRef drop_prefix(const int64_t n) const + constexpr StringRef drop_prefix(const int64_t n) const { BLI_assert(n >= 0); BLI_assert(n <= size_); @@ -334,7 +336,7 @@ class StringRef : public StringRefBase { * Return a new StringRef with the given prefix being skipped. This invokes undefined behavior if * the string does not begin with the given prefix. */ - StringRef drop_prefix(StringRef prefix) const + constexpr StringRef drop_prefix(StringRef prefix) const { BLI_assert(this->startswith(prefix)); return this->drop_prefix(prefix.size()); @@ -345,7 +347,7 @@ class StringRef : public StringRefBase { * * This is similar to std::string_view::remove_suffix. */ - StringRef drop_suffix(const int64_t n) const + constexpr StringRef drop_suffix(const int64_t n) const { BLI_assert(n >= 0); BLI_assert(n <= size_); @@ -355,7 +357,7 @@ class StringRef : public StringRefBase { /** * Get the char at the given index. */ - char operator[](int64_t index) const + constexpr char operator[](int64_t index) const { BLI_assert(index >= 0); BLI_assert(index < size_); @@ -391,7 +393,7 @@ inline std::string operator+(StringRef a, StringRef b) * not a problem when std::string_view is only used at api boundaries. To compare a StringRef and a * std::string_view, one should convert the std::string_view to StringRef (which is very cheap). * Ideally, we only use StringRef in our code to avoid this problem altogether. */ -inline bool operator==(StringRef a, StringRef b) +constexpr inline bool operator==(StringRef a, StringRef b) { if (a.size() != b.size()) { return false; @@ -399,27 +401,27 @@ inline bool operator==(StringRef a, StringRef b) return STREQLEN(a.data(), b.data(), (size_t)a.size()); } -inline bool operator!=(StringRef a, StringRef b) +constexpr inline bool operator!=(StringRef a, StringRef b) { return !(a == b); } -inline bool operator<(StringRef a, StringRef b) +constexpr inline bool operator<(StringRef a, StringRef b) { return std::string_view(a) < std::string_view(b); } -inline bool operator>(StringRef a, StringRef b) +constexpr inline bool operator>(StringRef a, StringRef b) { return std::string_view(a) > std::string_view(b); } -inline bool operator<=(StringRef a, StringRef b) +constexpr inline bool operator<=(StringRef a, StringRef b) { return std::string_view(a) <= std::string_view(b); } -inline bool operator>=(StringRef a, StringRef b) +constexpr inline bool operator>=(StringRef a, StringRef b) { return std::string_view(a) >= std::string_view(b); } @@ -427,7 +429,7 @@ inline bool operator>=(StringRef a, StringRef b) /** * Return true when the string starts with the given prefix. */ -inline bool StringRefBase::startswith(StringRef prefix) const +constexpr inline bool StringRefBase::startswith(StringRef prefix) const { if (size_ < prefix.size_) { return false; @@ -443,7 +445,7 @@ inline bool StringRefBase::startswith(StringRef prefix) const /** * Return true when the string ends with the given suffix. */ -inline bool StringRefBase::endswith(StringRef suffix) const +constexpr inline bool StringRefBase::endswith(StringRef suffix) const { if (size_ < suffix.size_) { return false; @@ -460,8 +462,8 @@ inline bool StringRefBase::endswith(StringRef suffix) const /** * Return a new #StringRef containing only a sub-string of the original string. */ -inline StringRef StringRefBase::substr(const int64_t start, - const int64_t max_size = INT64_MAX) const +constexpr inline StringRef StringRefBase::substr(const int64_t start, + const int64_t max_size = INT64_MAX) const { BLI_assert(max_size >= 0); BLI_assert(start >= 0); @@ -469,7 +471,7 @@ inline StringRef StringRefBase::substr(const int64_t start, return StringRef(data_ + start, substr_size); } -inline int64_t index_or_npos_to_int64(size_t index) +constexpr inline int64_t index_or_npos_to_int64(size_t index) { /* The compiler will probably optimize this check away. */ if (index == std::string_view::npos) { @@ -478,62 +480,62 @@ inline int64_t index_or_npos_to_int64(size_t index) return static_cast(index); } -inline int64_t StringRefBase::find(char c, int64_t pos) const +constexpr inline int64_t StringRefBase::find(char c, int64_t pos) const { BLI_assert(pos >= 0); return index_or_npos_to_int64(std::string_view(*this).find(c, static_cast(pos))); } -inline int64_t StringRefBase::find(StringRef str, int64_t pos) const +constexpr inline int64_t StringRefBase::find(StringRef str, int64_t pos) const { BLI_assert(pos >= 0); return index_or_npos_to_int64(std::string_view(*this).find(str, static_cast(pos))); } -inline int64_t StringRefBase::find_first_of(StringRef chars, int64_t pos) const +constexpr inline int64_t StringRefBase::find_first_of(StringRef chars, int64_t pos) const { BLI_assert(pos >= 0); return index_or_npos_to_int64( std::string_view(*this).find_first_of(chars, static_cast(pos))); } -inline int64_t StringRefBase::find_first_of(char c, int64_t pos) const +constexpr inline int64_t StringRefBase::find_first_of(char c, int64_t pos) const { return this->find_first_of(StringRef(&c, 1), pos); } -inline int64_t StringRefBase::find_last_of(StringRef chars, int64_t pos) const +constexpr inline int64_t StringRefBase::find_last_of(StringRef chars, int64_t pos) const { BLI_assert(pos >= 0); return index_or_npos_to_int64( std::string_view(*this).find_last_of(chars, static_cast(pos))); } -inline int64_t StringRefBase::find_last_of(char c, int64_t pos) const +constexpr inline int64_t StringRefBase::find_last_of(char c, int64_t pos) const { return this->find_last_of(StringRef(&c, 1), pos); } -inline int64_t StringRefBase::find_first_not_of(StringRef chars, int64_t pos) const +constexpr inline int64_t StringRefBase::find_first_not_of(StringRef chars, int64_t pos) const { BLI_assert(pos >= 0); return index_or_npos_to_int64( std::string_view(*this).find_first_not_of(chars, static_cast(pos))); } -inline int64_t StringRefBase::find_first_not_of(char c, int64_t pos) const +constexpr inline int64_t StringRefBase::find_first_not_of(char c, int64_t pos) const { return this->find_first_not_of(StringRef(&c, 1), pos); } -inline int64_t StringRefBase::find_last_not_of(StringRef chars, int64_t pos) const +constexpr inline int64_t StringRefBase::find_last_not_of(StringRef chars, int64_t pos) const { BLI_assert(pos >= 0); return index_or_npos_to_int64( std::string_view(*this).find_last_not_of(chars, static_cast(pos))); } -inline int64_t StringRefBase::find_last_not_of(char c, int64_t pos) const +constexpr inline int64_t StringRefBase::find_last_not_of(char c, int64_t pos) const { return this->find_last_not_of(StringRef(&c, 1), pos); } diff --git a/source/blender/blenlib/tests/BLI_index_range_test.cc b/source/blender/blenlib/tests/BLI_index_range_test.cc index d472ded0f18..ddaa067f50e 100644 --- a/source/blender/blenlib/tests/BLI_index_range_test.cc +++ b/source/blender/blenlib/tests/BLI_index_range_test.cc @@ -140,4 +140,11 @@ TEST(index_range, AsSpan) EXPECT_EQ(span[3], 7); } +TEST(index_range, constexpr_) +{ + constexpr IndexRange range = IndexRange(1, 1); + std::array compiles = {1}; + BLI_STATIC_ASSERT(range.size() == 1, ""); + EXPECT_EQ(compiles[0], 1); +} } // namespace blender::tests diff --git a/source/blender/blenlib/tests/BLI_span_test.cc b/source/blender/blenlib/tests/BLI_span_test.cc index 9a8d9df7873..d1c9f312b97 100644 --- a/source/blender/blenlib/tests/BLI_span_test.cc +++ b/source/blender/blenlib/tests/BLI_span_test.cc @@ -337,4 +337,19 @@ TEST(span, MutableReverseIterator) EXPECT_EQ_ARRAY(src.data(), Span({14, 15, 16, 17}).data(), 4); } +TEST(span, constexpr_) +{ + static constexpr std::array src = {3, 2, 1}; + constexpr Span span(src); + BLI_STATIC_ASSERT(span[2] == 1, ""); + BLI_STATIC_ASSERT(span.size() == 3, ""); + BLI_STATIC_ASSERT(span.slice(1, 2).size() == 2, ""); + BLI_STATIC_ASSERT(span.has_duplicates__linear_search() == false, ""); + + std::integral_constant ic; + BLI_STATIC_ASSERT(ic.value, ""); + + EXPECT_EQ(span.slice(1, 2).size(), 2); +} + } // namespace blender::tests diff --git a/source/blender/blenlib/tests/BLI_string_ref_test.cc b/source/blender/blenlib/tests/BLI_string_ref_test.cc index 2d488feff71..401a7bc1118 100644 --- a/source/blender/blenlib/tests/BLI_string_ref_test.cc +++ b/source/blender/blenlib/tests/BLI_string_ref_test.cc @@ -298,4 +298,12 @@ TEST(string_ref, ToStringView) EXPECT_EQ(view, "hello"); } +TEST(string_ref, constexpr_) +{ + constexpr StringRef sref("World"); + BLI_STATIC_ASSERT(sref[2] == 'r', ""); + BLI_STATIC_ASSERT(sref.size() == 5, ""); + std::array(sref.find_first_of('o'))> compiles = {1}; + EXPECT_EQ(compiles[0], 1); +} } // namespace blender::tests -- cgit v1.2.3 From 1a375d6eceed4c17f92fd90699645856e0951530 Mon Sep 17 00:00:00 2001 From: Nathan Letwory Date: Wed, 16 Dec 2020 11:06:36 +0100 Subject: Steam Release: Script creation of Steam build files Script tool for automation of Steam build files for tasks like {T77348} For in-depth information see the README. Related Wiki page: https://wiki.blender.org/wiki/Process/Release_On_Steam Reviewed By: jbakker Maniphest Tasks: T77348 Differential Revision: https://developer.blender.org/D8429 --- release/datafiles/locale | 2 +- release/scripts/addons | 2 +- release/steam/README.md | 70 +++++ release/steam/blender_app_build.vdf.template | 17 ++ release/steam/create_steam_builds.py | 397 +++++++++++++++++++++++++++ release/steam/depot_build_linux.vdf.template | 31 +++ release/steam/depot_build_macos.vdf.template | 30 ++ release/steam/depot_build_win.vdf.template | 31 +++ 8 files changed, 578 insertions(+), 2 deletions(-) create mode 100644 release/steam/README.md create mode 100644 release/steam/blender_app_build.vdf.template create mode 100644 release/steam/create_steam_builds.py create mode 100644 release/steam/depot_build_linux.vdf.template create mode 100644 release/steam/depot_build_macos.vdf.template create mode 100644 release/steam/depot_build_win.vdf.template diff --git a/release/datafiles/locale b/release/datafiles/locale index 9e40c01dffd..877a343fed9 160000 --- a/release/datafiles/locale +++ b/release/datafiles/locale @@ -1 +1 @@ -Subproject commit 9e40c01dffd3f720b23b906d20df8e999d34a4af +Subproject commit 877a343fed9613d8e02e7fe7181d3bbb628506f2 diff --git a/release/scripts/addons b/release/scripts/addons index 1a3f127714e..f8a16827a25 160000 --- a/release/scripts/addons +++ b/release/scripts/addons @@ -1 +1 @@ -Subproject commit 1a3f127714e8da9f0af12d9a174dae9793ae63c1 +Subproject commit f8a16827a2568088e5206e9d4432c5b57aae3eb5 diff --git a/release/steam/README.md b/release/steam/README.md new file mode 100644 index 00000000000..05eda799c3f --- /dev/null +++ b/release/steam/README.md @@ -0,0 +1,70 @@ +Creating Steam builds for Blender +================================= + +This script automates creation of the Steam files: download of the archives, +extraction of the archives, preparation of the build scripts (VDF files), actual +building of the Steam game files. + +Requirements +============ + +* MacOS machine - Tested on Catalina 10.15.6. Extracting contents from the DMG + archive did not work Windows nor on Linux using 7-zip. All DMG archives tested + failed to be extracted. As such only MacOS is known to work. +* Steam SDK downloaded from SteamWorks - The `steamcmd` is used to generate the + Steam game files. The path to the `steamcmd` is what is actually needed. +* SteamWorks credentials - Needed to log in using `steamcmd`. +* Login to SteamWorks with the `steamcmd` from the command-line at least once - + Needded to ensure the user is properly logged in. On a new machine the user + will have to go through two-factor authentication. +* App ID and Depot IDs - Needed to create the VDF files. +* Python 3.x - 3.7 was tested. +* Base URL - for downloading the archives. + +Usage +===== + +```bash +$ export STEAMUSER=SteamUserName +$ export STEAMPW=SteamUserPW +$ export BASEURL=https://download.blender.org/release/Blender2.83/ +$ export VERSION=2.83.3 +$ export APPID=appidnr +$ export WINID=winidnr +$ export LINID=linuxidnr +$ export MACOSID=macosidnr + +# log in to SteamWorks from command-line at least once + +$ ../sdk/tools/ContentBuilder/builder_osx/steamcmd +login $STEAMUSER $STEAMPW + +# once that has been done we can now actually start our tool + +$ python3.7 create_steam_builds.py --baseurl $BASEURL --version $VERSION --appid $APPID --winid $WINID --linuxid $LINID --macosid $MACOSID --steamuser $STEAMUSER --steampw $STEAMPW --steamcmd ../sdk/tools/ContentBuilder/builder_osx/steamcmd +``` + +All arguments in the above example are required. + +At the start the tool will login using `steamcmd`. This is necessary to let the +Steam SDK update itself if necessary. + +There are a few optional arguments: + +* `--dryrun`: If set building the game files will not actually happen. A set of + log files and a preview manifest per depot will be created in the output folder. + This can be used to double-check everything works as expected. +* `--skipdl`: If set will skip downloading of the archives. The tool expects the + archives to already exist in the correct content location. +* `--skipextract`: If set will skip extraction of all archives. The tool expects + the archives to already have been correctly extracted in the content location. + +Run the tool with `-h` for detailed information on each argument. + +The content and output folders are generated through appending the version +without dots to the words `content` and `output` respectively, e.g. `content2833` +and `output2833`. These folders are created next to the tool. + +From all `.template` files the Steam build scripts will be generated also in the +same directory as the tool. The files will have the extension `.vdf`. + +In case of errors the tool will have a non-zero return code. \ No newline at end of file diff --git a/release/steam/blender_app_build.vdf.template b/release/steam/blender_app_build.vdf.template new file mode 100644 index 00000000000..9e2d0625d72 --- /dev/null +++ b/release/steam/blender_app_build.vdf.template @@ -0,0 +1,17 @@ +"appbuild" +{ + "appid" "[APPID]" + "desc" "Blender [VERSION]" // description for this build + "buildoutput" "./[OUTPUT]" // build output folder for .log, .csm & .csd files, relative to location of this file + "contentroot" "./[CONTENT]" // root content folder, relative to location of this file + "setlive" "" // branch to set live after successful build, non if empty + "preview" "[DRYRUN]" // 1 to enable preview builds, 0 to commit build to steampipe + "local" "" // set to flie path of local content server + + "depots" + { + "[WINID]" "depot_build_win.vdf" + "[LINUXID]" "depot_build_linux.vdf" + "[MACOSID]" "depot_build_macos.vdf" + } +} diff --git a/release/steam/create_steam_builds.py b/release/steam/create_steam_builds.py new file mode 100644 index 00000000000..2ecd0c347f7 --- /dev/null +++ b/release/steam/create_steam_builds.py @@ -0,0 +1,397 @@ +#!/usr/bin/env python3 + +import argparse +import pathlib +import requests +import shutil +import subprocess +from typing import Callable, Iterator, List, Tuple + +# supported archive and platform endings, used to create actual archive names +archive_endings = ["windows64.zip", "linux64.tar.xz", "macOS.dmg"] + + +def add_optional_argument(option: str, help: str) -> None: + global parser + """Add an optional argument + + Args: + option (str): Option to add + help (str): Help description for the argument + """ + parser.add_argument(option, help=help, action='store_const', const=1) + + +def blender_archives(version: str) -> Iterator[str]: + """Generator for Blender archives for version. + + Yields for items in archive_endings an archive name in the form of + blender-{version}-{ending}. + + Args: + version (str): Version string of the form 2.83.2 + + + Yields: + Iterator[str]: Name in the form of blender-{version}-{ending} + """ + global archive_endings + + for ending in archive_endings: + yield f"blender-{version}-{ending}" + + +def get_archive_type(archive_type: str, version: str) -> str: + """Return the archive of given type and version. + + Args: + archive_type (str): extension for archive type to check for + version (str): Version string in the form 2.83.2 + + Raises: + Exception: Execption when archive type isn't found + + Returns: + str: archive name for given type + """ + + for archive in blender_archives(version): + if archive.endswith(archive_type): + return archive + raise Exception("Unknown archive type") + + +def execute_command(cmd: List[str], name: str, errcode: int, cwd=".", capture_output=True) -> str: + """Execute the given command. + + Returns the process stdout upon success if any. + + On error print message the command with name that has failed. Print stdout + and stderr of the process if any, and then exit with given error code. + + Args: + cmd (List[str]): Command in list format, each argument as their own item + name (str): Name of command to use when printing to command-line + errcode (int): Error code to use in case of exit() + cwd (str, optional): Folder to use as current work directory for command + execution. Defaults to ".". + capture_output (bool, optional): Whether to capture command output or not. + Defaults to True. + + Returns: + str: stdout if any, or empty string + """ + cmd_process = subprocess.run( + cmd, capture_output=capture_output, encoding="UTF-8", cwd=cwd) + if cmd_process.returncode == 0: + if cmd_process.stdout: + return cmd_process.stdout + else: + return "" + else: + print(f"ERROR: {name} failed.") + if cmd_process.stdout: + print(cmd_process.stdout) + if cmd_process.stderr: + print(cmd_process.stderr) + exit(errcode) + return "" + + +def download_archives(base_url: str, archives: Callable[[str], Iterator[str]], version: str, dst_dir: pathlib.Path): + """Download archives from the given base_url. + + Archives is a generator for Blender archive names based on version. + + Archive names are appended to the base_url to load from, and appended to + dst_dir to save to. + + Args: + base_url (str): Base URL to load archives from + archives (Callable[[str], Iterator[str]]): Generator for Blender archive + names based on version + version (str): Version string in the form of 2.83.2 + dst_dir (pathlib.Path): Download destination + """ + + if base_url[-1] != '/': + base_url = base_url + '/' + + for archive in archives(version): + download_url = f"{base_url}{archive}" + target_file = dst_dir.joinpath(archive) + download_file(download_url, target_file) + + +def download_file(from_url: str, to_file: pathlib.Path) -> None: + """Download from_url as to_file. + + Actual downloading will be skipped if --skipdl is given on the command-line. + + Args: + from_url (str): Full URL to resource to download + to_file (pathlib.Path): Full path to save downloaded resource as + """ + global args + + if not args.skipdl or not to_file.exists(): + print(f"Downloading {from_url}") + with open(to_file, "wb") as download_zip: + response = requests.get(from_url) + if response.status_code != requests.codes.ok: + print(f"ERROR: failed to download {from_url} (status code: {response.status_code})") + exit(1313) + download_zip.write(response.content) + else: + print(f"Downloading {from_url} skipped") + print(" ... OK") + + +def copy_contents_from_dmg_to_path(dmg_file: pathlib.Path, dst: pathlib.Path) -> None: + """Copy the contents of the given DMG file to the destination folder. + + Args: + dmg_file (pathlib.Path): Full path to DMG archive to extract from + dst (pathlib.Path): Full path to destination to extract to + """ + hdiutil_attach = ["hdiutil", + "attach", + "-readonly", + f"{dmg_file}" + ] + attached = execute_command(hdiutil_attach, "hdiutil attach", 1) + + # Last line of output is what we want, it is of the form + # /dev/somedisk Apple_HFS /Volumes/Blender + # We want to retain the mount point, and the folder the mount is + # created on. The mounted disk we need for detaching, the folder we + # need to be able to copy the contents to where we can use them + attachment_items = attached.splitlines()[-1].split() + mounted_disk = attachment_items[0] + source_location = pathlib.Path(attachment_items[2], "Blender.app") + + print(f"{source_location} -> {dst}") + + shutil.copytree(source_location, dst) + + hdiutil_detach = ["hdiutil", + "detach", + f"{mounted_disk}" + ] + execute_command(hdiutil_detach, "hdiutil detach", 2) + + +def create_build_script(template_name: str, vars: List[Tuple[str, str]]) -> pathlib.Path: + """ + Create the Steam build script + + Use the given template and template variable tuple list. + + Returns pathlib.Path to the created script. + + Args: + template_name (str): [description] + vars (List[Tuple[str, str]]): [description] + + Returns: + pathlib.Path: Full path to the generated script + """ + build_script = pathlib.Path(".", template_name).read_text() + for var in vars: + build_script = build_script.replace(var[0], var[1]) + build_script_file = template_name.replace(".template", "") + build_script_path = pathlib.Path(".", build_script_file) + build_script_path.write_text(build_script) + return build_script_path + + +def clean_up() -> None: + """Remove intermediate files depending on given command-line arguments + """ + global content_location, args + + if not args.leavearch and not args.leaveextracted: + shutil.rmtree(content_location) + + if args.leavearch and not args.leaveextracted: + shutil.rmtree(content_location.joinpath(zip_extract_folder)) + shutil.rmtree(content_location.joinpath(tarxz_extract_folder)) + shutil.rmtree(content_location.joinpath(dmg_extract_folder)) + + if args.leaveextracted and not args.leavearch: + import os + os.remove(content_location.joinpath(zipped_blender)) + os.remove(content_location.joinpath(tarxz_blender)) + os.remove(content_location.joinpath(dmg_blender)) + + +def extract_archive(archive: str, extract_folder_name: str, + cmd: List[str], errcode: int) -> None: + """Extract all files from archive to given folder name. + + Will not extract if + target folder already exists, or if --skipextract was given on the + command-line. + + Args: + archive (str): Archive name to extract + extract_folder_name (str): Folder name to extract to + cmd (List[str]): Command with arguments to use + errcode (int): Error code to use for exit() + """ + global args, content_location + + extract_location = content_location.joinpath(extract_folder_name) + + pre_extract = set(content_location.glob("*")) + + if not args.skipextract or not extract_location.exists(): + print(f"Extracting files from {archive}...") + cmd.append(content_location.joinpath(archive)) + execute_command(cmd, cmd[0], errcode, cwd=content_location) + # in case we use a non-release archive the naming will be incorrect. + # simply rename to expected target name + post_extract = set(content_location.glob("*")) + diff_extract = post_extract - pre_extract + if not extract_location in diff_extract: + folder_to_rename = list(diff_extract)[0] + folder_to_rename.rename(extract_location) + print(" OK") + else: + print(f"Skipping extraction {archive}!") + +# ============================================================================== + + +parser = argparse.ArgumentParser() + +parser.add_argument("--baseurl", required=True, + help="The base URL for files to download, " + "i.e. https://download.blender.org/release/Blender2.83/") + +parser.add_argument("--version", required=True, + help="The Blender version to release, in the form 2.83.3") + +parser.add_argument("--appid", required=True, + help="The Blender App ID on Steam") +parser.add_argument("--winid", required=True, + help="The Windows depot ID") +parser.add_argument("--linuxid", required=True, + help="The Linux depot ID") +parser.add_argument("--macosid", required=True, + help="The MacOS depot ID") + +parser.add_argument("--steamcmd", required=True, + help="Path to the steamcmd") +parser.add_argument("--steamuser", required=True, + help="The login for the Steam builder user") +parser.add_argument("--steampw", required=True, + help="Login password for the Steam builder user") + +add_optional_argument("--dryrun", + "If set the Steam files will not be uploaded") +add_optional_argument("--leavearch", + help="If set don't clean up the downloaded archives") +add_optional_argument("--leaveextracted", + help="If set don't clean up the extraction folders") +add_optional_argument("--skipdl", + help="If set downloading the archives is skipped if it already exists locally.") +add_optional_argument("--skipextract", + help="If set skips extracting of archives. The tool assumes the archives" + "have already been extracted to their correct locations") + +args = parser.parse_args() + +VERSIONNODOTS = args.version.replace('.', '') +OUTPUT = f"output{VERSIONNODOTS}" +CONTENT = f"content{VERSIONNODOTS}" + +# ===== set up main locations + +content_location = pathlib.Path(".", CONTENT).absolute() +output_location = pathlib.Path(".", OUTPUT).absolute() + +content_location.mkdir(parents=True, exist_ok=True) +output_location.mkdir(parents=True, exist_ok=True) + +# ===== login + +# Logging into Steam once to ensure the SDK updates itself properly. If we don't +# do that the combined +login and +run_app_build_http at the end of the tool +# will fail. +steam_login = [args.steamcmd, + "+login", + args.steamuser, + args.steampw, + "+quit" + ] +print("Logging in to Steam...") +execute_command(steam_login, "Login to Steam", 10) +print(" OK") + +# ===== prepare Steam build scripts + +template_vars = [ + ("[APPID]", args.appid), + ("[OUTPUT]", OUTPUT), + ("[CONTENT]", CONTENT), + ("[VERSION]", args.version), + ("[WINID]", args.winid), + ("[LINUXID]", args.linuxid), + ("[MACOSID]", args.macosid), + ("[DRYRUN]", f"{args.dryrun}" if args.dryrun else "0") +] + +blender_app_build = create_build_script( + "blender_app_build.vdf.template", template_vars) +create_build_script("depot_build_win.vdf.template", template_vars) +create_build_script("depot_build_linux.vdf.template", template_vars) +create_build_script("depot_build_macos.vdf.template", template_vars) + +# ===== download archives + +download_archives(args.baseurl, blender_archives, + args.version, content_location) + +# ===== set up file and folder names + +zipped_blender = get_archive_type("zip", args.version) +zip_extract_folder = zipped_blender.replace(".zip", "") +tarxz_blender = get_archive_type("tar.xz", args.version) +tarxz_extract_folder = tarxz_blender.replace(".tar.xz", "") +dmg_blender = get_archive_type("dmg", args.version) +dmg_extract_folder = dmg_blender.replace(".dmg", "") + +# ===== extract + +unzip_cmd = ["unzip", "-q"] +extract_archive(zipped_blender, zip_extract_folder, unzip_cmd, 3) + +untarxz_cmd = ["tar", "-xf"] +extract_archive(tarxz_blender, tarxz_extract_folder, untarxz_cmd, 4) + +if not args.skipextract or not content_location.joinpath(dmg_extract_folder).exists(): + print("Extracting files from Blender MacOS archive...") + blender_dmg = content_location.joinpath(dmg_blender) + target_location = content_location.joinpath( + dmg_extract_folder, "Blender.app") + copy_contents_from_dmg_to_path(blender_dmg, target_location) + print(" OK") +else: + print("Skipping extraction of .dmg!") + +# ===== building + +print("Build Steam game files...") +steam_build = [args.steamcmd, + "+login", + args.steamuser, + args.steampw, + "+run_app_build_http", + blender_app_build.absolute(), + "+quit" + ] +execute_command(steam_build, "Build with steamcmd", 13) +print(" OK") + +clean_up() diff --git a/release/steam/depot_build_linux.vdf.template b/release/steam/depot_build_linux.vdf.template new file mode 100644 index 00000000000..0f69008548e --- /dev/null +++ b/release/steam/depot_build_linux.vdf.template @@ -0,0 +1,31 @@ +"DepotBuildConfig" +{ + // Set your assigned depot ID here + "DepotID" "[LINUXID]" + + // Set a root for all content. + // All relative paths specified below (LocalPath in FileMapping entries, and FileExclusion paths) + // will be resolved relative to this root. + // If you don't define ContentRoot, then it will be assumed to be + // the location of this script file, which probably isn't what you want + "ContentRoot" "./blender-[VERSION]-linux64/" + + // include all files recursivley + "FileMapping" + { + // This can be a full path, or a path relative to ContentRoot + "LocalPath" "*" + + // This is a path relative to the install folder of your game + "DepotPath" "." + + // If LocalPath contains wildcards, setting this means that all + // matching files within subdirectories of LocalPath will also + // be included. + "recursive" "1" + } + + // but exclude all symbol files + // This can be a full path, or a path relative to ContentRoot + "FileExclusion" "*.pdb" +} diff --git a/release/steam/depot_build_macos.vdf.template b/release/steam/depot_build_macos.vdf.template new file mode 100644 index 00000000000..33dde860462 --- /dev/null +++ b/release/steam/depot_build_macos.vdf.template @@ -0,0 +1,30 @@ +"DepotBuildConfig" +{ + // Set your assigned depot ID here + "DepotID" "[MACOSID]" + + // Set a root for all content. + // All relative paths specified below (LocalPath in FileMapping entries, and FileExclusion paths) + // will be resolved relative to this root. + // If you don't define ContentRoot, then it will be assumed to be + // the location of this script file, which probably isn't what you want + "ContentRoot" "./blender-[VERSION]-macOS/" + // include all files recursivley + "FileMapping" + { + // This can be a full path, or a path relative to ContentRoot + "LocalPath" "*" + + // This is a path relative to the install folder of your game + "DepotPath" "." + + // If LocalPath contains wildcards, setting this means that all + // matching files within subdirectories of LocalPath will also + // be included. + "recursive" "1" + } + + // but exclude all symbol files + // This can be a full path, or a path relative to ContentRoot + "FileExclusion" "*.pdb" +} diff --git a/release/steam/depot_build_win.vdf.template b/release/steam/depot_build_win.vdf.template new file mode 100644 index 00000000000..2c18a0f15dd --- /dev/null +++ b/release/steam/depot_build_win.vdf.template @@ -0,0 +1,31 @@ +"DepotBuildConfig" +{ + // Set your assigned depot ID here + "DepotID" "[WINID]" + + // Set a root for all content. + // All relative paths specified below (LocalPath in FileMapping entries, and FileExclusion paths) + // will be resolved relative to this root. + // If you don't define ContentRoot, then it will be assumed to be + // the location of this script file, which probably isn't what you want + "ContentRoot" "./blender-[VERSION]-windows64/" + + // include all files recursivley + "FileMapping" + { + // This can be a full path, or a path relative to ContentRoot + "LocalPath" "*" + + // This is a path relative to the install folder of your game + "DepotPath" "." + + // If LocalPath contains wildcards, setting this means that all + // matching files within subdirectories of LocalPath will also + // be included. + "recursive" "1" + } + + // but exclude all symbol files + // This can be a full path, or a path relative to ContentRoot + "FileExclusion" "*.pdb" +} -- cgit v1.2.3 From 9cbfcc4af500186ce8b30a915bef263a2cd1e1d5 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Wed, 16 Dec 2020 11:11:15 +0100 Subject: Revert "Steam Release: Script creation of Steam build files" This reverts commit 1a375d6eceed4c17f92fd90699645856e0951530. --- release/datafiles/locale | 2 +- release/scripts/addons | 2 +- release/steam/README.md | 70 ----- release/steam/blender_app_build.vdf.template | 17 -- release/steam/create_steam_builds.py | 397 --------------------------- release/steam/depot_build_linux.vdf.template | 31 --- release/steam/depot_build_macos.vdf.template | 30 -- release/steam/depot_build_win.vdf.template | 31 --- 8 files changed, 2 insertions(+), 578 deletions(-) delete mode 100644 release/steam/README.md delete mode 100644 release/steam/blender_app_build.vdf.template delete mode 100644 release/steam/create_steam_builds.py delete mode 100644 release/steam/depot_build_linux.vdf.template delete mode 100644 release/steam/depot_build_macos.vdf.template delete mode 100644 release/steam/depot_build_win.vdf.template diff --git a/release/datafiles/locale b/release/datafiles/locale index 877a343fed9..9e40c01dffd 160000 --- a/release/datafiles/locale +++ b/release/datafiles/locale @@ -1 +1 @@ -Subproject commit 877a343fed9613d8e02e7fe7181d3bbb628506f2 +Subproject commit 9e40c01dffd3f720b23b906d20df8e999d34a4af diff --git a/release/scripts/addons b/release/scripts/addons index f8a16827a25..1a3f127714e 160000 --- a/release/scripts/addons +++ b/release/scripts/addons @@ -1 +1 @@ -Subproject commit f8a16827a2568088e5206e9d4432c5b57aae3eb5 +Subproject commit 1a3f127714e8da9f0af12d9a174dae9793ae63c1 diff --git a/release/steam/README.md b/release/steam/README.md deleted file mode 100644 index 05eda799c3f..00000000000 --- a/release/steam/README.md +++ /dev/null @@ -1,70 +0,0 @@ -Creating Steam builds for Blender -================================= - -This script automates creation of the Steam files: download of the archives, -extraction of the archives, preparation of the build scripts (VDF files), actual -building of the Steam game files. - -Requirements -============ - -* MacOS machine - Tested on Catalina 10.15.6. Extracting contents from the DMG - archive did not work Windows nor on Linux using 7-zip. All DMG archives tested - failed to be extracted. As such only MacOS is known to work. -* Steam SDK downloaded from SteamWorks - The `steamcmd` is used to generate the - Steam game files. The path to the `steamcmd` is what is actually needed. -* SteamWorks credentials - Needed to log in using `steamcmd`. -* Login to SteamWorks with the `steamcmd` from the command-line at least once - - Needded to ensure the user is properly logged in. On a new machine the user - will have to go through two-factor authentication. -* App ID and Depot IDs - Needed to create the VDF files. -* Python 3.x - 3.7 was tested. -* Base URL - for downloading the archives. - -Usage -===== - -```bash -$ export STEAMUSER=SteamUserName -$ export STEAMPW=SteamUserPW -$ export BASEURL=https://download.blender.org/release/Blender2.83/ -$ export VERSION=2.83.3 -$ export APPID=appidnr -$ export WINID=winidnr -$ export LINID=linuxidnr -$ export MACOSID=macosidnr - -# log in to SteamWorks from command-line at least once - -$ ../sdk/tools/ContentBuilder/builder_osx/steamcmd +login $STEAMUSER $STEAMPW - -# once that has been done we can now actually start our tool - -$ python3.7 create_steam_builds.py --baseurl $BASEURL --version $VERSION --appid $APPID --winid $WINID --linuxid $LINID --macosid $MACOSID --steamuser $STEAMUSER --steampw $STEAMPW --steamcmd ../sdk/tools/ContentBuilder/builder_osx/steamcmd -``` - -All arguments in the above example are required. - -At the start the tool will login using `steamcmd`. This is necessary to let the -Steam SDK update itself if necessary. - -There are a few optional arguments: - -* `--dryrun`: If set building the game files will not actually happen. A set of - log files and a preview manifest per depot will be created in the output folder. - This can be used to double-check everything works as expected. -* `--skipdl`: If set will skip downloading of the archives. The tool expects the - archives to already exist in the correct content location. -* `--skipextract`: If set will skip extraction of all archives. The tool expects - the archives to already have been correctly extracted in the content location. - -Run the tool with `-h` for detailed information on each argument. - -The content and output folders are generated through appending the version -without dots to the words `content` and `output` respectively, e.g. `content2833` -and `output2833`. These folders are created next to the tool. - -From all `.template` files the Steam build scripts will be generated also in the -same directory as the tool. The files will have the extension `.vdf`. - -In case of errors the tool will have a non-zero return code. \ No newline at end of file diff --git a/release/steam/blender_app_build.vdf.template b/release/steam/blender_app_build.vdf.template deleted file mode 100644 index 9e2d0625d72..00000000000 --- a/release/steam/blender_app_build.vdf.template +++ /dev/null @@ -1,17 +0,0 @@ -"appbuild" -{ - "appid" "[APPID]" - "desc" "Blender [VERSION]" // description for this build - "buildoutput" "./[OUTPUT]" // build output folder for .log, .csm & .csd files, relative to location of this file - "contentroot" "./[CONTENT]" // root content folder, relative to location of this file - "setlive" "" // branch to set live after successful build, non if empty - "preview" "[DRYRUN]" // 1 to enable preview builds, 0 to commit build to steampipe - "local" "" // set to flie path of local content server - - "depots" - { - "[WINID]" "depot_build_win.vdf" - "[LINUXID]" "depot_build_linux.vdf" - "[MACOSID]" "depot_build_macos.vdf" - } -} diff --git a/release/steam/create_steam_builds.py b/release/steam/create_steam_builds.py deleted file mode 100644 index 2ecd0c347f7..00000000000 --- a/release/steam/create_steam_builds.py +++ /dev/null @@ -1,397 +0,0 @@ -#!/usr/bin/env python3 - -import argparse -import pathlib -import requests -import shutil -import subprocess -from typing import Callable, Iterator, List, Tuple - -# supported archive and platform endings, used to create actual archive names -archive_endings = ["windows64.zip", "linux64.tar.xz", "macOS.dmg"] - - -def add_optional_argument(option: str, help: str) -> None: - global parser - """Add an optional argument - - Args: - option (str): Option to add - help (str): Help description for the argument - """ - parser.add_argument(option, help=help, action='store_const', const=1) - - -def blender_archives(version: str) -> Iterator[str]: - """Generator for Blender archives for version. - - Yields for items in archive_endings an archive name in the form of - blender-{version}-{ending}. - - Args: - version (str): Version string of the form 2.83.2 - - - Yields: - Iterator[str]: Name in the form of blender-{version}-{ending} - """ - global archive_endings - - for ending in archive_endings: - yield f"blender-{version}-{ending}" - - -def get_archive_type(archive_type: str, version: str) -> str: - """Return the archive of given type and version. - - Args: - archive_type (str): extension for archive type to check for - version (str): Version string in the form 2.83.2 - - Raises: - Exception: Execption when archive type isn't found - - Returns: - str: archive name for given type - """ - - for archive in blender_archives(version): - if archive.endswith(archive_type): - return archive - raise Exception("Unknown archive type") - - -def execute_command(cmd: List[str], name: str, errcode: int, cwd=".", capture_output=True) -> str: - """Execute the given command. - - Returns the process stdout upon success if any. - - On error print message the command with name that has failed. Print stdout - and stderr of the process if any, and then exit with given error code. - - Args: - cmd (List[str]): Command in list format, each argument as their own item - name (str): Name of command to use when printing to command-line - errcode (int): Error code to use in case of exit() - cwd (str, optional): Folder to use as current work directory for command - execution. Defaults to ".". - capture_output (bool, optional): Whether to capture command output or not. - Defaults to True. - - Returns: - str: stdout if any, or empty string - """ - cmd_process = subprocess.run( - cmd, capture_output=capture_output, encoding="UTF-8", cwd=cwd) - if cmd_process.returncode == 0: - if cmd_process.stdout: - return cmd_process.stdout - else: - return "" - else: - print(f"ERROR: {name} failed.") - if cmd_process.stdout: - print(cmd_process.stdout) - if cmd_process.stderr: - print(cmd_process.stderr) - exit(errcode) - return "" - - -def download_archives(base_url: str, archives: Callable[[str], Iterator[str]], version: str, dst_dir: pathlib.Path): - """Download archives from the given base_url. - - Archives is a generator for Blender archive names based on version. - - Archive names are appended to the base_url to load from, and appended to - dst_dir to save to. - - Args: - base_url (str): Base URL to load archives from - archives (Callable[[str], Iterator[str]]): Generator for Blender archive - names based on version - version (str): Version string in the form of 2.83.2 - dst_dir (pathlib.Path): Download destination - """ - - if base_url[-1] != '/': - base_url = base_url + '/' - - for archive in archives(version): - download_url = f"{base_url}{archive}" - target_file = dst_dir.joinpath(archive) - download_file(download_url, target_file) - - -def download_file(from_url: str, to_file: pathlib.Path) -> None: - """Download from_url as to_file. - - Actual downloading will be skipped if --skipdl is given on the command-line. - - Args: - from_url (str): Full URL to resource to download - to_file (pathlib.Path): Full path to save downloaded resource as - """ - global args - - if not args.skipdl or not to_file.exists(): - print(f"Downloading {from_url}") - with open(to_file, "wb") as download_zip: - response = requests.get(from_url) - if response.status_code != requests.codes.ok: - print(f"ERROR: failed to download {from_url} (status code: {response.status_code})") - exit(1313) - download_zip.write(response.content) - else: - print(f"Downloading {from_url} skipped") - print(" ... OK") - - -def copy_contents_from_dmg_to_path(dmg_file: pathlib.Path, dst: pathlib.Path) -> None: - """Copy the contents of the given DMG file to the destination folder. - - Args: - dmg_file (pathlib.Path): Full path to DMG archive to extract from - dst (pathlib.Path): Full path to destination to extract to - """ - hdiutil_attach = ["hdiutil", - "attach", - "-readonly", - f"{dmg_file}" - ] - attached = execute_command(hdiutil_attach, "hdiutil attach", 1) - - # Last line of output is what we want, it is of the form - # /dev/somedisk Apple_HFS /Volumes/Blender - # We want to retain the mount point, and the folder the mount is - # created on. The mounted disk we need for detaching, the folder we - # need to be able to copy the contents to where we can use them - attachment_items = attached.splitlines()[-1].split() - mounted_disk = attachment_items[0] - source_location = pathlib.Path(attachment_items[2], "Blender.app") - - print(f"{source_location} -> {dst}") - - shutil.copytree(source_location, dst) - - hdiutil_detach = ["hdiutil", - "detach", - f"{mounted_disk}" - ] - execute_command(hdiutil_detach, "hdiutil detach", 2) - - -def create_build_script(template_name: str, vars: List[Tuple[str, str]]) -> pathlib.Path: - """ - Create the Steam build script - - Use the given template and template variable tuple list. - - Returns pathlib.Path to the created script. - - Args: - template_name (str): [description] - vars (List[Tuple[str, str]]): [description] - - Returns: - pathlib.Path: Full path to the generated script - """ - build_script = pathlib.Path(".", template_name).read_text() - for var in vars: - build_script = build_script.replace(var[0], var[1]) - build_script_file = template_name.replace(".template", "") - build_script_path = pathlib.Path(".", build_script_file) - build_script_path.write_text(build_script) - return build_script_path - - -def clean_up() -> None: - """Remove intermediate files depending on given command-line arguments - """ - global content_location, args - - if not args.leavearch and not args.leaveextracted: - shutil.rmtree(content_location) - - if args.leavearch and not args.leaveextracted: - shutil.rmtree(content_location.joinpath(zip_extract_folder)) - shutil.rmtree(content_location.joinpath(tarxz_extract_folder)) - shutil.rmtree(content_location.joinpath(dmg_extract_folder)) - - if args.leaveextracted and not args.leavearch: - import os - os.remove(content_location.joinpath(zipped_blender)) - os.remove(content_location.joinpath(tarxz_blender)) - os.remove(content_location.joinpath(dmg_blender)) - - -def extract_archive(archive: str, extract_folder_name: str, - cmd: List[str], errcode: int) -> None: - """Extract all files from archive to given folder name. - - Will not extract if - target folder already exists, or if --skipextract was given on the - command-line. - - Args: - archive (str): Archive name to extract - extract_folder_name (str): Folder name to extract to - cmd (List[str]): Command with arguments to use - errcode (int): Error code to use for exit() - """ - global args, content_location - - extract_location = content_location.joinpath(extract_folder_name) - - pre_extract = set(content_location.glob("*")) - - if not args.skipextract or not extract_location.exists(): - print(f"Extracting files from {archive}...") - cmd.append(content_location.joinpath(archive)) - execute_command(cmd, cmd[0], errcode, cwd=content_location) - # in case we use a non-release archive the naming will be incorrect. - # simply rename to expected target name - post_extract = set(content_location.glob("*")) - diff_extract = post_extract - pre_extract - if not extract_location in diff_extract: - folder_to_rename = list(diff_extract)[0] - folder_to_rename.rename(extract_location) - print(" OK") - else: - print(f"Skipping extraction {archive}!") - -# ============================================================================== - - -parser = argparse.ArgumentParser() - -parser.add_argument("--baseurl", required=True, - help="The base URL for files to download, " - "i.e. https://download.blender.org/release/Blender2.83/") - -parser.add_argument("--version", required=True, - help="The Blender version to release, in the form 2.83.3") - -parser.add_argument("--appid", required=True, - help="The Blender App ID on Steam") -parser.add_argument("--winid", required=True, - help="The Windows depot ID") -parser.add_argument("--linuxid", required=True, - help="The Linux depot ID") -parser.add_argument("--macosid", required=True, - help="The MacOS depot ID") - -parser.add_argument("--steamcmd", required=True, - help="Path to the steamcmd") -parser.add_argument("--steamuser", required=True, - help="The login for the Steam builder user") -parser.add_argument("--steampw", required=True, - help="Login password for the Steam builder user") - -add_optional_argument("--dryrun", - "If set the Steam files will not be uploaded") -add_optional_argument("--leavearch", - help="If set don't clean up the downloaded archives") -add_optional_argument("--leaveextracted", - help="If set don't clean up the extraction folders") -add_optional_argument("--skipdl", - help="If set downloading the archives is skipped if it already exists locally.") -add_optional_argument("--skipextract", - help="If set skips extracting of archives. The tool assumes the archives" - "have already been extracted to their correct locations") - -args = parser.parse_args() - -VERSIONNODOTS = args.version.replace('.', '') -OUTPUT = f"output{VERSIONNODOTS}" -CONTENT = f"content{VERSIONNODOTS}" - -# ===== set up main locations - -content_location = pathlib.Path(".", CONTENT).absolute() -output_location = pathlib.Path(".", OUTPUT).absolute() - -content_location.mkdir(parents=True, exist_ok=True) -output_location.mkdir(parents=True, exist_ok=True) - -# ===== login - -# Logging into Steam once to ensure the SDK updates itself properly. If we don't -# do that the combined +login and +run_app_build_http at the end of the tool -# will fail. -steam_login = [args.steamcmd, - "+login", - args.steamuser, - args.steampw, - "+quit" - ] -print("Logging in to Steam...") -execute_command(steam_login, "Login to Steam", 10) -print(" OK") - -# ===== prepare Steam build scripts - -template_vars = [ - ("[APPID]", args.appid), - ("[OUTPUT]", OUTPUT), - ("[CONTENT]", CONTENT), - ("[VERSION]", args.version), - ("[WINID]", args.winid), - ("[LINUXID]", args.linuxid), - ("[MACOSID]", args.macosid), - ("[DRYRUN]", f"{args.dryrun}" if args.dryrun else "0") -] - -blender_app_build = create_build_script( - "blender_app_build.vdf.template", template_vars) -create_build_script("depot_build_win.vdf.template", template_vars) -create_build_script("depot_build_linux.vdf.template", template_vars) -create_build_script("depot_build_macos.vdf.template", template_vars) - -# ===== download archives - -download_archives(args.baseurl, blender_archives, - args.version, content_location) - -# ===== set up file and folder names - -zipped_blender = get_archive_type("zip", args.version) -zip_extract_folder = zipped_blender.replace(".zip", "") -tarxz_blender = get_archive_type("tar.xz", args.version) -tarxz_extract_folder = tarxz_blender.replace(".tar.xz", "") -dmg_blender = get_archive_type("dmg", args.version) -dmg_extract_folder = dmg_blender.replace(".dmg", "") - -# ===== extract - -unzip_cmd = ["unzip", "-q"] -extract_archive(zipped_blender, zip_extract_folder, unzip_cmd, 3) - -untarxz_cmd = ["tar", "-xf"] -extract_archive(tarxz_blender, tarxz_extract_folder, untarxz_cmd, 4) - -if not args.skipextract or not content_location.joinpath(dmg_extract_folder).exists(): - print("Extracting files from Blender MacOS archive...") - blender_dmg = content_location.joinpath(dmg_blender) - target_location = content_location.joinpath( - dmg_extract_folder, "Blender.app") - copy_contents_from_dmg_to_path(blender_dmg, target_location) - print(" OK") -else: - print("Skipping extraction of .dmg!") - -# ===== building - -print("Build Steam game files...") -steam_build = [args.steamcmd, - "+login", - args.steamuser, - args.steampw, - "+run_app_build_http", - blender_app_build.absolute(), - "+quit" - ] -execute_command(steam_build, "Build with steamcmd", 13) -print(" OK") - -clean_up() diff --git a/release/steam/depot_build_linux.vdf.template b/release/steam/depot_build_linux.vdf.template deleted file mode 100644 index 0f69008548e..00000000000 --- a/release/steam/depot_build_linux.vdf.template +++ /dev/null @@ -1,31 +0,0 @@ -"DepotBuildConfig" -{ - // Set your assigned depot ID here - "DepotID" "[LINUXID]" - - // Set a root for all content. - // All relative paths specified below (LocalPath in FileMapping entries, and FileExclusion paths) - // will be resolved relative to this root. - // If you don't define ContentRoot, then it will be assumed to be - // the location of this script file, which probably isn't what you want - "ContentRoot" "./blender-[VERSION]-linux64/" - - // include all files recursivley - "FileMapping" - { - // This can be a full path, or a path relative to ContentRoot - "LocalPath" "*" - - // This is a path relative to the install folder of your game - "DepotPath" "." - - // If LocalPath contains wildcards, setting this means that all - // matching files within subdirectories of LocalPath will also - // be included. - "recursive" "1" - } - - // but exclude all symbol files - // This can be a full path, or a path relative to ContentRoot - "FileExclusion" "*.pdb" -} diff --git a/release/steam/depot_build_macos.vdf.template b/release/steam/depot_build_macos.vdf.template deleted file mode 100644 index 33dde860462..00000000000 --- a/release/steam/depot_build_macos.vdf.template +++ /dev/null @@ -1,30 +0,0 @@ -"DepotBuildConfig" -{ - // Set your assigned depot ID here - "DepotID" "[MACOSID]" - - // Set a root for all content. - // All relative paths specified below (LocalPath in FileMapping entries, and FileExclusion paths) - // will be resolved relative to this root. - // If you don't define ContentRoot, then it will be assumed to be - // the location of this script file, which probably isn't what you want - "ContentRoot" "./blender-[VERSION]-macOS/" - // include all files recursivley - "FileMapping" - { - // This can be a full path, or a path relative to ContentRoot - "LocalPath" "*" - - // This is a path relative to the install folder of your game - "DepotPath" "." - - // If LocalPath contains wildcards, setting this means that all - // matching files within subdirectories of LocalPath will also - // be included. - "recursive" "1" - } - - // but exclude all symbol files - // This can be a full path, or a path relative to ContentRoot - "FileExclusion" "*.pdb" -} diff --git a/release/steam/depot_build_win.vdf.template b/release/steam/depot_build_win.vdf.template deleted file mode 100644 index 2c18a0f15dd..00000000000 --- a/release/steam/depot_build_win.vdf.template +++ /dev/null @@ -1,31 +0,0 @@ -"DepotBuildConfig" -{ - // Set your assigned depot ID here - "DepotID" "[WINID]" - - // Set a root for all content. - // All relative paths specified below (LocalPath in FileMapping entries, and FileExclusion paths) - // will be resolved relative to this root. - // If you don't define ContentRoot, then it will be assumed to be - // the location of this script file, which probably isn't what you want - "ContentRoot" "./blender-[VERSION]-windows64/" - - // include all files recursivley - "FileMapping" - { - // This can be a full path, or a path relative to ContentRoot - "LocalPath" "*" - - // This is a path relative to the install folder of your game - "DepotPath" "." - - // If LocalPath contains wildcards, setting this means that all - // matching files within subdirectories of LocalPath will also - // be included. - "recursive" "1" - } - - // but exclude all symbol files - // This can be a full path, or a path relative to ContentRoot - "FileExclusion" "*.pdb" -} -- cgit v1.2.3 From 975ca9193913c034f864121597e044d6eb043a5f Mon Sep 17 00:00:00 2001 From: Nathan Letwory Date: Wed, 16 Dec 2020 11:12:51 +0100 Subject: Steam Release: Script creation of Steam build files Script tool for automation of Steam build files for tasks like {T77348} This script automates creation of the Steam files: download of the archives, extraction of the archives, preparation of the build scripts (VDF files), actual building of the Steam game files. Requirements ============ * MacOS machine - Tested on Catalina 10.15.6. Extracting contents from the DMG archive did not work Windows nor on Linux using 7-zip. All DMG archives tested failed to be extracted. As such only MacOS is known to work. * Steam SDK downloaded from SteamWorks - The `steamcmd` is used to generate the Steam game files. The path to the `steamcmd` is what is actually needed. * SteamWorks credentials - Needed to log in using `steamcmd`. * Login to SteamWorks with the `steamcmd` from the command-line at least once - Needded to ensure the user is properly logged in. On a new machine the user will have to go through two-factor authentication. * App ID and Depot IDs - Needed to create the VDF files. * Python 3.x - 3.7 was tested. * Base URL - for downloading the archives. Reviewed By: Jeroen Bakker Differential Revision: https://developer.blender.org/D8429 --- release/steam/README.md | 70 +++++ release/steam/blender_app_build.vdf.template | 17 ++ release/steam/create_steam_builds.py | 397 +++++++++++++++++++++++++++ release/steam/depot_build_linux.vdf.template | 31 +++ release/steam/depot_build_macos.vdf.template | 30 ++ release/steam/depot_build_win.vdf.template | 31 +++ 6 files changed, 576 insertions(+) create mode 100644 release/steam/README.md create mode 100644 release/steam/blender_app_build.vdf.template create mode 100644 release/steam/create_steam_builds.py create mode 100644 release/steam/depot_build_linux.vdf.template create mode 100644 release/steam/depot_build_macos.vdf.template create mode 100644 release/steam/depot_build_win.vdf.template diff --git a/release/steam/README.md b/release/steam/README.md new file mode 100644 index 00000000000..05eda799c3f --- /dev/null +++ b/release/steam/README.md @@ -0,0 +1,70 @@ +Creating Steam builds for Blender +================================= + +This script automates creation of the Steam files: download of the archives, +extraction of the archives, preparation of the build scripts (VDF files), actual +building of the Steam game files. + +Requirements +============ + +* MacOS machine - Tested on Catalina 10.15.6. Extracting contents from the DMG + archive did not work Windows nor on Linux using 7-zip. All DMG archives tested + failed to be extracted. As such only MacOS is known to work. +* Steam SDK downloaded from SteamWorks - The `steamcmd` is used to generate the + Steam game files. The path to the `steamcmd` is what is actually needed. +* SteamWorks credentials - Needed to log in using `steamcmd`. +* Login to SteamWorks with the `steamcmd` from the command-line at least once - + Needded to ensure the user is properly logged in. On a new machine the user + will have to go through two-factor authentication. +* App ID and Depot IDs - Needed to create the VDF files. +* Python 3.x - 3.7 was tested. +* Base URL - for downloading the archives. + +Usage +===== + +```bash +$ export STEAMUSER=SteamUserName +$ export STEAMPW=SteamUserPW +$ export BASEURL=https://download.blender.org/release/Blender2.83/ +$ export VERSION=2.83.3 +$ export APPID=appidnr +$ export WINID=winidnr +$ export LINID=linuxidnr +$ export MACOSID=macosidnr + +# log in to SteamWorks from command-line at least once + +$ ../sdk/tools/ContentBuilder/builder_osx/steamcmd +login $STEAMUSER $STEAMPW + +# once that has been done we can now actually start our tool + +$ python3.7 create_steam_builds.py --baseurl $BASEURL --version $VERSION --appid $APPID --winid $WINID --linuxid $LINID --macosid $MACOSID --steamuser $STEAMUSER --steampw $STEAMPW --steamcmd ../sdk/tools/ContentBuilder/builder_osx/steamcmd +``` + +All arguments in the above example are required. + +At the start the tool will login using `steamcmd`. This is necessary to let the +Steam SDK update itself if necessary. + +There are a few optional arguments: + +* `--dryrun`: If set building the game files will not actually happen. A set of + log files and a preview manifest per depot will be created in the output folder. + This can be used to double-check everything works as expected. +* `--skipdl`: If set will skip downloading of the archives. The tool expects the + archives to already exist in the correct content location. +* `--skipextract`: If set will skip extraction of all archives. The tool expects + the archives to already have been correctly extracted in the content location. + +Run the tool with `-h` for detailed information on each argument. + +The content and output folders are generated through appending the version +without dots to the words `content` and `output` respectively, e.g. `content2833` +and `output2833`. These folders are created next to the tool. + +From all `.template` files the Steam build scripts will be generated also in the +same directory as the tool. The files will have the extension `.vdf`. + +In case of errors the tool will have a non-zero return code. \ No newline at end of file diff --git a/release/steam/blender_app_build.vdf.template b/release/steam/blender_app_build.vdf.template new file mode 100644 index 00000000000..9e2d0625d72 --- /dev/null +++ b/release/steam/blender_app_build.vdf.template @@ -0,0 +1,17 @@ +"appbuild" +{ + "appid" "[APPID]" + "desc" "Blender [VERSION]" // description for this build + "buildoutput" "./[OUTPUT]" // build output folder for .log, .csm & .csd files, relative to location of this file + "contentroot" "./[CONTENT]" // root content folder, relative to location of this file + "setlive" "" // branch to set live after successful build, non if empty + "preview" "[DRYRUN]" // 1 to enable preview builds, 0 to commit build to steampipe + "local" "" // set to flie path of local content server + + "depots" + { + "[WINID]" "depot_build_win.vdf" + "[LINUXID]" "depot_build_linux.vdf" + "[MACOSID]" "depot_build_macos.vdf" + } +} diff --git a/release/steam/create_steam_builds.py b/release/steam/create_steam_builds.py new file mode 100644 index 00000000000..2ecd0c347f7 --- /dev/null +++ b/release/steam/create_steam_builds.py @@ -0,0 +1,397 @@ +#!/usr/bin/env python3 + +import argparse +import pathlib +import requests +import shutil +import subprocess +from typing import Callable, Iterator, List, Tuple + +# supported archive and platform endings, used to create actual archive names +archive_endings = ["windows64.zip", "linux64.tar.xz", "macOS.dmg"] + + +def add_optional_argument(option: str, help: str) -> None: + global parser + """Add an optional argument + + Args: + option (str): Option to add + help (str): Help description for the argument + """ + parser.add_argument(option, help=help, action='store_const', const=1) + + +def blender_archives(version: str) -> Iterator[str]: + """Generator for Blender archives for version. + + Yields for items in archive_endings an archive name in the form of + blender-{version}-{ending}. + + Args: + version (str): Version string of the form 2.83.2 + + + Yields: + Iterator[str]: Name in the form of blender-{version}-{ending} + """ + global archive_endings + + for ending in archive_endings: + yield f"blender-{version}-{ending}" + + +def get_archive_type(archive_type: str, version: str) -> str: + """Return the archive of given type and version. + + Args: + archive_type (str): extension for archive type to check for + version (str): Version string in the form 2.83.2 + + Raises: + Exception: Execption when archive type isn't found + + Returns: + str: archive name for given type + """ + + for archive in blender_archives(version): + if archive.endswith(archive_type): + return archive + raise Exception("Unknown archive type") + + +def execute_command(cmd: List[str], name: str, errcode: int, cwd=".", capture_output=True) -> str: + """Execute the given command. + + Returns the process stdout upon success if any. + + On error print message the command with name that has failed. Print stdout + and stderr of the process if any, and then exit with given error code. + + Args: + cmd (List[str]): Command in list format, each argument as their own item + name (str): Name of command to use when printing to command-line + errcode (int): Error code to use in case of exit() + cwd (str, optional): Folder to use as current work directory for command + execution. Defaults to ".". + capture_output (bool, optional): Whether to capture command output or not. + Defaults to True. + + Returns: + str: stdout if any, or empty string + """ + cmd_process = subprocess.run( + cmd, capture_output=capture_output, encoding="UTF-8", cwd=cwd) + if cmd_process.returncode == 0: + if cmd_process.stdout: + return cmd_process.stdout + else: + return "" + else: + print(f"ERROR: {name} failed.") + if cmd_process.stdout: + print(cmd_process.stdout) + if cmd_process.stderr: + print(cmd_process.stderr) + exit(errcode) + return "" + + +def download_archives(base_url: str, archives: Callable[[str], Iterator[str]], version: str, dst_dir: pathlib.Path): + """Download archives from the given base_url. + + Archives is a generator for Blender archive names based on version. + + Archive names are appended to the base_url to load from, and appended to + dst_dir to save to. + + Args: + base_url (str): Base URL to load archives from + archives (Callable[[str], Iterator[str]]): Generator for Blender archive + names based on version + version (str): Version string in the form of 2.83.2 + dst_dir (pathlib.Path): Download destination + """ + + if base_url[-1] != '/': + base_url = base_url + '/' + + for archive in archives(version): + download_url = f"{base_url}{archive}" + target_file = dst_dir.joinpath(archive) + download_file(download_url, target_file) + + +def download_file(from_url: str, to_file: pathlib.Path) -> None: + """Download from_url as to_file. + + Actual downloading will be skipped if --skipdl is given on the command-line. + + Args: + from_url (str): Full URL to resource to download + to_file (pathlib.Path): Full path to save downloaded resource as + """ + global args + + if not args.skipdl or not to_file.exists(): + print(f"Downloading {from_url}") + with open(to_file, "wb") as download_zip: + response = requests.get(from_url) + if response.status_code != requests.codes.ok: + print(f"ERROR: failed to download {from_url} (status code: {response.status_code})") + exit(1313) + download_zip.write(response.content) + else: + print(f"Downloading {from_url} skipped") + print(" ... OK") + + +def copy_contents_from_dmg_to_path(dmg_file: pathlib.Path, dst: pathlib.Path) -> None: + """Copy the contents of the given DMG file to the destination folder. + + Args: + dmg_file (pathlib.Path): Full path to DMG archive to extract from + dst (pathlib.Path): Full path to destination to extract to + """ + hdiutil_attach = ["hdiutil", + "attach", + "-readonly", + f"{dmg_file}" + ] + attached = execute_command(hdiutil_attach, "hdiutil attach", 1) + + # Last line of output is what we want, it is of the form + # /dev/somedisk Apple_HFS /Volumes/Blender + # We want to retain the mount point, and the folder the mount is + # created on. The mounted disk we need for detaching, the folder we + # need to be able to copy the contents to where we can use them + attachment_items = attached.splitlines()[-1].split() + mounted_disk = attachment_items[0] + source_location = pathlib.Path(attachment_items[2], "Blender.app") + + print(f"{source_location} -> {dst}") + + shutil.copytree(source_location, dst) + + hdiutil_detach = ["hdiutil", + "detach", + f"{mounted_disk}" + ] + execute_command(hdiutil_detach, "hdiutil detach", 2) + + +def create_build_script(template_name: str, vars: List[Tuple[str, str]]) -> pathlib.Path: + """ + Create the Steam build script + + Use the given template and template variable tuple list. + + Returns pathlib.Path to the created script. + + Args: + template_name (str): [description] + vars (List[Tuple[str, str]]): [description] + + Returns: + pathlib.Path: Full path to the generated script + """ + build_script = pathlib.Path(".", template_name).read_text() + for var in vars: + build_script = build_script.replace(var[0], var[1]) + build_script_file = template_name.replace(".template", "") + build_script_path = pathlib.Path(".", build_script_file) + build_script_path.write_text(build_script) + return build_script_path + + +def clean_up() -> None: + """Remove intermediate files depending on given command-line arguments + """ + global content_location, args + + if not args.leavearch and not args.leaveextracted: + shutil.rmtree(content_location) + + if args.leavearch and not args.leaveextracted: + shutil.rmtree(content_location.joinpath(zip_extract_folder)) + shutil.rmtree(content_location.joinpath(tarxz_extract_folder)) + shutil.rmtree(content_location.joinpath(dmg_extract_folder)) + + if args.leaveextracted and not args.leavearch: + import os + os.remove(content_location.joinpath(zipped_blender)) + os.remove(content_location.joinpath(tarxz_blender)) + os.remove(content_location.joinpath(dmg_blender)) + + +def extract_archive(archive: str, extract_folder_name: str, + cmd: List[str], errcode: int) -> None: + """Extract all files from archive to given folder name. + + Will not extract if + target folder already exists, or if --skipextract was given on the + command-line. + + Args: + archive (str): Archive name to extract + extract_folder_name (str): Folder name to extract to + cmd (List[str]): Command with arguments to use + errcode (int): Error code to use for exit() + """ + global args, content_location + + extract_location = content_location.joinpath(extract_folder_name) + + pre_extract = set(content_location.glob("*")) + + if not args.skipextract or not extract_location.exists(): + print(f"Extracting files from {archive}...") + cmd.append(content_location.joinpath(archive)) + execute_command(cmd, cmd[0], errcode, cwd=content_location) + # in case we use a non-release archive the naming will be incorrect. + # simply rename to expected target name + post_extract = set(content_location.glob("*")) + diff_extract = post_extract - pre_extract + if not extract_location in diff_extract: + folder_to_rename = list(diff_extract)[0] + folder_to_rename.rename(extract_location) + print(" OK") + else: + print(f"Skipping extraction {archive}!") + +# ============================================================================== + + +parser = argparse.ArgumentParser() + +parser.add_argument("--baseurl", required=True, + help="The base URL for files to download, " + "i.e. https://download.blender.org/release/Blender2.83/") + +parser.add_argument("--version", required=True, + help="The Blender version to release, in the form 2.83.3") + +parser.add_argument("--appid", required=True, + help="The Blender App ID on Steam") +parser.add_argument("--winid", required=True, + help="The Windows depot ID") +parser.add_argument("--linuxid", required=True, + help="The Linux depot ID") +parser.add_argument("--macosid", required=True, + help="The MacOS depot ID") + +parser.add_argument("--steamcmd", required=True, + help="Path to the steamcmd") +parser.add_argument("--steamuser", required=True, + help="The login for the Steam builder user") +parser.add_argument("--steampw", required=True, + help="Login password for the Steam builder user") + +add_optional_argument("--dryrun", + "If set the Steam files will not be uploaded") +add_optional_argument("--leavearch", + help="If set don't clean up the downloaded archives") +add_optional_argument("--leaveextracted", + help="If set don't clean up the extraction folders") +add_optional_argument("--skipdl", + help="If set downloading the archives is skipped if it already exists locally.") +add_optional_argument("--skipextract", + help="If set skips extracting of archives. The tool assumes the archives" + "have already been extracted to their correct locations") + +args = parser.parse_args() + +VERSIONNODOTS = args.version.replace('.', '') +OUTPUT = f"output{VERSIONNODOTS}" +CONTENT = f"content{VERSIONNODOTS}" + +# ===== set up main locations + +content_location = pathlib.Path(".", CONTENT).absolute() +output_location = pathlib.Path(".", OUTPUT).absolute() + +content_location.mkdir(parents=True, exist_ok=True) +output_location.mkdir(parents=True, exist_ok=True) + +# ===== login + +# Logging into Steam once to ensure the SDK updates itself properly. If we don't +# do that the combined +login and +run_app_build_http at the end of the tool +# will fail. +steam_login = [args.steamcmd, + "+login", + args.steamuser, + args.steampw, + "+quit" + ] +print("Logging in to Steam...") +execute_command(steam_login, "Login to Steam", 10) +print(" OK") + +# ===== prepare Steam build scripts + +template_vars = [ + ("[APPID]", args.appid), + ("[OUTPUT]", OUTPUT), + ("[CONTENT]", CONTENT), + ("[VERSION]", args.version), + ("[WINID]", args.winid), + ("[LINUXID]", args.linuxid), + ("[MACOSID]", args.macosid), + ("[DRYRUN]", f"{args.dryrun}" if args.dryrun else "0") +] + +blender_app_build = create_build_script( + "blender_app_build.vdf.template", template_vars) +create_build_script("depot_build_win.vdf.template", template_vars) +create_build_script("depot_build_linux.vdf.template", template_vars) +create_build_script("depot_build_macos.vdf.template", template_vars) + +# ===== download archives + +download_archives(args.baseurl, blender_archives, + args.version, content_location) + +# ===== set up file and folder names + +zipped_blender = get_archive_type("zip", args.version) +zip_extract_folder = zipped_blender.replace(".zip", "") +tarxz_blender = get_archive_type("tar.xz", args.version) +tarxz_extract_folder = tarxz_blender.replace(".tar.xz", "") +dmg_blender = get_archive_type("dmg", args.version) +dmg_extract_folder = dmg_blender.replace(".dmg", "") + +# ===== extract + +unzip_cmd = ["unzip", "-q"] +extract_archive(zipped_blender, zip_extract_folder, unzip_cmd, 3) + +untarxz_cmd = ["tar", "-xf"] +extract_archive(tarxz_blender, tarxz_extract_folder, untarxz_cmd, 4) + +if not args.skipextract or not content_location.joinpath(dmg_extract_folder).exists(): + print("Extracting files from Blender MacOS archive...") + blender_dmg = content_location.joinpath(dmg_blender) + target_location = content_location.joinpath( + dmg_extract_folder, "Blender.app") + copy_contents_from_dmg_to_path(blender_dmg, target_location) + print(" OK") +else: + print("Skipping extraction of .dmg!") + +# ===== building + +print("Build Steam game files...") +steam_build = [args.steamcmd, + "+login", + args.steamuser, + args.steampw, + "+run_app_build_http", + blender_app_build.absolute(), + "+quit" + ] +execute_command(steam_build, "Build with steamcmd", 13) +print(" OK") + +clean_up() diff --git a/release/steam/depot_build_linux.vdf.template b/release/steam/depot_build_linux.vdf.template new file mode 100644 index 00000000000..0f69008548e --- /dev/null +++ b/release/steam/depot_build_linux.vdf.template @@ -0,0 +1,31 @@ +"DepotBuildConfig" +{ + // Set your assigned depot ID here + "DepotID" "[LINUXID]" + + // Set a root for all content. + // All relative paths specified below (LocalPath in FileMapping entries, and FileExclusion paths) + // will be resolved relative to this root. + // If you don't define ContentRoot, then it will be assumed to be + // the location of this script file, which probably isn't what you want + "ContentRoot" "./blender-[VERSION]-linux64/" + + // include all files recursivley + "FileMapping" + { + // This can be a full path, or a path relative to ContentRoot + "LocalPath" "*" + + // This is a path relative to the install folder of your game + "DepotPath" "." + + // If LocalPath contains wildcards, setting this means that all + // matching files within subdirectories of LocalPath will also + // be included. + "recursive" "1" + } + + // but exclude all symbol files + // This can be a full path, or a path relative to ContentRoot + "FileExclusion" "*.pdb" +} diff --git a/release/steam/depot_build_macos.vdf.template b/release/steam/depot_build_macos.vdf.template new file mode 100644 index 00000000000..33dde860462 --- /dev/null +++ b/release/steam/depot_build_macos.vdf.template @@ -0,0 +1,30 @@ +"DepotBuildConfig" +{ + // Set your assigned depot ID here + "DepotID" "[MACOSID]" + + // Set a root for all content. + // All relative paths specified below (LocalPath in FileMapping entries, and FileExclusion paths) + // will be resolved relative to this root. + // If you don't define ContentRoot, then it will be assumed to be + // the location of this script file, which probably isn't what you want + "ContentRoot" "./blender-[VERSION]-macOS/" + // include all files recursivley + "FileMapping" + { + // This can be a full path, or a path relative to ContentRoot + "LocalPath" "*" + + // This is a path relative to the install folder of your game + "DepotPath" "." + + // If LocalPath contains wildcards, setting this means that all + // matching files within subdirectories of LocalPath will also + // be included. + "recursive" "1" + } + + // but exclude all symbol files + // This can be a full path, or a path relative to ContentRoot + "FileExclusion" "*.pdb" +} diff --git a/release/steam/depot_build_win.vdf.template b/release/steam/depot_build_win.vdf.template new file mode 100644 index 00000000000..2c18a0f15dd --- /dev/null +++ b/release/steam/depot_build_win.vdf.template @@ -0,0 +1,31 @@ +"DepotBuildConfig" +{ + // Set your assigned depot ID here + "DepotID" "[WINID]" + + // Set a root for all content. + // All relative paths specified below (LocalPath in FileMapping entries, and FileExclusion paths) + // will be resolved relative to this root. + // If you don't define ContentRoot, then it will be assumed to be + // the location of this script file, which probably isn't what you want + "ContentRoot" "./blender-[VERSION]-windows64/" + + // include all files recursivley + "FileMapping" + { + // This can be a full path, or a path relative to ContentRoot + "LocalPath" "*" + + // This is a path relative to the install folder of your game + "DepotPath" "." + + // If LocalPath contains wildcards, setting this means that all + // matching files within subdirectories of LocalPath will also + // be included. + "recursive" "1" + } + + // but exclude all symbol files + // This can be a full path, or a path relative to ContentRoot + "FileExclusion" "*.pdb" +} -- cgit v1.2.3 From 055ef5df615632f81e30e39ae47b42a87af350ca Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Wed, 16 Dec 2020 01:05:46 +0100 Subject: Cleanup: Rename Asset Browser context member from "active_id" to "id" This is the same name we use elsewhere for the focused/active ID context member, so this should follow it. --- source/blender/editors/space_file/space_file.c | 2 +- source/blender/editors/util/ed_util.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c index d4f6618e82a..5bd7f6c17f6 100644 --- a/source/blender/editors/space_file/space_file.c +++ b/source/blender/editors/space_file/space_file.c @@ -806,7 +806,7 @@ static int /*eContextResult*/ file_context(const bContext *C, CTX_data_pointer_set(result, &screen->id, &RNA_FileSelectEntry, file); return CTX_RESULT_OK; } - if (CTX_data_equals(member, "active_id")) { + if (CTX_data_equals(member, "id")) { const FileDirEntry *file = filelist_file(sfile->files, params->active_file); ID *id = filelist_file_get_id(file); diff --git a/source/blender/editors/util/ed_util.c b/source/blender/editors/util/ed_util.c index 6547e42f410..4740e4d8d33 100644 --- a/source/blender/editors/util/ed_util.c +++ b/source/blender/editors/util/ed_util.c @@ -507,7 +507,7 @@ void ED_OT_flush_edits(wmOperatorType *ot) static bool lib_id_load_custom_preview_poll(bContext *C) { - const PointerRNA idptr = CTX_data_pointer_get(C, "active_id"); + const PointerRNA idptr = CTX_data_pointer_get(C, "id"); BLI_assert(!idptr.data || RNA_struct_is_ID(idptr.type)); const ID *id = idptr.data; @@ -541,7 +541,7 @@ static int lib_id_load_custom_preview_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - PointerRNA idptr = CTX_data_pointer_get(C, "active_id"); + PointerRNA idptr = CTX_data_pointer_get(C, "id"); ID *id = idptr.data; BKE_previewimg_id_custom_set(id, path); -- cgit v1.2.3 From 0ae15e68c78530843a670e2d57854e8aa12178d2 Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Wed, 16 Dec 2020 01:07:01 +0100 Subject: Asset Browser: Allow renaming asset data-blocks from the sidebar directly This is something we wanted to support doing. It's confusing if users see the name but it's always grayed out. So be convenient and avoid the confusion. --- release/scripts/startup/bl_ui/space_filebrowser.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/release/scripts/startup/bl_ui/space_filebrowser.py b/release/scripts/startup/bl_ui/space_filebrowser.py index 15e2e3d02e0..b6ca0639b4b 100644 --- a/release/scripts/startup/bl_ui/space_filebrowser.py +++ b/release/scripts/startup/bl_ui/space_filebrowser.py @@ -598,7 +598,8 @@ class ASSETBROWSER_PT_metadata(asset_utils.AssetBrowserPanel, Panel): box.template_icon(icon_value=active_file.preview_icon_id, scale=5.0) if bpy.ops.ed.lib_id_load_custom_preview.poll(): box.operator("ed.lib_id_load_custom_preview", icon='FILEBROWSER', text="Load Custom") - layout.prop(active_file, "name") + # If the active file is an ID, use its name directly so renaming is possible from right here. + layout.prop(context.id if not None else active_file, "name") class ASSETBROWSER_PT_metadata_details(asset_utils.AssetBrowserPanel, Panel): -- cgit v1.2.3 From 19fc30c15fa50765a70f662e1aa78cd4140035ce Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Wed, 16 Dec 2020 11:20:32 +0100 Subject: Assets UI: Tweak position of the "Add Asset Library" icon-button in Preferences It's weird to have a button that adds a new item at the bottom be placed at the top. So rather move it below the list of custom asset library paths. --- release/scripts/startup/bl_ui/space_userpref.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py index 1d9d4fbf393..0167f0b1e20 100644 --- a/release/scripts/startup/bl_ui/space_userpref.py +++ b/release/scripts/startup/bl_ui/space_userpref.py @@ -1362,14 +1362,15 @@ class USERPREF_PT_file_paths_asset_libraries(FilePathsPanel, Panel): row.separator() row.label(text="Path") - subrow = row.row() - subrow.operator("preferences.asset_library_add", text="", icon='ADD', emboss=False) for i, library in enumerate(paths.asset_libraries): name_col.prop(library, "name", text="") row = path_col.row() row.prop(library, "path", text="") row.operator("preferences.asset_library_remove", text="", icon='X', emboss=False).index = i + row = box.row() + row.alignment = 'LEFT' + row.operator("preferences.asset_library_add", text="", icon='ADD', emboss=False) # ----------------------------------------------------------------------------- -- cgit v1.2.3 From c7a500e3a0fa0721eb1771a422b6b17255692843 Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Wed, 16 Dec 2020 11:24:22 +0100 Subject: Asset Browser UI: Changes to the sidebar layout The current layout wasn't great at all, and it was planned to polish this. This does a first round of improvements, some more tweaking may follow. * Place name button at the top, with no panel and no leading label. * Add "Preview" panel, people may not want to see the preview all the time, it's already visible in the file list. * Move button to browse for a custom preview to the right of the preview, as icon-only. We have a similar layout in other places (UI-lists, matcaps). * Don't make the details panel a sub-panel. Looked weird because the parent doesn't have a header. * Add info icon to "No asset selected", looks a bit friendlier. * Minor cleanups in the UI script. Based on designs and feedback by William Reynish. --- release/scripts/startup/bl_ui/space_filebrowser.py | 28 ++++++++++++++-------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/release/scripts/startup/bl_ui/space_filebrowser.py b/release/scripts/startup/bl_ui/space_filebrowser.py index b6ca0639b4b..98368f304d9 100644 --- a/release/scripts/startup/bl_ui/space_filebrowser.py +++ b/release/scripts/startup/bl_ui/space_filebrowser.py @@ -588,24 +588,31 @@ class ASSETBROWSER_PT_metadata(asset_utils.AssetBrowserPanel, Panel): active_file = context.active_file active_asset = asset_utils.SpaceAssetInfo.get_active_asset(context) - layout.use_property_split = True - if not active_file or not active_asset: - layout.label(text="No asset selected.") + layout.label(text="No asset selected.", icon='INFO') return - box = layout.box() + # If the active file is an ID, use its name directly so renaming is possible from right here. + layout.prop(context.id if not None else active_file, "name", text="") + + +class ASSETBROWSER_PT_metadata_preview(asset_utils.AssetMetaDataPanel, Panel): + bl_label = "Preview" + + def draw(self, context): + layout = self.layout + active_file = context.active_file + + row = layout.row() + box = row.box() box.template_icon(icon_value=active_file.preview_icon_id, scale=5.0) if bpy.ops.ed.lib_id_load_custom_preview.poll(): - box.operator("ed.lib_id_load_custom_preview", icon='FILEBROWSER', text="Load Custom") - # If the active file is an ID, use its name directly so renaming is possible from right here. - layout.prop(context.id if not None else active_file, "name") + col = row.column(align=True) + col.operator("ed.lib_id_load_custom_preview", icon='FILEBROWSER', text="") -class ASSETBROWSER_PT_metadata_details(asset_utils.AssetBrowserPanel, Panel): - bl_region_type = 'TOOL_PROPS' +class ASSETBROWSER_PT_metadata_details(asset_utils.AssetMetaDataPanel, Panel): bl_label = "Details" - bl_parent_id = "ASSETBROWSER_PT_metadata" def draw(self, context): layout = self.layout @@ -663,6 +670,7 @@ classes = ( FILEBROWSER_MT_context_menu, ASSETBROWSER_PT_navigation_bar, ASSETBROWSER_PT_metadata, + ASSETBROWSER_PT_metadata_preview, ASSETBROWSER_PT_metadata_details, ASSETBROWSER_PT_metadata_tags, ASSETBROWSER_UL_metadata_tags, -- cgit v1.2.3 From 58d818f8bebf8c08b528d1637c93f15d2559cca1 Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Wed, 16 Dec 2020 11:44:22 +0100 Subject: Assets: Add operator & button to regenerate the automatic preview This makes it possible to trigger a refresh of the data-block preview, available next to the preview in the Asset Browser sidebar. The previews get easily outdated and automatically refreshing it all the time is not an option because it would be a consistently running, quite expensive process. So a button to cause a refresh should be reasonable. This button can also be used to switch back from a custom preview to a generated one. Although that may not be clear, and we should probably think of a way to explain that better. Addresses T82719. --- release/scripts/startup/bl_ui/space_filebrowser.py | 2 ++ source/blender/editors/include/ED_util.h | 1 + source/blender/editors/screen/screen_ops.c | 1 + source/blender/editors/util/ed_util.c | 37 ++++++++++++++++++++-- 4 files changed, 39 insertions(+), 2 deletions(-) diff --git a/release/scripts/startup/bl_ui/space_filebrowser.py b/release/scripts/startup/bl_ui/space_filebrowser.py index 98368f304d9..58a4269ab96 100644 --- a/release/scripts/startup/bl_ui/space_filebrowser.py +++ b/release/scripts/startup/bl_ui/space_filebrowser.py @@ -609,6 +609,8 @@ class ASSETBROWSER_PT_metadata_preview(asset_utils.AssetMetaDataPanel, Panel): if bpy.ops.ed.lib_id_load_custom_preview.poll(): col = row.column(align=True) col.operator("ed.lib_id_load_custom_preview", icon='FILEBROWSER', text="") + col.separator() + col.operator("ed.lib_id_generate_preview", icon='FILE_REFRESH', text="") class ASSETBROWSER_PT_metadata_details(asset_utils.AssetMetaDataPanel, Panel): diff --git a/source/blender/editors/include/ED_util.h b/source/blender/editors/include/ED_util.h index d74a80045f1..ca6b4bdc618 100644 --- a/source/blender/editors/include/ED_util.h +++ b/source/blender/editors/include/ED_util.h @@ -54,6 +54,7 @@ void ED_spacedata_id_remap(struct ScrArea *area, void ED_OT_flush_edits(struct wmOperatorType *ot); void ED_OT_lib_id_load_custom_preview(struct wmOperatorType *ot); +void ED_OT_lib_id_generate_preview(struct wmOperatorType *ot); /* ************** XXX OLD CRUFT WARNING ************* */ diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index a0c5762c73c..51687d5de1d 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -5511,6 +5511,7 @@ void ED_operatortypes_screen(void) WM_operatortype_append(ED_OT_flush_edits); WM_operatortype_append(ED_OT_lib_id_load_custom_preview); + WM_operatortype_append(ED_OT_lib_id_generate_preview); } /** \} */ diff --git a/source/blender/editors/util/ed_util.c b/source/blender/editors/util/ed_util.c index 4740e4d8d33..d78758dcc1c 100644 --- a/source/blender/editors/util/ed_util.c +++ b/source/blender/editors/util/ed_util.c @@ -67,6 +67,7 @@ #include "ED_object.h" #include "ED_outliner.h" #include "ED_paint.h" +#include "ED_render.h" #include "ED_space_api.h" #include "ED_util.h" @@ -505,7 +506,7 @@ void ED_OT_flush_edits(wmOperatorType *ot) ot->flag = OPTYPE_INTERNAL; } -static bool lib_id_load_custom_preview_poll(bContext *C) +static bool lib_id_preview_editing_poll(bContext *C) { const PointerRNA idptr = CTX_data_pointer_get(C, "id"); BLI_assert(!idptr.data || RNA_struct_is_ID(idptr.type)); @@ -558,7 +559,7 @@ void ED_OT_lib_id_load_custom_preview(wmOperatorType *ot) ot->idname = "ED_OT_lib_id_load_custom_preview"; /* api callbacks */ - ot->poll = lib_id_load_custom_preview_poll; + ot->poll = lib_id_preview_editing_poll; ot->exec = lib_id_load_custom_preview_exec; ot->invoke = WM_operator_filesel; @@ -573,3 +574,35 @@ void ED_OT_lib_id_load_custom_preview(wmOperatorType *ot) FILE_DEFAULTDISPLAY, FILE_SORT_DEFAULT); } + +static int lib_id_generate_preview_exec(bContext *C, wmOperator *UNUSED(op)) +{ + PointerRNA idptr = CTX_data_pointer_get(C, "id"); + ID *id = idptr.data; + + ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); + + PreviewImage *preview = BKE_previewimg_id_get(id); + if (preview) { + BKE_previewimg_clear(preview); + } + UI_icon_render_id(C, NULL, id, true, true); + + WM_event_add_notifier(C, NC_ASSET, NULL); + + return OPERATOR_FINISHED; +} + +void ED_OT_lib_id_generate_preview(wmOperatorType *ot) +{ + ot->name = "Generate Preview"; + ot->description = "Create an automatic preview for the selected data-block"; + ot->idname = "ED_OT_lib_id_generate_preview"; + + /* api callbacks */ + ot->poll = lib_id_preview_editing_poll; + ot->exec = lib_id_generate_preview_exec; + + /* flags */ + ot->flag = OPTYPE_INTERNAL; +} -- cgit v1.2.3 From 3fc9fc1cb46a49bbfa2da4443fb4edefcdc3b89d Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Wed, 16 Dec 2020 11:58:30 +0100 Subject: UI: Indicate asset data-blocks with an icon in Outliners & search menus It's useful to easily see which data-blocks are assets and which not. So just like we usually show the library linking/override icons, we show the asset icon there (these are mutually exclusive data-block states). Uses the `'MAT_SPHERE_SKY` icon, which wasn't used before (except by an add-on!) and is sorta fitting, but not quite. We should either change this one or add an own asset icon. Meanwhile this isn't too bad :) Also adds an internal macro to check if a data-block is an asset, consistent to how we do it for libraries and library overrides. --- source/blender/editors/interface/interface_icons.c | 3 +++ source/blender/makesdna/DNA_ID.h | 2 ++ 2 files changed, 5 insertions(+) diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c index 1c09dc6f4df..08e9ea31b53 100644 --- a/source/blender/editors/interface/interface_icons.c +++ b/source/blender/editors/interface/interface_icons.c @@ -2199,6 +2199,9 @@ int UI_icon_from_library(const ID *id) if (ID_IS_OVERRIDE_LIBRARY(id)) { return ICON_LIBRARY_DATA_OVERRIDE; } + if (ID_IS_ASSET(id)) { + return ICON_MAT_SPHERE_SKY; + } return ICON_NONE; } diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h index af8e83a2c44..265baa16cc5 100644 --- a/source/blender/makesdna/DNA_ID.h +++ b/source/blender/makesdna/DNA_ID.h @@ -509,6 +509,8 @@ typedef enum ID_Type { #define ID_IS_OVERRIDE_LIBRARY_TEMPLATE(_id) \ (((ID *)(_id))->override_library != NULL && ((ID *)(_id))->override_library->reference == NULL) +#define ID_IS_ASSET(_id) (((const ID *)(_id))->asset_data != NULL) + /* Check whether datablock type is covered by copy-on-write. */ #define ID_TYPE_IS_COW(_id_type) (!ELEM(_id_type, ID_BR, ID_PAL, ID_IM)) -- cgit v1.2.3 From 4f128269b2dcf453647e7293f68f35173d45486a Mon Sep 17 00:00:00 2001 From: Eric Cosky Date: Wed, 16 Dec 2020 12:12:06 +0100 Subject: Fix possible crash with custom (add-on defined) icons This change is a simple null check on the ID provided to icon_set_image() which appears to be a legitimate value for the ID when used by some addins (discovered with PowerSave shortly after syncing to main). Differential Revision: https://developer.blender.org/D9866 Reviewed by: Julian Eisel --- source/blender/editors/interface/interface_icons.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c index 08e9ea31b53..899f4a6ddb1 100644 --- a/source/blender/editors/interface/interface_icons.c +++ b/source/blender/editors/interface/interface_icons.c @@ -1416,7 +1416,7 @@ static void icon_set_image(const bContext *C, const bool delay = prv_img->rect[size] != NULL; icon_create_rect(prv_img, size); - if (use_job && BKE_previewimg_id_supports_jobs(id)) { + if (use_job && (!id || BKE_previewimg_id_supports_jobs(id))) { /* Job (background) version */ ED_preview_icon_job( C, prv_img, id, prv_img->rect[size], prv_img->w[size], prv_img->h[size], delay); -- cgit v1.2.3 From 985d673374a48eef6af5e73b0b24d4462a911f4b Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Wed, 16 Dec 2020 12:19:17 +0100 Subject: BLI: add new InplacePriorityQueue data structure This data structure adds priority queue functionality to an existing array. The underlying array is not changed. Instead, the priority queue maintains indices into the original array. Changing priorities of elements dynamically is supported, but the priority queue has to be informed of such changes. This data structure is needed for D9787. --- .../blender/blenlib/BLI_inplace_priority_queue.hh | 304 +++++++++++++++++++++ source/blender/blenlib/CMakeLists.txt | 2 + .../tests/BLI_inplace_priority_queue_test.cc | 113 ++++++++ 3 files changed, 419 insertions(+) create mode 100644 source/blender/blenlib/BLI_inplace_priority_queue.hh create mode 100644 source/blender/blenlib/tests/BLI_inplace_priority_queue_test.cc diff --git a/source/blender/blenlib/BLI_inplace_priority_queue.hh b/source/blender/blenlib/BLI_inplace_priority_queue.hh new file mode 100644 index 00000000000..e76cb8504a3 --- /dev/null +++ b/source/blender/blenlib/BLI_inplace_priority_queue.hh @@ -0,0 +1,304 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#pragma once + +#include "BLI_array.hh" +#include "BLI_dot_export.hh" + +namespace blender { + +/** + * An InplacePriorityQueue adds priority queue functionality to an existing array. The underlying + * array is not changed. Instead, the priority queue maintains indices into the original array. + * + * The priority queue provides efficient access to the element in order of their priorities. + * + * When a priority changes, the priority queue has to be informed using one of the following + * methods: #priority_decreased, #priority_increased or #priority_changed. + */ +template< + /* Type of the elements in the underlying array. */ + typename T, + /* Binary function that takes two `const T &` inputs and returns true, when the first input has + greater priority than the second. */ + typename FirstHasHigherPriority = std::greater> +class InplacePriorityQueue { + private: + /* Underlying array the priority queue is built upon. This is a span instead of a mutable span, + * because this data structure never changes the values itself. */ + Span data_; + /* Maps indices from the heap (binary tree in array format) to indices of the underlying/original + * array. */ + Array heap_to_orig_; + /* This is the inversion of the above mapping. */ + Array orig_to_heap_; + /* Number of elements that are currently in the priority queue. */ + int64_t heap_size_ = 0; + /* Function that can be changed to customize how the priority of two elements is compared. */ + FirstHasHigherPriority first_has_higher_priority_fn_; + + public: + /** + * Construct the priority queue on top of the data in the given span. + */ + InplacePriorityQueue(Span data) + : data_(data), heap_to_orig_(data_.size()), orig_to_heap_(data_.size()) + { + for (const int64_t i : IndexRange(data_.size())) { + heap_to_orig_[i] = i; + orig_to_heap_[i] = i; + } + + this->rebuild(); + } + + /** + * Rebuilds the priority queue from the array that has been passed to the constructor. + */ + void rebuild() + { + const int final_heap_size = data_.size(); + if (final_heap_size > 1) { + for (int64_t i = this->get_parent(final_heap_size - 1); i >= 0; i--) { + this->heapify(i, final_heap_size); + } + } + heap_size_ = final_heap_size; + } + + /** + * Returns the number of elements in the priority queue. + * This is less or equal than the size of the underlying array. + */ + int64_t size() const + { + return heap_size_; + } + + /** + * Returns true, when the priority queue contains no elements. If this returns true, #peek and + * #pop must not be used. + */ + bool is_empty() const + { + return heap_size_ == 0; + } + + /** + * Get the element with the highest priority in the priority queue. + * The returned reference is const, because the priority queue has read-only access to the + * underlying data. If you need a mutable reference, use #peek_index instead. + */ + const T &peek() const + { + return data_[this->peek_index()]; + } + + /** + * Get the element with the highest priority in the priority queue and remove it. + * The returned reference is const, because the priority queue has read-only access to the + * underlying data. If you need a mutable reference, use #pop_index instead. + */ + const T &pop() + { + return data_[this->pop_index()]; + } + + /** + * Get the index of the element with the highest priority in the priority queue. + */ + int64_t peek_index() const + { + BLI_assert(!this->is_empty()); + return heap_to_orig_[0]; + } + + /** + * Get the index of the element with the highest priority in the priority queue and remove it. + */ + int64_t pop_index() + { + BLI_assert(!this->is_empty()); + const int64_t top_index_orig = heap_to_orig_[0]; + heap_size_--; + if (heap_size_ > 1) { + this->swap_indices(0, heap_size_); + this->heapify(0, heap_size_); + } + return top_index_orig; + } + + /** + * Inform the priority queue that the priority of the element at the given index has been + * decreased. + */ + void priority_decreased(const int64_t index) + { + const int64_t heap_index = orig_to_heap_[index]; + if (heap_index >= heap_size_) { + /* This element is not in the queue currently. */ + return; + } + this->heapify(heap_index, heap_size_); + } + + /** + * Inform the priority queue that the priority of the element at the given index has been + * increased. + */ + void priority_increased(const int64_t index) + { + int64_t current = orig_to_heap_[index]; + if (current >= heap_size_) { + /* This element is not in the queue currently. */ + return; + } + while (true) { + if (current == 0) { + break; + } + const int64_t parent = this->get_parent(current); + if (this->first_has_higher_priority(parent, current)) { + break; + } + this->swap_indices(current, parent); + current = parent; + } + } + + /** + * Inform the priority queue that the priority of the element at the given index has been + * changed. + */ + void priority_changed(const int64_t index) + { + this->priority_increased(index); + this->priority_decreased(index); + } + + /** + * Returns the indices of all elements that are in the priority queue. + * There are no guarantees about the order of indices. + */ + Span active_indices() const + { + return heap_to_orig_.as_span().take_front(heap_size_); + } + + /** + * Returns the indices of all elements that are not in the priority queue. + * The indices are in reverse order of their removal from the queue. + * I.e. the index that has been removed last, comes first. + */ + Span inactive_indices() const + { + return heap_to_orig_.as_span().drop_front(heap_size_); + } + + /** + * Returns the concatenation of the active and inactive indices. + */ + Span all_indices() const + { + return heap_to_orig_; + } + + /** + * Return the heap used by the priority queue as dot graph string. + * This exists for debugging purposes. + */ + std::string to_dot() const + { + return this->partial_to_dot(heap_size_); + } + + private: + bool first_has_higher_priority(const int64_t a, const int64_t b) + { + const T &value_a = data_[heap_to_orig_[a]]; + const T &value_b = data_[heap_to_orig_[b]]; + return first_has_higher_priority_fn_(value_a, value_b); + } + + void swap_indices(const int64_t a, const int64_t b) + { + std::swap(heap_to_orig_[a], heap_to_orig_[b]); + orig_to_heap_[heap_to_orig_[a]] = a; + orig_to_heap_[heap_to_orig_[b]] = b; + } + + void heapify(const int64_t parent, const int64_t heap_size) + { + int64_t max_index = parent; + const int left = this->get_left(parent); + const int right = this->get_right(parent); + if (left < heap_size && this->first_has_higher_priority(left, max_index)) { + max_index = left; + } + if (right < heap_size && this->first_has_higher_priority(right, max_index)) { + max_index = right; + } + if (max_index != parent) { + this->swap_indices(parent, max_index); + this->heapify(max_index, heap_size); + } + if (left < heap_size) { + BLI_assert(!this->first_has_higher_priority(left, parent)); + } + if (right < heap_size) { + BLI_assert(!this->first_has_higher_priority(right, parent)); + } + } + + int64_t get_parent(const int64_t child) const + { + BLI_assert(child > 0); + return (child - 1) / 2; + } + + int64_t get_left(const int64_t parent) const + { + return parent * 2 + 1; + } + + int64_t get_right(const int64_t parent) const + { + return parent * 2 + 2; + } + + std::string partial_to_dot(const int size) const + { + dot::DirectedGraph digraph; + Array dot_nodes(size); + for (const int i : IndexRange(size)) { + std::stringstream ss; + ss << data_[heap_to_orig_[i]]; + const std::string name = ss.str(); + dot::Node &node = digraph.new_node(name); + node.set_shape(dot::Attr_shape::Rectangle); + node.attributes.set("ordering", "out"); + dot_nodes[i] = &node; + if (i > 0) { + const int64_t parent = this->get_parent(i); + digraph.new_edge(*dot_nodes[parent], node); + } + } + return digraph.to_dot_string(); + } +}; + +} // namespace blender diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt index 46a3ad87dfe..aa4c4efe7d4 100644 --- a/source/blender/blenlib/CMakeLists.txt +++ b/source/blender/blenlib/CMakeLists.txt @@ -203,6 +203,7 @@ set(SRC BLI_heap_simple.h BLI_index_mask.hh BLI_index_range.hh + BLI_inplace_priority_queue.hh BLI_iterator.h BLI_jitter_2d.h BLI_kdopbvh.h @@ -390,6 +391,7 @@ if(WITH_GTESTS) tests/BLI_heap_test.cc tests/BLI_index_mask_test.cc tests/BLI_index_range_test.cc + tests/BLI_inplace_priority_queue_test.cc tests/BLI_kdopbvh_test.cc tests/BLI_linear_allocator_test.cc tests/BLI_linklist_lockfree_test.cc diff --git a/source/blender/blenlib/tests/BLI_inplace_priority_queue_test.cc b/source/blender/blenlib/tests/BLI_inplace_priority_queue_test.cc new file mode 100644 index 00000000000..3adf12f36a7 --- /dev/null +++ b/source/blender/blenlib/tests/BLI_inplace_priority_queue_test.cc @@ -0,0 +1,113 @@ +/* Apache License, Version 2.0 */ + +#include "testing/testing.h" + +#include "BLI_inplace_priority_queue.hh" +#include "BLI_rand.hh" + +namespace blender::tests { + +TEST(inplace_priority_queue, BuildSmall) +{ + Array values = {1, 5, 2, 8, 5, 6, 5, 4, 3, 6, 7, 3}; + InplacePriorityQueue priority_queue{values}; + + EXPECT_EQ(priority_queue.peek(), 8); + EXPECT_EQ(priority_queue.pop(), 8); + EXPECT_EQ(priority_queue.peek(), 7); + EXPECT_EQ(priority_queue.pop(), 7); + EXPECT_EQ(priority_queue.pop(), 6); + EXPECT_EQ(priority_queue.pop(), 6); + EXPECT_EQ(priority_queue.pop(), 5); +} + +TEST(inplace_priority_queue, DecreasePriority) +{ + Array values = {5, 2, 7, 4}; + InplacePriorityQueue priority_queue(values); + + EXPECT_EQ(priority_queue.peek(), 7); + values[2] = 0; + EXPECT_EQ(priority_queue.peek(), 0); + priority_queue.priority_decreased(2); + EXPECT_EQ(priority_queue.peek(), 5); +} + +TEST(inplace_priority_queue, IncreasePriority) +{ + Array values = {5, 2, 7, 4}; + InplacePriorityQueue priority_queue(values); + + EXPECT_EQ(priority_queue.peek(), 7); + values[1] = 10; + EXPECT_EQ(priority_queue.peek(), 7); + priority_queue.priority_increased(1); + EXPECT_EQ(priority_queue.peek(), 10); +} + +TEST(inplace_priority_queue, PopAll) +{ + RandomNumberGenerator rng; + Vector values; + const int amount = 1000; + for (int i = 0; i < amount; i++) { + values.append(rng.get_int32() % amount); + } + + InplacePriorityQueue priority_queue(values); + + int last_value = amount; + while (!priority_queue.is_empty()) { + const int value = priority_queue.pop(); + EXPECT_LE(value, last_value); + last_value = value; + } +} + +TEST(inplace_priority_queue, ManyPriorityChanges) +{ + RandomNumberGenerator rng; + Vector values; + const int amount = 1000; + for (int i = 0; i < amount; i++) { + values.append(rng.get_int32() % amount); + } + + InplacePriorityQueue priority_queue(values); + + for (int i = 0; i < amount; i++) { + const int index = rng.get_int32() % amount; + const int new_priority = rng.get_int32() % amount; + values[index] = new_priority; + priority_queue.priority_changed(index); + } + + int last_value = amount; + while (!priority_queue.is_empty()) { + const int value = priority_queue.pop(); + EXPECT_LE(value, last_value); + last_value = value; + } +} + +TEST(inplace_priority_queue, IndicesAccess) +{ + Array values = {4, 6, 2, 4, 8, 1, 10, 2, 5}; + InplacePriorityQueue priority_queue(values); + + EXPECT_EQ(priority_queue.active_indices().size(), 9); + EXPECT_EQ(priority_queue.inactive_indices().size(), 0); + EXPECT_EQ(priority_queue.all_indices().size(), 9); + EXPECT_EQ(priority_queue.pop(), 10); + EXPECT_EQ(priority_queue.active_indices().size(), 8); + EXPECT_EQ(priority_queue.inactive_indices().size(), 1); + EXPECT_EQ(values[priority_queue.inactive_indices()[0]], 10); + EXPECT_EQ(priority_queue.all_indices().size(), 9); + EXPECT_EQ(priority_queue.pop(), 8); + EXPECT_EQ(priority_queue.inactive_indices().size(), 2); + EXPECT_EQ(values[priority_queue.inactive_indices()[0]], 8); + EXPECT_EQ(values[priority_queue.inactive_indices()[1]], 10); + EXPECT_EQ(priority_queue.all_indices().size(), 9); +} + +} // namespace blender::tests -- cgit v1.2.3 From 4c26dd430d5ec0867cd7b834e601fbaaf7e10e67 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Wed, 16 Dec 2020 13:31:56 +0100 Subject: Geometry Nodes: rename node to Attribute Randomize Previously, the node was called Random Attribute. For consistency reasons, we move the "Attribute" part of the name to the front. --- release/scripts/startup/nodeitems_builtins.py | 2 +- source/blender/blenkernel/BKE_node.h | 2 +- source/blender/blenkernel/intern/node.c | 2 +- source/blender/blenloader/intern/versioning_290.c | 8 + source/blender/editors/space_node/drawnode.c | 2 +- source/blender/makesrna/intern/rna_nodetree.c | 2 +- source/blender/nodes/CMakeLists.txt | 2 +- source/blender/nodes/NOD_geometry.h | 2 +- source/blender/nodes/NOD_static_types.h | 2 +- .../geometry/nodes/node_geo_attribute_randomize.cc | 162 +++++++++++++++++++++ .../geometry/nodes/node_geo_random_attribute.cc | 161 -------------------- 11 files changed, 178 insertions(+), 169 deletions(-) create mode 100644 source/blender/nodes/geometry/nodes/node_geo_attribute_randomize.cc delete mode 100644 source/blender/nodes/geometry/nodes/node_geo_random_attribute.cc diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py index f1b783f31a5..484f0b12400 100644 --- a/release/scripts/startup/nodeitems_builtins.py +++ b/release/scripts/startup/nodeitems_builtins.py @@ -481,7 +481,7 @@ def not_implemented_node(idname): geometry_node_categories = [ # Geometry Nodes GeometryNodeCategory("GEO_ATTRIBUTE", "Attribute", items=[ - NodeItem("GeometryNodeRandomAttribute"), + NodeItem("GeometryNodeAttributeRandomize"), NodeItem("GeometryNodeAttributeMath"), NodeItem("GeometryNodeAttributeFill"), NodeItem("GeometryNodeAttributeMix"), diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 77a1d3989b0..f8ce364d694 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -1347,7 +1347,7 @@ int ntreeTexExecTree(struct bNodeTree *ntree, #define GEO_NODE_POINT_INSTANCE 1005 #define GEO_NODE_SUBDIVISION_SURFACE 1006 #define GEO_NODE_OBJECT_INFO 1007 -#define GEO_NODE_RANDOM_ATTRIBUTE 1008 +#define GEO_NODE_ATTRIBUTE_RANDOMIZE 1008 #define GEO_NODE_ATTRIBUTE_MATH 1009 #define GEO_NODE_JOIN_GEOMETRY 1010 #define GEO_NODE_ATTRIBUTE_FILL 1011 diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c index 87997198334..06ff7c2e65c 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -4737,7 +4737,7 @@ static void registerGeometryNodes(void) register_node_type_geo_point_distribute(); register_node_type_geo_point_instance(); register_node_type_geo_object_info(); - register_node_type_geo_random_attribute(); + register_node_type_geo_attribute_randomize(); register_node_type_geo_attribute_math(); register_node_type_geo_join_geometry(); register_node_type_geo_attribute_mix(); diff --git a/source/blender/blenloader/intern/versioning_290.c b/source/blender/blenloader/intern/versioning_290.c index 685bb762f29..49e1b057b39 100644 --- a/source/blender/blenloader/intern/versioning_290.c +++ b/source/blender/blenloader/intern/versioning_290.c @@ -1316,5 +1316,13 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain) */ { /* Keep this block, even when empty. */ + + LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) { + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { + if (STREQ(node->idname, "GeometryNodeRandomAttribute")) { + STRNCPY(node->idname, "GeometryNodeAttributeRandomize"); + } + } + } } } diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index f8c71791054..421d645d7bd 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -3220,7 +3220,7 @@ static void node_geometry_set_butfunc(bNodeType *ntype) case GEO_NODE_TRIANGULATE: ntype->draw_buttons = node_geometry_buts_triangulate; break; - case GEO_NODE_RANDOM_ATTRIBUTE: + case GEO_NODE_ATTRIBUTE_RANDOMIZE: ntype->draw_buttons = node_geometry_buts_random_attribute; break; case GEO_NODE_ATTRIBUTE_MATH: diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 153e2aebd22..34f4d287d6e 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -8388,7 +8388,7 @@ static void def_geo_attribute_create_common(StructRNA *srna, RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } -static void def_geo_random_attribute(StructRNA *srna) +static void def_geo_attribute_randomize(StructRNA *srna) { def_geo_attribute_create_common(srna, "rna_GeometryNodeAttributeRandom_type_itemf", diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt index 11852f6f723..779680a5da7 100644 --- a/source/blender/nodes/CMakeLists.txt +++ b/source/blender/nodes/CMakeLists.txt @@ -140,6 +140,7 @@ set(SRC geometry/nodes/node_geo_attribute_fill.cc geometry/nodes/node_geo_attribute_math.cc + geometry/nodes/node_geo_attribute_randomize.cc geometry/nodes/node_geo_boolean.cc geometry/nodes/node_geo_common.cc geometry/nodes/node_geo_edge_split.cc @@ -148,7 +149,6 @@ set(SRC geometry/nodes/node_geo_object_info.cc geometry/nodes/node_geo_point_distribute.cc geometry/nodes/node_geo_point_instance.cc - geometry/nodes/node_geo_random_attribute.cc geometry/nodes/node_geo_subdivision_surface.cc geometry/nodes/node_geo_transform.cc geometry/nodes/node_geo_triangulate.cc diff --git a/source/blender/nodes/NOD_geometry.h b/source/blender/nodes/NOD_geometry.h index e3ec0451832..5ac4af9fc14 100644 --- a/source/blender/nodes/NOD_geometry.h +++ b/source/blender/nodes/NOD_geometry.h @@ -35,7 +35,7 @@ void register_node_type_geo_triangulate(void); void register_node_type_geo_point_distribute(void); void register_node_type_geo_point_instance(void); void register_node_type_geo_object_info(void); -void register_node_type_geo_random_attribute(void); +void register_node_type_geo_attribute_randomize(void); void register_node_type_geo_attribute_math(void); void register_node_type_geo_join_geometry(void); void register_node_type_geo_attribute_mix(void); diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h index 491f49cf425..681286ae5ab 100644 --- a/source/blender/nodes/NOD_static_types.h +++ b/source/blender/nodes/NOD_static_types.h @@ -274,7 +274,7 @@ DefNode(GeometryNode, GEO_NODE_BOOLEAN, def_geo_boolean, "BOOLEAN", Boolean, "Bo DefNode(GeometryNode, GEO_NODE_POINT_DISTRIBUTE, 0, "POINT_DISTRIBUTE", PointDistribute, "Point Distribute", "") DefNode(GeometryNode, GEO_NODE_POINT_INSTANCE, def_geo_point_instance, "POINT_INSTANCE", PointInstance, "Point Instance", "") DefNode(GeometryNode, GEO_NODE_OBJECT_INFO, 0, "OBJECT_INFO", ObjectInfo, "Object Info", "") -DefNode(GeometryNode, GEO_NODE_RANDOM_ATTRIBUTE, def_geo_random_attribute, "RANDOM_ATTRIBUTE", RandomAttribute, "Random Attribute", "") +DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_RANDOMIZE, def_geo_attribute_randomize, "ATTRIBUTE_RANDOMIZE", AttributeRandomize, "Attribute Randomize", "") DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_MATH, def_geo_attribute_math, "ATTRIBUTE_MATH", AttributeMath, "Attribute Math", "") DefNode(GeometryNode, GEO_NODE_JOIN_GEOMETRY, 0, "JOIN_GEOMETRY", JoinGeometry, "Join Geometry", "") DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_FILL, def_geo_attribute_fill, "ATTRIBUTE_FILL", AttributeFill, "Attribute Fill", "") diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_randomize.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_randomize.cc new file mode 100644 index 00000000000..bde9a2a695e --- /dev/null +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_randomize.cc @@ -0,0 +1,162 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "node_geometry_util.hh" + +#include "BLI_rand.hh" + +#include "DNA_mesh_types.h" +#include "DNA_pointcloud_types.h" + +static bNodeSocketTemplate geo_node_attribute_randomize_in[] = { + {SOCK_GEOMETRY, N_("Geometry")}, + {SOCK_STRING, N_("Attribute")}, + {SOCK_VECTOR, N_("Min"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX}, + {SOCK_VECTOR, N_("Max"), 1.0f, 1.0f, 1.0f, 0.0f, -FLT_MAX, FLT_MAX}, + {SOCK_FLOAT, N_("Min"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX}, + {SOCK_FLOAT, N_("Max"), 1.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX}, + {SOCK_INT, N_("Seed"), 0, 0, 0, 0, -10000, 10000}, + {-1, ""}, +}; + +static bNodeSocketTemplate geo_node_attribute_randomize_out[] = { + {SOCK_GEOMETRY, N_("Geometry")}, + {-1, ""}, +}; + +static void geo_node_attribute_randomize_init(bNodeTree *UNUSED(tree), bNode *node) +{ + node->custom1 = CD_PROP_FLOAT; +} + +static void geo_node_attribute_randomize_update(bNodeTree *UNUSED(ntree), bNode *node) +{ + bNodeSocket *sock_min_vector = (bNodeSocket *)BLI_findlink(&node->inputs, 2); + bNodeSocket *sock_max_vector = sock_min_vector->next; + bNodeSocket *sock_min_float = sock_max_vector->next; + bNodeSocket *sock_max_float = sock_min_float->next; + + const int data_type = node->custom1; + + nodeSetSocketAvailability(sock_min_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(sock_max_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(sock_min_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(sock_max_float, data_type == CD_PROP_FLOAT); +} + +namespace blender::nodes { + +static void randomize_attribute(FloatWriteAttribute &attribute, + float min, + float max, + RandomNumberGenerator &rng) +{ + MutableSpan attribute_span = attribute.get_span(); + for (const int i : IndexRange(attribute.size())) { + const float value = rng.get_float() * (max - min) + min; + attribute_span[i] = value; + } + attribute.apply_span(); +} + +static void randomize_attribute(Float3WriteAttribute &attribute, + float3 min, + float3 max, + RandomNumberGenerator &rng) +{ + MutableSpan attribute_span = attribute.get_span(); + for (const int i : IndexRange(attribute.size())) { + const float x = rng.get_float(); + const float y = rng.get_float(); + const float z = rng.get_float(); + const float3 value = float3(x, y, z) * (max - min) + min; + attribute_span[i] = value; + } + attribute.apply_span(); +} + +static void randomize_attribute(GeometryComponent &component, + const GeoNodeExecParams ¶ms, + RandomNumberGenerator &rng) +{ + const bNode &node = params.node(); + const CustomDataType data_type = static_cast(node.custom1); + const AttributeDomain domain = static_cast(node.custom2); + const std::string attribute_name = params.get_input("Attribute"); + if (attribute_name.empty()) { + return; + } + + WriteAttributePtr attribute = component.attribute_try_ensure_for_write( + attribute_name, domain, data_type); + if (!attribute) { + return; + } + + switch (data_type) { + case CD_PROP_FLOAT: { + FloatWriteAttribute float_attribute = std::move(attribute); + const float min_value = params.get_input("Min_001"); + const float max_value = params.get_input("Max_001"); + randomize_attribute(float_attribute, min_value, max_value, rng); + break; + } + case CD_PROP_FLOAT3: { + Float3WriteAttribute float3_attribute = std::move(attribute); + const float3 min_value = params.get_input("Min"); + const float3 max_value = params.get_input("Max"); + randomize_attribute(float3_attribute, min_value, max_value, rng); + break; + } + default: + break; + } +} + +static void geo_node_random_attribute_exec(GeoNodeExecParams params) +{ + GeometrySet geometry_set = params.extract_input("Geometry"); + const int seed = params.get_input("Seed"); + + if (geometry_set.has()) { + RandomNumberGenerator rng; + rng.seed_random(seed); + randomize_attribute(geometry_set.get_component_for_write(), params, rng); + } + if (geometry_set.has()) { + RandomNumberGenerator rng; + rng.seed_random(seed + 3245231); + randomize_attribute(geometry_set.get_component_for_write(), params, rng); + } + + params.set_output("Geometry", geometry_set); +} + +} // namespace blender::nodes + +void register_node_type_geo_attribute_randomize() +{ + static bNodeType ntype; + + geo_node_type_base( + &ntype, GEO_NODE_ATTRIBUTE_RANDOMIZE, "Attribute Randomize", NODE_CLASS_ATTRIBUTE, 0); + node_type_socket_templates( + &ntype, geo_node_attribute_randomize_in, geo_node_attribute_randomize_out); + node_type_init(&ntype, geo_node_attribute_randomize_init); + node_type_update(&ntype, geo_node_attribute_randomize_update); + ntype.geometry_node_execute = blender::nodes::geo_node_random_attribute_exec; + nodeRegisterType(&ntype); +} diff --git a/source/blender/nodes/geometry/nodes/node_geo_random_attribute.cc b/source/blender/nodes/geometry/nodes/node_geo_random_attribute.cc deleted file mode 100644 index 5cacb96412c..00000000000 --- a/source/blender/nodes/geometry/nodes/node_geo_random_attribute.cc +++ /dev/null @@ -1,161 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include "node_geometry_util.hh" - -#include "BLI_rand.hh" - -#include "DNA_mesh_types.h" -#include "DNA_pointcloud_types.h" - -static bNodeSocketTemplate geo_node_random_attribute_in[] = { - {SOCK_GEOMETRY, N_("Geometry")}, - {SOCK_STRING, N_("Attribute")}, - {SOCK_VECTOR, N_("Min"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX}, - {SOCK_VECTOR, N_("Max"), 1.0f, 1.0f, 1.0f, 0.0f, -FLT_MAX, FLT_MAX}, - {SOCK_FLOAT, N_("Min"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX}, - {SOCK_FLOAT, N_("Max"), 1.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX}, - {SOCK_INT, N_("Seed"), 0, 0, 0, 0, -10000, 10000}, - {-1, ""}, -}; - -static bNodeSocketTemplate geo_node_random_attribute_out[] = { - {SOCK_GEOMETRY, N_("Geometry")}, - {-1, ""}, -}; - -static void geo_node_random_attribute_init(bNodeTree *UNUSED(tree), bNode *node) -{ - node->custom1 = CD_PROP_FLOAT; -} - -static void geo_node_random_attribute_update(bNodeTree *UNUSED(ntree), bNode *node) -{ - bNodeSocket *sock_min_vector = (bNodeSocket *)BLI_findlink(&node->inputs, 2); - bNodeSocket *sock_max_vector = sock_min_vector->next; - bNodeSocket *sock_min_float = sock_max_vector->next; - bNodeSocket *sock_max_float = sock_min_float->next; - - const int data_type = node->custom1; - - nodeSetSocketAvailability(sock_min_vector, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(sock_max_vector, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(sock_min_float, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(sock_max_float, data_type == CD_PROP_FLOAT); -} - -namespace blender::nodes { - -static void randomize_attribute(FloatWriteAttribute &attribute, - float min, - float max, - RandomNumberGenerator &rng) -{ - MutableSpan attribute_span = attribute.get_span(); - for (const int i : IndexRange(attribute.size())) { - const float value = rng.get_float() * (max - min) + min; - attribute_span[i] = value; - } - attribute.apply_span(); -} - -static void randomize_attribute(Float3WriteAttribute &attribute, - float3 min, - float3 max, - RandomNumberGenerator &rng) -{ - MutableSpan attribute_span = attribute.get_span(); - for (const int i : IndexRange(attribute.size())) { - const float x = rng.get_float(); - const float y = rng.get_float(); - const float z = rng.get_float(); - const float3 value = float3(x, y, z) * (max - min) + min; - attribute_span[i] = value; - } - attribute.apply_span(); -} - -static void randomize_attribute(GeometryComponent &component, - const GeoNodeExecParams ¶ms, - RandomNumberGenerator &rng) -{ - const bNode &node = params.node(); - const CustomDataType data_type = static_cast(node.custom1); - const AttributeDomain domain = static_cast(node.custom2); - const std::string attribute_name = params.get_input("Attribute"); - if (attribute_name.empty()) { - return; - } - - WriteAttributePtr attribute = component.attribute_try_ensure_for_write( - attribute_name, domain, data_type); - if (!attribute) { - return; - } - - switch (data_type) { - case CD_PROP_FLOAT: { - FloatWriteAttribute float_attribute = std::move(attribute); - const float min_value = params.get_input("Min_001"); - const float max_value = params.get_input("Max_001"); - randomize_attribute(float_attribute, min_value, max_value, rng); - break; - } - case CD_PROP_FLOAT3: { - Float3WriteAttribute float3_attribute = std::move(attribute); - const float3 min_value = params.get_input("Min"); - const float3 max_value = params.get_input("Max"); - randomize_attribute(float3_attribute, min_value, max_value, rng); - break; - } - default: - break; - } -} - -static void geo_node_random_attribute_exec(GeoNodeExecParams params) -{ - GeometrySet geometry_set = params.extract_input("Geometry"); - const int seed = params.get_input("Seed"); - - if (geometry_set.has()) { - RandomNumberGenerator rng; - rng.seed_random(seed); - randomize_attribute(geometry_set.get_component_for_write(), params, rng); - } - if (geometry_set.has()) { - RandomNumberGenerator rng; - rng.seed_random(seed + 3245231); - randomize_attribute(geometry_set.get_component_for_write(), params, rng); - } - - params.set_output("Geometry", geometry_set); -} - -} // namespace blender::nodes - -void register_node_type_geo_random_attribute() -{ - static bNodeType ntype; - - geo_node_type_base( - &ntype, GEO_NODE_RANDOM_ATTRIBUTE, "Random Attribute", NODE_CLASS_ATTRIBUTE, 0); - node_type_socket_templates(&ntype, geo_node_random_attribute_in, geo_node_random_attribute_out); - node_type_init(&ntype, geo_node_random_attribute_init); - node_type_update(&ntype, geo_node_random_attribute_update); - ntype.geometry_node_execute = blender::nodes::geo_node_random_attribute_exec; - nodeRegisterType(&ntype); -} -- cgit v1.2.3 From 29f923b27c5c0a183791a2a97e80c5f469a4ef51 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Wed, 16 Dec 2020 13:54:02 +0100 Subject: Fix T83557: Alpha blend + emissive colors renders white artifacts Issue was that not all code paths were taken to determine if the GPU Texture was premultiplied or not. In this case the result was set to unpremultiplied what is incorrect. This fixes broken test case image alpha blend from image_colorspace. --- source/blender/blenkernel/intern/image_gpu.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/blenkernel/intern/image_gpu.c b/source/blender/blenkernel/intern/image_gpu.c index 9ed233ab34c..50138b34fa3 100644 --- a/source/blender/blenkernel/intern/image_gpu.c +++ b/source/blender/blenkernel/intern/image_gpu.c @@ -62,7 +62,7 @@ bool BKE_image_has_gpu_texture_premultiplied_alpha(Image *image, ImBuf *ibuf) return ibuf->rect_float != NULL; } } - else if (ibuf) { + if (ibuf) { if (ibuf->rect_float) { return image ? (image->alpha_mode != IMA_ALPHA_STRAIGHT) : false; } -- cgit v1.2.3 From 69c3f4a46d4621300ca2aa3ab778b24cb1713e95 Mon Sep 17 00:00:00 2001 From: Valdemar Lindberg Date: Wed, 16 Dec 2020 14:21:38 +0100 Subject: Fix 3D View is red when using stereo Fix T83415: 3D View is red when using stereo The red view was caused by SRGB not being enabled for an SRGB texture attached to the framebuffer. Currently, when configuring a framebuffer, the first texture attachment needs to be an SRGB format in order for the framebuffer to be binded with SRGB enabled. Thus, simply changing the SRGB texture attachment as the first texture attachment removes the red color in the view. Reviewed By: #eevee_viewport, jbakker Maniphest Tasks: T83415 Differential Revision: https://developer.blender.org/D9845 --- release/datafiles/locale | 2 +- release/scripts/addons | 2 +- source/blender/gpu/intern/gpu_viewport.c | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/release/datafiles/locale b/release/datafiles/locale index 9e40c01dffd..877a343fed9 160000 --- a/release/datafiles/locale +++ b/release/datafiles/locale @@ -1 +1 @@ -Subproject commit 9e40c01dffd3f720b23b906d20df8e999d34a4af +Subproject commit 877a343fed9613d8e02e7fe7181d3bbb628506f2 diff --git a/release/scripts/addons b/release/scripts/addons index 1a3f127714e..a3fa40ec0ba 160000 --- a/release/scripts/addons +++ b/release/scripts/addons @@ -1 +1 @@ -Subproject commit 1a3f127714e8da9f0af12d9a174dae9793ae63c1 +Subproject commit a3fa40ec0ba525bc96cbfad49f854a0230b0524e diff --git a/source/blender/gpu/intern/gpu_viewport.c b/source/blender/gpu/intern/gpu_viewport.c index 188c8786665..a83654d31e7 100644 --- a/source/blender/gpu/intern/gpu_viewport.c +++ b/source/blender/gpu/intern/gpu_viewport.c @@ -616,8 +616,8 @@ void GPU_viewport_stereo_composite(GPUViewport *viewport, Stereo3dFormat *stereo GPU_framebuffer_ensure_config(&dfbl->stereo_comp_fb, { GPU_ATTACHMENT_NONE, - GPU_ATTACHMENT_TEXTURE(dtxl->color), GPU_ATTACHMENT_TEXTURE(dtxl->color_overlay), + GPU_ATTACHMENT_TEXTURE(dtxl->color), }); GPUVertFormat *vert_format = immVertexFormat(); @@ -628,8 +628,8 @@ void GPU_viewport_stereo_composite(GPUViewport *viewport, Stereo3dFormat *stereo GPU_matrix_identity_set(); GPU_matrix_identity_projection_set(); immBindBuiltinProgram(GPU_SHADER_2D_IMAGE_OVERLAYS_STEREO_MERGE); - immUniform1i("imageTexture", 0); - immUniform1i("overlayTexture", 1); + immUniform1i("overlayTexture", 0); + immUniform1i("imageTexture", 1); int settings = stereo_format->display_mode; if (settings == S3D_DISPLAY_ANAGLYPH) { switch (stereo_format->anaglyph_type) { -- cgit v1.2.3 From 245450b1441208c2e5975dd061afe8040618d027 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Thu, 17 Dec 2020 00:52:04 +1100 Subject: Fix exported keymaps loading in 2.91 and older The generated keymaps used a keyword argument that doesn't exist in older Blender versions. --- release/scripts/modules/bl_keymap_utils/io.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/release/scripts/modules/bl_keymap_utils/io.py b/release/scripts/modules/bl_keymap_utils/io.py index 091cdbc2642..645a145f994 100644 --- a/release/scripts/modules/bl_keymap_utils/io.py +++ b/release/scripts/modules/bl_keymap_utils/io.py @@ -222,12 +222,21 @@ def keyconfig_export_as_data(wm, kc, filepath, *, all_keymaps=False): fw("]\n") fw("\n\n") fw("if __name__ == \"__main__\":\n") + + # We could remove this in the future, as loading new key-maps in older Blender versions + # makes less and less sense as Blender changes. + fw(" # Only add keywords that are supported.\n") + fw(" from bpy.app import version as blender_version\n") + fw(" keywords = {}\n") + fw(" if blender_version >= (2, 92, 0):\n") + fw(" keywords[\"keyconfig_version\"] = keyconfig_version\n") + fw(" import os\n") fw(" from bl_keymap_utils.io import keyconfig_import_from_data\n") fw(" keyconfig_import_from_data(\n") fw(" os.path.splitext(os.path.basename(__file__))[0],\n") fw(" keyconfig_data,\n") - fw(" keyconfig_version=keyconfig_version,\n") + fw(" **keywords,\n") fw(" )\n") -- cgit v1.2.3 From 8da62a9a86d98676ff0bc4cffd389dcbed7e3071 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Wed, 16 Dec 2020 15:01:25 +0100 Subject: Fix T83547: UV Editor stitching preview is gone. Issue was related that the draw manager didn't invoked the draw handlers for image editors. --- source/blender/draw/intern/draw_manager.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index 988975bd399..ffc565d0514 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -2073,7 +2073,6 @@ void DRW_draw_render_loop_2d_ex(struct Depsgraph *depsgraph, * for the image editor this is when showing UV's.*/ const bool do_populate_loop = (DST.draw_ctx.space_data->spacetype == SPACE_IMAGE); const bool do_annotations = drw_draw_show_annotation(); - const bool do_region_callbacks = (DST.draw_ctx.space_data->spacetype != SPACE_IMAGE); const bool do_draw_gizmos = (DST.draw_ctx.space_data->spacetype != SPACE_IMAGE); /* Get list of enabled engines */ @@ -2125,7 +2124,7 @@ void DRW_draw_render_loop_2d_ex(struct Depsgraph *depsgraph, /* Start Drawing */ DRW_state_reset(); - if (do_region_callbacks && DST.draw_ctx.evil_C) { + if (DST.draw_ctx.evil_C) { ED_region_draw_cb_draw(DST.draw_ctx.evil_C, DST.draw_ctx.region, REGION_DRAW_PRE_VIEW); } @@ -2147,10 +2146,8 @@ void DRW_draw_render_loop_2d_ex(struct Depsgraph *depsgraph, if (do_annotations) { ED_annotation_draw_view2d(DST.draw_ctx.evil_C, true); } - if (do_region_callbacks) { - GPU_depth_test(GPU_DEPTH_NONE); - ED_region_draw_cb_draw(DST.draw_ctx.evil_C, DST.draw_ctx.region, REGION_DRAW_POST_VIEW); - } + GPU_depth_test(GPU_DEPTH_NONE); + ED_region_draw_cb_draw(DST.draw_ctx.evil_C, DST.draw_ctx.region, REGION_DRAW_POST_VIEW); GPU_matrix_pop_projection(); /* Callback can be nasty and do whatever they want with the state. * Don't trust them! */ -- cgit v1.2.3 From 8d590e4b86287be22567d1adf8c6a7946bc7f63d Mon Sep 17 00:00:00 2001 From: Philipp Oeser Date: Wed, 16 Dec 2020 10:14:58 +0100 Subject: Fix T83801: UVEditor translation ignores "Pixel Coordinates" and aspect ratio Caused by rB4eda60c2d82d. T83801 reported not moving in pixel space, but even without that toggle above commit caused the translation to not take apsect ratio into account properly [a translation of 1 on the x axis for example on an image with non 1:1 aspect ration caused the UVs to not end up in the same place on the next 'tile'] Above commit removed 'removeAspectRatio()' [the counterpart of applyAspectRatio -- which does the pixel coord correction internally] from 'applyTranslation()'. This was also reported in T83352 [which was closed by rBf3b08af24c9f -- but that only solved the displax in header, not the actual transformation] Now bring back 'removeAspectRatio()'. Maniphest Tasks: T83801 Differential Revision: https://developer.blender.org/D9869 --- source/blender/editors/transform/transform_mode_translate.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/source/blender/editors/transform/transform_mode_translate.c b/source/blender/editors/transform/transform_mode_translate.c index 90c1f241338..8597c372537 100644 --- a/source/blender/editors/transform/transform_mode_translate.c +++ b/source/blender/editors/transform/transform_mode_translate.c @@ -377,6 +377,9 @@ static void applyTranslation(TransInfo *t, const int UNUSED(mval[2])) else { mul_v3_m3v3(global_dir, t->spacemtx, global_dir); } + if (t->flag & T_2D_EDIT) { + removeAspectRatio(t, global_dir); + } } else { copy_v3_v3(global_dir, t->values); -- cgit v1.2.3 From 25543e6983602b4d14f51d73396c652b2aa65aa0 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Wed, 16 Dec 2020 15:10:28 +0100 Subject: LibOverride: Better handling of missing linked data during resync. We do not generate overrides for missing data-blocks (aka placeholder ones) anymore, and properly delete the remaining old overrides of those during the resync process. This should prevent constant 'missing data-blocks' messages when opening blend files with overrides whose libraries have beed edited. Issue reported by @andy from Blender studio, thanks. --- source/blender/blenkernel/BKE_lib_override.h | 1 + source/blender/blenkernel/intern/lib_override.c | 32 ++++++++++++++++++------- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/source/blender/blenkernel/BKE_lib_override.h b/source/blender/blenkernel/BKE_lib_override.h index bf6b5cbccef..13edabd4cb7 100644 --- a/source/blender/blenkernel/BKE_lib_override.h +++ b/source/blender/blenkernel/BKE_lib_override.h @@ -72,6 +72,7 @@ void BKE_lib_override_library_dependencies_tag(struct Main *bmain, void BKE_lib_override_library_override_group_tag(struct Main *bmain, struct ID *id_root, const uint tag, + const uint missing_tag, const bool do_create_main_relashionships); bool BKE_lib_override_library_create(struct Main *bmain, struct Scene *scene, diff --git a/source/blender/blenkernel/intern/lib_override.c b/source/blender/blenkernel/intern/lib_override.c index d82315a0e7f..11544d83ba9 100644 --- a/source/blender/blenkernel/intern/lib_override.c +++ b/source/blender/blenkernel/intern/lib_override.c @@ -369,6 +369,7 @@ bool BKE_lib_override_library_create_from_tag(Main *bmain) static bool lib_override_hierarchy_recursive_tag(Main *bmain, ID *id, const uint tag, + const uint missing_tag, Library *override_group_lib_reference) { void **entry_vp = BLI_ghash_lookup_p(bmain->relations->id_user_to_used, id); @@ -377,9 +378,16 @@ static bool lib_override_hierarchy_recursive_tag(Main *bmain, return (id->tag & tag) != 0; } + /* Note: in case some reference ID is missing from linked data (and therefore its override uses + * a placeholder as reference), use `missing_tag` instead of `tag` for this override. */ if (override_group_lib_reference != NULL && ID_IS_OVERRIDE_LIBRARY_REAL(id) && id->override_library->reference->lib == override_group_lib_reference) { - id->tag |= tag; + if (id->override_library->reference->tag & LIB_TAG_MISSING) { + id->tag |= missing_tag; + } + else { + id->tag |= tag; + } } /* This way we won't process again that ID, should we encounter it again through another @@ -397,7 +405,7 @@ static bool lib_override_hierarchy_recursive_tag(Main *bmain, /* We only consider IDs from the same library. */ if (entry->id_pointer != NULL && (*entry->id_pointer)->lib == id->lib) { if (lib_override_hierarchy_recursive_tag( - bmain, *entry->id_pointer, tag, override_group_lib_reference) && + bmain, *entry->id_pointer, tag, missing_tag, override_group_lib_reference) && override_group_lib_reference == NULL) { id->tag |= tag; } @@ -430,7 +438,7 @@ void BKE_lib_override_library_dependencies_tag(Main *bmain, /* We tag all intermediary data-blocks in-between two overridden ones (e.g. if a shape-key * has a driver using an armature object's bone, we need to override the shape-key/obdata, * the objects using them, etc.) */ - lib_override_hierarchy_recursive_tag(bmain, id_root, tag, NULL); + lib_override_hierarchy_recursive_tag(bmain, id_root, tag, 0, NULL); BKE_main_relations_free(bmain); } @@ -447,6 +455,7 @@ void BKE_lib_override_library_dependencies_tag(Main *bmain, void BKE_lib_override_library_override_group_tag(Main *bmain, ID *id_root, const uint tag, + const uint missing_tag, const bool do_create_main_relashionships) { if (do_create_main_relashionships) { @@ -456,7 +465,7 @@ void BKE_lib_override_library_override_group_tag(Main *bmain, /* We tag all liboverride data-blocks from the same library as reference one, * being used by the root ID. */ lib_override_hierarchy_recursive_tag( - bmain, id_root, tag, id_root->override_library->reference->lib); + bmain, id_root, tag, missing_tag, id_root->override_library->reference->lib); BKE_main_relations_free(bmain); } @@ -492,8 +501,9 @@ static int lib_override_library_make_tag_ids_cb(LibraryIDLinkCallbackData *cb_da } /* We tag all collections and objects for override. And we also tag all other data-blocks which - * would use one of those. */ - if (ELEM(GS(id->name), ID_OB, ID_GR)) { + * would use one of those. + * Note: missing IDs (aka placeholders) are never overridden. */ + if (ELEM(GS(id->name), ID_OB, ID_GR) && !(id->tag & LIB_TAG_MISSING)) { id->tag |= LIB_TAG_DOIT; } @@ -725,7 +735,7 @@ bool BKE_lib_override_library_resync(Main *bmain, Scene *scene, ViewLayer *view_ /* Make a mapping 'linked reference IDs' -> 'Local override IDs' of existing overrides, and tag * linked reference ones to be overridden again. */ - BKE_lib_override_library_override_group_tag(bmain, id_root, LIB_TAG_DOIT, true); + BKE_lib_override_library_override_group_tag(bmain, id_root, LIB_TAG_DOIT, LIB_TAG_MISSING, true); GHash *linkedref_to_old_override = BLI_ghash_new( BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__); @@ -835,6 +845,12 @@ bool BKE_lib_override_library_resync(Main *bmain, Scene *scene, ViewLayer *view_ } id->tag &= ~LIB_TAG_DOIT; } + /* Also cleanup old overrides that went missing in new linked data. */ + else if (id->tag & LIB_TAG_MISSING && !ID_IS_LINKED(id)) { + BLI_assert(ID_IS_OVERRIDE_LIBRARY(id)); + id->tag |= LIB_TAG_DOIT; + id->tag &= ~LIB_TAG_MISSING; + } } FOREACH_MAIN_ID_END; BKE_id_multi_tagged_delete(bmain); @@ -876,7 +892,7 @@ void BKE_lib_override_library_delete(Main *bmain, ID *id_root) id_root->tag |= LIB_TAG_DOIT; /* Tag all library overrides in the chains of dependencies from the given root one. */ - BKE_lib_override_library_override_group_tag(bmain, id_root, LIB_TAG_DOIT, true); + BKE_lib_override_library_override_group_tag(bmain, id_root, LIB_TAG_DOIT, LIB_TAG_DOIT, true); ID *id; FOREACH_MAIN_ID_BEGIN (bmain, id) { -- cgit v1.2.3 From 684c771263db1a5a7dbf65cde97e672d94b57839 Mon Sep 17 00:00:00 2001 From: Ray Molenkamp Date: Wed, 16 Dec 2020 07:27:47 -0700 Subject: Fix: Python warning in windows debug builds When doing a debug build on windows, blender will start with the following warning: "Unable to find the python binary, the multiprocessing module may not be functional!" The root cause for this issue is: for a debug build the python binary is called python_d.exe rather than just python.exe This change fixes BKE_appdir_program_python_search to look for the _d suffix for debug builds on windows Differential Revision: https://developer.blender.org/D9775 Reviewed by: Campbell Barton --- source/blender/blenkernel/intern/appdir.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/source/blender/blenkernel/intern/appdir.c b/source/blender/blenkernel/intern/appdir.c index a6b3985e80d..ae0c27635a6 100644 --- a/source/blender/blenkernel/intern/appdir.c +++ b/source/blender/blenkernel/intern/appdir.c @@ -906,14 +906,20 @@ bool BKE_appdir_program_python_search(char *fullpath, const char *python_build_def = STRINGIFY(PYTHON_EXECUTABLE_NAME); #endif const char *basename = "python"; +#if defined(WIN32) && !defined(NDEBUG) + const char *basename_debug = "python_d"; +#endif char python_version[16]; /* Check both possible names. */ const char *python_names[] = { #ifdef PYTHON_EXECUTABLE_NAME - python_build_def, + python_build_def, +#endif +#if defined(WIN32) && !defined(NDEBUG) + basename_debug, #endif - python_version, - basename, + python_version, + basename, }; bool is_found = false; -- cgit v1.2.3 From 4463087223983c40a6d67beab0513fba7cdb7538 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Wed, 16 Dec 2020 15:59:58 +0100 Subject: BLI: remove implicit casts between some span types Casting pointers from one type to another does change the value of the pointer in some cases. Therefore, casting a span that contains pointers of one type to a span that contains pointers of another type, is not generally safe. In practice, this issue mainly comes up when dealing with classes that have a vtable. There are some special cases that are still allowed. For example, adding const to the pointer does not change the address. Also, casting to a void pointer is fine. In cases where implicit conversion is disabled, but one is sure that the cast is valid, an explicit call of `span.cast()` can be used. --- source/blender/blenlib/BLI_array.hh | 4 ++-- source/blender/blenlib/BLI_memory_utils.hh | 19 +++++++++++++++++++ source/blender/blenlib/BLI_span.hh | 5 +++-- source/blender/blenlib/BLI_vector.hh | 4 ++-- source/blender/blenlib/tests/BLI_memory_utils_test.cc | 11 +++++++++++ 5 files changed, 37 insertions(+), 6 deletions(-) diff --git a/source/blender/blenlib/BLI_array.hh b/source/blender/blenlib/BLI_array.hh index 8a7dcb7ffaa..284d62fb876 100644 --- a/source/blender/blenlib/BLI_array.hh +++ b/source/blender/blenlib/BLI_array.hh @@ -220,13 +220,13 @@ class Array { return MutableSpan(data_, size_); } - template> * = nullptr> + template> * = nullptr> operator Span() const { return Span(data_, size_); } - template> * = nullptr> + template> * = nullptr> operator MutableSpan() { return MutableSpan(data_, size_); diff --git a/source/blender/blenlib/BLI_memory_utils.hh b/source/blender/blenlib/BLI_memory_utils.hh index 49076bb1aae..b3b6855089e 100644 --- a/source/blender/blenlib/BLI_memory_utils.hh +++ b/source/blender/blenlib/BLI_memory_utils.hh @@ -427,6 +427,25 @@ template inline constexpr bool is_convertible_pointer_v = std::is_convertible_v &&std::is_pointer_v &&std::is_pointer_v; +/** + * Helper variable that checks if a Span can be converted to Span safely, whereby From + * and To are pointers. Adding const and casting to a void pointer is allowed. + * Casting up and down a class hierarchy generally is not allowed, because this might change the + * pointer under some circumstances. + */ +template +inline constexpr bool is_span_convertible_pointer_v = + /* Make sure we are working with pointers. */ + std::is_pointer_v &&std::is_pointer_v && + (/* No casting is necessary when both types are the same. */ + std::is_same_v || + /* Allow adding const to the underlying type. */ + std::is_same_v, std::remove_pointer_t> || + /* Allow casting non-const pointers to void pointers. */ + (!std::is_const_v> && std::is_same_v) || + /* Allow casting any pointer to const void pointers. */ + std::is_same_v); + /** * Inline buffers for small-object-optimization should be disable by default. Otherwise we might * get large unexpected allocations on the stack. diff --git a/source/blender/blenlib/BLI_span.hh b/source/blender/blenlib/BLI_span.hh index 3f410efe908..8011b2f9abc 100644 --- a/source/blender/blenlib/BLI_span.hh +++ b/source/blender/blenlib/BLI_span.hh @@ -100,7 +100,7 @@ template class Span { BLI_assert(size >= 0); } - template> * = nullptr> + template> * = nullptr> constexpr Span(const U *start, int64_t size) : data_(static_cast(start)), size_(size) { BLI_assert(size >= 0); @@ -135,7 +135,8 @@ template class Span { * Support implicit conversions like the ones below: * Span -> Span */ - template> * = nullptr> + + template> * = nullptr> constexpr Span(Span array) : data_(static_cast(array.data())), size_(array.size()) { } diff --git a/source/blender/blenlib/BLI_vector.hh b/source/blender/blenlib/BLI_vector.hh index 053dcb6faea..fe6d54ae9e5 100644 --- a/source/blender/blenlib/BLI_vector.hh +++ b/source/blender/blenlib/BLI_vector.hh @@ -315,13 +315,13 @@ class Vector { return MutableSpan(begin_, this->size()); } - template> * = nullptr> + template> * = nullptr> operator Span() const { return Span(begin_, this->size()); } - template> * = nullptr> + template> * = nullptr> operator MutableSpan() { return MutableSpan(begin_, this->size()); diff --git a/source/blender/blenlib/tests/BLI_memory_utils_test.cc b/source/blender/blenlib/tests/BLI_memory_utils_test.cc index fcef2f8688a..23415e69b04 100644 --- a/source/blender/blenlib/tests/BLI_memory_utils_test.cc +++ b/source/blender/blenlib/tests/BLI_memory_utils_test.cc @@ -158,4 +158,15 @@ static_assert(is_convertible_pointer_v); static_assert(is_convertible_pointer_v); static_assert(is_convertible_pointer_v); +static_assert(is_span_convertible_pointer_v); +static_assert(is_span_convertible_pointer_v); +static_assert(!is_span_convertible_pointer_v); +static_assert(is_span_convertible_pointer_v); +static_assert(is_span_convertible_pointer_v); +static_assert(!is_span_convertible_pointer_v); +static_assert(is_span_convertible_pointer_v); +static_assert(is_span_convertible_pointer_v); +static_assert(!is_span_convertible_pointer_v); +static_assert(!is_span_convertible_pointer_v); + } // namespace blender::tests -- cgit v1.2.3 From 7ed69bd672555f6bbedc598aacda56efb6eeafbb Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Wed, 16 Dec 2020 16:07:23 +0100 Subject: Fix T83843: Crash in Asset Browser sidebar with geometry asset selected No icon should be created if the preview doesn't exist. --- source/blender/editors/space_file/filelist.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c index 3ed7b5499db..8202a87864d 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -1511,7 +1511,9 @@ static void filelist_cache_preview_runf(TaskPool *__restrict pool, void *taskdat * in case user switch to a bigger preview size. */ ImBuf *imbuf = IMB_thumb_manage(preview->path, THB_LARGE, source); IMB_thumb_path_unlock(preview->path); - preview->icon_id = BKE_icon_imbuf_create(imbuf); + if (imbuf) { + preview->icon_id = BKE_icon_imbuf_create(imbuf); + } done = true; } -- cgit v1.2.3 From 5c5550f7b821cb6c67009682fec85ce0929474a3 Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Wed, 16 Dec 2020 16:10:53 +0100 Subject: Asset Browser: For assets without preview, show type icon in sidebar Otherwise it would just show empty space where the icon is supposed to be. Unfortunately this icon is upscaled quite a bit and doesn't look too great. Would be good to improve but not a high priority. --- source/blender/editors/include/ED_fileselect.h | 2 ++ source/blender/editors/space_file/filelist.c | 10 ++++++++-- source/blender/makesrna/intern/rna_space.c | 2 +- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/source/blender/editors/include/ED_fileselect.h b/source/blender/editors/include/ED_fileselect.h index 6c66a6162b8..7b240e0569f 100644 --- a/source/blender/editors/include/ED_fileselect.h +++ b/source/blender/editors/include/ED_fileselect.h @@ -30,6 +30,7 @@ extern "C" { struct ARegion; struct FileAssetSelectParams; struct FileSelectParams; +struct FileDirEntry; struct Scene; struct ScrArea; struct SpaceFile; @@ -154,6 +155,7 @@ struct ScrArea *ED_fileselect_handler_area_find(const struct wmWindow *win, int ED_path_extension_type(const char *path); int ED_file_extension_icon(const char *path); +int ED_file_icon(const struct FileDirEntry *file); void ED_file_read_bookmarks(void); diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c index 8202a87864d..d66219c7549 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -1178,7 +1178,7 @@ ImBuf *filelist_geticon_image(struct FileList *filelist, const int index) return filelist_geticon_image_ex(file); } -static int filelist_geticon_ex(FileDirEntry *file, +static int filelist_geticon_ex(const FileDirEntry *file, const char *root, const bool is_main, const bool ignore_libdir) @@ -1217,7 +1217,7 @@ static int filelist_geticon_ex(FileDirEntry *file, if (file->redirection_path) { target = file->redirection_path; } - else { + else if (root) { BLI_join_dirfile(fullpath, sizeof(fullpath), root, file->relpath); BLI_path_slash_ensure(fullpath); } @@ -1301,6 +1301,12 @@ int filelist_geticon(struct FileList *filelist, const int index, const bool is_m return filelist_geticon_ex(file, filelist->filelist.root, is_main, false); } +int ED_file_icon(const FileDirEntry *file) +{ + return file->preview_icon_id ? file->preview_icon_id : + filelist_geticon_ex(file, NULL, false, false); +} + /* ********** Main ********** */ static void parent_dir_until_exists_or_default_root(char *dir) diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index 7405bc541c9..2f821dad811 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -2602,7 +2602,7 @@ static int rna_FileBrowser_FileSelectEntry_name_length(PointerRNA *ptr) static int rna_FileBrowser_FileSelectEntry_preview_icon_id_get(PointerRNA *ptr) { const FileDirEntry *entry = ptr->data; - return entry->preview_icon_id; + return ED_file_icon(entry); } static PointerRNA rna_FileBrowser_FileSelectEntry_asset_data_get(PointerRNA *ptr) -- cgit v1.2.3 From f3ab123e33b87cfcf4d310323572c798f9953201 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Wed, 16 Dec 2020 16:16:50 +0100 Subject: Cleanup: Remove unused crop field from RenderResult. The `crop` field was used by Blender Internal to do an overscan per tile and merge it back to the render result. --- source/blender/editors/render/render_internal.c | 18 +++++----- source/blender/render/RE_pipeline.h | 2 +- source/blender/render/intern/engine.c | 4 +-- source/blender/render/intern/pipeline.c | 6 ++-- source/blender/render/intern/render_result.c | 47 ++++++------------------- source/blender/render/intern/render_result.h | 1 - 6 files changed, 26 insertions(+), 52 deletions(-) diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c index 3dbf70aa4bc..a035ee3e342 100644 --- a/source/blender/editors/render/render_internal.c +++ b/source/blender/editors/render/render_internal.c @@ -150,31 +150,31 @@ static void image_buffer_rect_update(RenderJob *rj, } /* xmin here is first subrect x coord, xmax defines subrect width */ - xmin = renrect->xmin + rr->crop; - xmax = renrect->xmax - xmin + rr->crop; + xmin = renrect->xmin; + xmax = renrect->xmax - xmin; if (xmax < 2) { return; } - ymin = renrect->ymin + rr->crop; - ymax = renrect->ymax - ymin + rr->crop; + ymin = renrect->ymin; + ymax = renrect->ymax - ymin; if (ymax < 2) { return; } renrect->ymin = renrect->ymax; } else { - xmin = ymin = rr->crop; - xmax = rr->rectx - 2 * rr->crop; - ymax = rr->recty - 2 * rr->crop; + xmin = ymin = 0; + xmax = rr->rectx; + ymax = rr->recty; } /* xmin ymin is in tile coords. transform to ibuf */ - rxmin = rr->tilerect.xmin + xmin; + rxmin = rr->tilerect.xmin; if (rxmin >= ibuf->x) { return; } - rymin = rr->tilerect.ymin + ymin; + rymin = rr->tilerect.ymin; if (rymin >= ibuf->y) { return; } diff --git a/source/blender/render/RE_pipeline.h b/source/blender/render/RE_pipeline.h index 4dd2b300700..3e73ac77fc6 100644 --- a/source/blender/render/RE_pipeline.h +++ b/source/blender/render/RE_pipeline.h @@ -114,7 +114,7 @@ typedef struct RenderResult { /* target image size */ int rectx, recty; - short crop, sample_nr; + short sample_nr; /* The following rect32, rectf and rectz buffers are for temporary storage only, * for RenderResult structs created in #RE_AcquireResultImage - which do not have RenderView */ diff --git a/source/blender/render/intern/engine.c b/source/blender/render/intern/engine.c index 769077c0e8c..5685911c42e 100644 --- a/source/blender/render/intern/engine.c +++ b/source/blender/render/intern/engine.c @@ -288,7 +288,7 @@ RenderResult *RE_engine_begin_result( disprect.ymin = y; disprect.ymax = y + h; - result = render_result_new(re, &disprect, 0, RR_USE_MEM, layername, viewname); + result = render_result_new(re, &disprect, RR_USE_MEM, layername, viewname); /* todo: make this thread safe */ @@ -846,7 +846,7 @@ int RE_engine_render(Render *re, int do_all) if ((type->flag & RE_USE_SAVE_BUFFERS) && (re->r.scemode & R_EXR_TILE_FILE)) { savebuffers = RR_USE_EXR; } - re->result = render_result_new(re, &re->disprect, 0, savebuffers, RR_ALL_LAYERS, RR_ALL_VIEWS); + re->result = render_result_new(re, &re->disprect, savebuffers, RR_ALL_LAYERS, RR_ALL_VIEWS); } BLI_rw_mutex_unlock(&re->resultmutex); diff --git a/source/blender/render/intern/pipeline.c b/source/blender/render/intern/pipeline.c index 3d19e5e6c15..6b55b82ac97 100644 --- a/source/blender/render/intern/pipeline.c +++ b/source/blender/render/intern/pipeline.c @@ -905,7 +905,7 @@ static void render_result_rescale(Render *re) if (src_rectf != NULL) { float *dst_rectf = NULL; - re->result = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS, ""); + re->result = render_result_new(re, &re->disprect, RR_USE_MEM, RR_ALL_LAYERS, ""); if (re->result != NULL) { dst_rectf = RE_RenderViewGetById(re->result, 0)->rectf; @@ -1162,7 +1162,7 @@ static void render_result_uncrop(Render *re) /* weak is: it chances disprect from border */ render_result_disprect_to_full_resolution(re); - rres = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS); + rres = render_result_new(re, &re->disprect, RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS); rres->stamp_data = BKE_stamp_data_copy(re->result->stamp_data); render_result_clone_passes(re, rres, NULL); @@ -1358,7 +1358,7 @@ static void do_render_composite(Render *re) if ((re->r.mode & R_CROP) == 0) { render_result_disprect_to_full_resolution(re); } - re->result = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS); + re->result = render_result_new(re, &re->disprect, RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS); BLI_rw_mutex_unlock(&re->resultmutex); diff --git a/source/blender/render/intern/render_result.c b/source/blender/render/intern/render_result.c index dfce51ec3ab..1ed894751ce 100644 --- a/source/blender/render/intern/render_result.c +++ b/source/blender/render/intern/render_result.c @@ -285,12 +285,8 @@ RenderPass *render_layer_add_pass(RenderResult *rr, /* will read info from Render *re to define layers */ /* called in threads */ /* re->winx,winy is coordinate space of entire image, partrct the part within */ -RenderResult *render_result_new(Render *re, - rcti *partrct, - int crop, - int savebuffers, - const char *layername, - const char *viewname) +RenderResult *render_result_new( + Render *re, rcti *partrct, int savebuffers, const char *layername, const char *viewname) { RenderResult *rr; RenderLayer *rl; @@ -308,9 +304,7 @@ RenderResult *render_result_new(Render *re, rr->rectx = rectx; rr->recty = recty; rr->renrect.xmin = 0; - rr->renrect.xmax = rectx - 2 * crop; - /* crop is one or two extra pixels rendered for filtering, is used for merging and display too */ - rr->crop = crop; + rr->renrect.xmax = rectx; /* tilerect is relative coordinates within render disprect. do not subtract crop yet */ rr->tilerect.xmin = partrct->xmin - re->disprect.xmin; @@ -827,20 +821,8 @@ static void do_merge_tile( copylen = tilex = rrpart->rectx; tiley = rrpart->recty; - if (rrpart->crop) { /* filters add pixel extra */ - tile += pixsize * (rrpart->crop + ((size_t)rrpart->crop) * tilex); - - copylen = tilex - 2 * rrpart->crop; - tiley -= 2 * rrpart->crop; - - ofs = (((size_t)rrpart->tilerect.ymin) + rrpart->crop) * rr->rectx + - (rrpart->tilerect.xmin + rrpart->crop); - target += pixsize * ofs; - } - else { - ofs = (((size_t)rrpart->tilerect.ymin) * rr->rectx + rrpart->tilerect.xmin); - target += pixsize * ofs; - } + ofs = (((size_t)rrpart->tilerect.ymin) * rr->rectx + rrpart->tilerect.xmin); + target += pixsize * ofs; copylen *= sizeof(float) * pixsize; tilex *= pixsize; @@ -1107,7 +1089,7 @@ static void save_render_result_tile(RenderResult *rr, RenderResult *rrpart, cons { RenderLayer *rlp, *rl; RenderPass *rpassp; - int offs, partx, party; + int partx, party; BLI_thread_lock(LOCK_IMAGE); @@ -1120,13 +1102,6 @@ static void save_render_result_tile(RenderResult *rr, RenderResult *rrpart, cons continue; } - if (rrpart->crop) { /* filters add pixel extra */ - offs = (rrpart->crop + rrpart->crop * rrpart->rectx); - } - else { - offs = 0; - } - /* passes are allocated in sync */ for (rpassp = rlp->passes.first; rpassp; rpassp = rpassp->next) { const int xstride = rpassp->channels; @@ -1141,13 +1116,13 @@ static void save_render_result_tile(RenderResult *rr, RenderResult *rrpart, cons fullname, xstride, xstride * rrpart->rectx, - rpassp->rect + a + xstride * offs); + rpassp->rect + a); } } } - party = rrpart->tilerect.ymin + rrpart->crop; - partx = rrpart->tilerect.xmin + rrpart->crop; + party = rrpart->tilerect.ymin; + partx = rrpart->tilerect.xmin; for (rlp = rrpart->layers.first; rlp; rlp = rlp->next) { rl = RE_GetRenderLayer(rr, rlp->name); @@ -1267,7 +1242,7 @@ void render_result_exr_file_end(Render *re, RenderEngine *engine) /* Create new render result in memory instead of on disk. */ BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE); render_result_free_list(&re->fullresult, re->result); - re->result = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS); + re->result = render_result_new(re, &re->disprect, RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS); BLI_rw_mutex_unlock(&re->resultmutex); LISTBASE_FOREACH (RenderLayer *, rl, &re->result->layers) { @@ -1429,7 +1404,7 @@ bool render_result_exr_file_cache_read(Render *re) char *root = U.render_cachedir; RE_FreeRenderResult(re->result); - re->result = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS); + re->result = render_result_new(re, &re->disprect, RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS); /* First try cache. */ render_result_exr_file_cache_path(re->scene, root, str); diff --git a/source/blender/render/intern/render_result.h b/source/blender/render/intern/render_result.h index 5c487223e94..67edd075e24 100644 --- a/source/blender/render/intern/render_result.h +++ b/source/blender/render/intern/render_result.h @@ -51,7 +51,6 @@ extern "C" { struct RenderResult *render_result_new(struct Render *re, struct rcti *partrct, - int crop, int savebuffers, const char *layername, const char *viewname); -- cgit v1.2.3 From d23894d3ef3f019eeb88ef3da77e8416c6f70f29 Mon Sep 17 00:00:00 2001 From: Pablo Dobarro Date: Fri, 11 Dec 2020 22:49:49 +0100 Subject: Sculpt: Multires Displacement Smear This tool implements smearing for multires displacement over the limit surface, similar to how smearing for colors and topology slide works. When used the displacement values of the vertices "slide" over the topology, creating the effect of smearing the surface detail. As the brush just modifies displacement values instead of coordinates, the total displacement of the affected area doesn't change. This means that this smearing effect can be used multiple times over the same area without generating any artifacts in the topology. When the brush is used with the pinch or expand smear modes, displacement differences are pushed into the same area, creating hard surface effects without pinching the topology. As any other brush that relies on the limit surface (like displacement erasers), this will work better after using apply base. Reviewed By: sergey, JulienKaspar, dbystedt Differential Revision: https://developer.blender.org/D9659 --- .../startup/bl_ui/properties_paint_common.py | 4 + source/blender/blenkernel/intern/brush.c | 9 ++ .../blenloader/intern/versioning_defaults.c | 8 ++ source/blender/editors/sculpt_paint/sculpt.c | 151 +++++++++++++++++++++ .../blender/editors/sculpt_paint/sculpt_intern.h | 4 + source/blender/makesdna/DNA_brush_enums.h | 1 + source/blender/makesdna/DNA_brush_types.h | 2 +- source/blender/makesrna/intern/rna_brush.c | 1 + 8 files changed, 179 insertions(+), 1 deletion(-) diff --git a/release/scripts/startup/bl_ui/properties_paint_common.py b/release/scripts/startup/bl_ui/properties_paint_common.py index 86221ebce59..5d241e8e216 100644 --- a/release/scripts/startup/bl_ui/properties_paint_common.py +++ b/release/scripts/startup/bl_ui/properties_paint_common.py @@ -764,6 +764,10 @@ def brush_settings(layout, context, brush, popover=False): col.prop(brush, "surface_smooth_current_vertex") col.prop(brush, "surface_smooth_iterations") + elif sculpt_tool == 'DISPLACEMENT_SMEAR': + col = layout.column() + col.prop(brush, "smear_deform_type") + elif sculpt_tool == 'MASK': layout.row().prop(brush, "mask_tool", expand=True) diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c index 33686cea4fc..9a954a89cad 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -1834,6 +1834,14 @@ void BKE_brush_sculpt_reset(Brush *br) br->flag &= ~BRUSH_SPACE_ATTEN; br->curve_preset = BRUSH_CURVE_SPHERE; break; + case SCULPT_TOOL_DISPLACEMENT_SMEAR: + br->alpha = 1.0f; + br->spacing = 5; + br->hardness = 0.7f; + br->flag &= ~BRUSH_ALPHA_PRESSURE; + br->flag &= ~BRUSH_SPACE_ATTEN; + br->curve_preset = BRUSH_CURVE_SMOOTHER; + break; default: break; } @@ -1898,6 +1906,7 @@ void BKE_brush_sculpt_reset(Brush *br) case SCULPT_TOOL_MASK: case SCULPT_TOOL_DRAW_FACE_SETS: case SCULPT_TOOL_DISPLACEMENT_ERASER: + case SCULPT_TOOL_DISPLACEMENT_SMEAR: br->add_col[0] = 0.75f; br->add_col[1] = 0.75f; br->add_col[2] = 0.75f; diff --git a/source/blender/blenloader/intern/versioning_defaults.c b/source/blender/blenloader/intern/versioning_defaults.c index 2d75b046366..198f65b9794 100644 --- a/source/blender/blenloader/intern/versioning_defaults.c +++ b/source/blender/blenloader/intern/versioning_defaults.c @@ -739,6 +739,14 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template) brush->sculpt_tool = SCULPT_TOOL_DISPLACEMENT_ERASER; } + brush_name = "Multires Displacement Smear"; + brush = BLI_findstring(&bmain->brushes, brush_name, offsetof(ID, name) + 2); + if (!brush) { + brush = BKE_brush_add(bmain, brush_name, OB_MODE_SCULPT); + id_us_min(&brush->id); + brush->sculpt_tool = SCULPT_TOOL_DISPLACEMENT_SMEAR; + } + /* Use the same tool icon color in the brush cursor */ for (brush = bmain->brushes.first; brush; brush = brush->id.next) { if (brush->ob_mode & OB_MODE_SCULPT) { diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index 80a32682325..26db2673335 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -1227,6 +1227,7 @@ static bool sculpt_tool_is_proxy_used(const char sculpt_tool) SCULPT_TOOL_SMOOTH, SCULPT_TOOL_LAYER, SCULPT_TOOL_POSE, + SCULPT_TOOL_DISPLACEMENT_SMEAR, SCULPT_TOOL_BOUNDARY, SCULPT_TOOL_CLOTH, SCULPT_TOOL_PAINT, @@ -2362,6 +2363,7 @@ static float brush_strength(const Sculpt *sd, final_pressure = pressure * pressure; return final_pressure * overlap * feather; case SCULPT_TOOL_SMEAR: + case SCULPT_TOOL_DISPLACEMENT_SMEAR: return alpha * pressure * overlap * feather; case SCULPT_TOOL_CLAY_STRIPS: /* Clay Strips needs less strength to compensate the curve. */ @@ -3103,6 +3105,147 @@ static void do_displacement_eraser_brush(Sculpt *sd, Object *ob, PBVHNode **node /** \} */ +/** \name Sculpt Multires Displacement Smear Brush + * \{ */ + +static void do_displacement_smear_brush_task_cb_ex(void *__restrict userdata, + const int n, + const TaskParallelTLS *__restrict tls) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + const Brush *brush = data->brush; + const float bstrength = clamp_f(ss->cache->bstrength, 0.0f, 1.0f); + + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( + ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); + + PBVHVertexIter vd; + BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) + { + if (!sculpt_brush_test_sq_fn(&test, vd.co)) { + continue; + } + const float fade = bstrength * SCULPT_brush_strength_factor(ss, + brush, + vd.co, + sqrtf(test.dist), + vd.no, + vd.fno, + vd.mask ? *vd.mask : 0.0f, + vd.index, + thread_id); + + float current_disp[3]; + float current_disp_norm[3]; + float interp_limit_surface_disp[3]; + + copy_v3_v3(interp_limit_surface_disp, ss->cache->prev_displacement[vd.index]); + + switch (brush->smear_deform_type) { + case BRUSH_SMEAR_DEFORM_DRAG: + sub_v3_v3v3(current_disp, ss->cache->location, ss->cache->last_location); + break; + case BRUSH_SMEAR_DEFORM_PINCH: + sub_v3_v3v3(current_disp, ss->cache->location, vd.co); + break; + case BRUSH_SMEAR_DEFORM_EXPAND: + sub_v3_v3v3(current_disp, vd.co, ss->cache->location); + break; + } + + normalize_v3_v3(current_disp_norm, current_disp); + mul_v3_v3fl(current_disp, current_disp_norm, ss->cache->bstrength); + + float weights_accum = 1.0f; + + SculptVertexNeighborIter ni; + SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) { + float vertex_disp[3]; + float vertex_disp_norm[3]; + float neighbor_limit_co[3]; + SCULPT_vertex_limit_surface_get(ss, ni.index, neighbor_limit_co); + sub_v3_v3v3(vertex_disp, + ss->cache->limit_surface_co[ni.index], + ss->cache->limit_surface_co[vd.index]); + const float *neighbor_limit_surface_disp = ss->cache->prev_displacement[ni.index]; + normalize_v3_v3(vertex_disp_norm, vertex_disp); + if (dot_v3v3(current_disp_norm, vertex_disp_norm) < 0.0f) { + const float disp_interp = clamp_f( + -dot_v3v3(current_disp_norm, vertex_disp_norm), 0.0f, 1.0f); + madd_v3_v3fl(interp_limit_surface_disp, neighbor_limit_surface_disp, disp_interp); + weights_accum += disp_interp; + } + } + SCULPT_VERTEX_NEIGHBORS_ITER_END(ni); + + mul_v3_fl(interp_limit_surface_disp, 1.0f / weights_accum); + + float new_co[3]; + add_v3_v3v3(new_co, ss->cache->limit_surface_co[vd.index], interp_limit_surface_disp); + interp_v3_v3v3(vd.co, vd.co, new_co, fade); + + if (vd.mvert) { + vd.mvert->flag |= ME_VERT_PBVH_UPDATE; + } + } + BKE_pbvh_vertex_iter_end; +} + +static void do_displacement_smear_store_prev_disp_task_cb_ex( + void *__restrict userdata, const int n, const TaskParallelTLS *__restrict UNUSED(tls)) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + + PBVHVertexIter vd; + BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) + { + sub_v3_v3v3(ss->cache->prev_displacement[vd.index], + SCULPT_vertex_co_get(ss, vd.index), + ss->cache->limit_surface_co[vd.index]); + } + BKE_pbvh_vertex_iter_end; +} + +static void do_displacement_smear_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) +{ + Brush *brush = BKE_paint_brush(&sd->paint); + SculptSession *ss = ob->sculpt; + + BKE_curvemapping_init(brush->curve); + + const int totvert = SCULPT_vertex_count_get(ss); + if (!ss->cache->prev_displacement) { + ss->cache->prev_displacement = MEM_malloc_arrayN( + totvert, sizeof(float[3]), "prev displacement"); + ss->cache->limit_surface_co = MEM_malloc_arrayN(totvert, sizeof(float[3]), "limit surface co"); + for (int i = 0; i < totvert; i++) { + SCULPT_vertex_limit_surface_get(ss, i, ss->cache->limit_surface_co[i]); + sub_v3_v3v3(ss->cache->prev_displacement[i], + SCULPT_vertex_co_get(ss, i), + ss->cache->limit_surface_co[i]); + } + } + /* Threaded loop over nodes. */ + SculptThreadedTaskData data = { + .sd = sd, + .ob = ob, + .brush = brush, + .nodes = nodes, + }; + + TaskParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, true, totnode); + BLI_task_parallel_range( + 0, totnode, &data, do_displacement_smear_store_prev_disp_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_displacement_smear_brush_task_cb_ex, &settings); +} + +/** \} */ + static void do_draw_brush_task_cb_ex(void *__restrict userdata, const int n, const TaskParallelTLS *__restrict tls) @@ -5927,6 +6070,9 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe case SCULPT_TOOL_DISPLACEMENT_ERASER: do_displacement_eraser_brush(sd, ob, nodes, totnode); break; + case SCULPT_TOOL_DISPLACEMENT_SMEAR: + do_displacement_smear_brush(sd, ob, nodes, totnode); + break; case SCULPT_TOOL_PAINT: SCULPT_do_paint_brush(sd, ob, nodes, totnode); break; @@ -6490,6 +6636,8 @@ static const char *sculpt_tool_name(Sculpt *sd) return "Draw Face Sets"; case SCULPT_TOOL_DISPLACEMENT_ERASER: return "Multires Displacement Eraser"; + case SCULPT_TOOL_DISPLACEMENT_SMEAR: + return "Multires Displacement Smear"; case SCULPT_TOOL_PAINT: return "Paint Brush"; case SCULPT_TOOL_SMEAR: @@ -6510,6 +6658,8 @@ void SCULPT_cache_free(StrokeCache *cache) MEM_SAFE_FREE(cache->layer_displacement_factor); MEM_SAFE_FREE(cache->prev_colors); MEM_SAFE_FREE(cache->detail_directions); + MEM_SAFE_FREE(cache->prev_displacement); + MEM_SAFE_FREE(cache->limit_surface_co); if (cache->pose_ik_chain) { SCULPT_pose_ik_chain_free(cache->pose_ik_chain); @@ -6681,6 +6831,7 @@ static void sculpt_update_cache_invariants( SCULPT_TOOL_MASK, SCULPT_TOOL_SMOOTH, SCULPT_TOOL_SIMPLIFY, + SCULPT_TOOL_DISPLACEMENT_SMEAR, SCULPT_TOOL_DISPLACEMENT_ERASER) && (sd->gravity_factor > 0.0f)); /* Get gravity vector in world space. */ diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h index 853b221e92a..d1e17c7e59b 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.h +++ b/source/blender/editors/sculpt_paint/sculpt_intern.h @@ -926,6 +926,10 @@ typedef struct StrokeCache { float (*prev_colors)[4]; + /* Multires Displacement Smear. */ + float (*prev_displacement)[3]; + float (*limit_surface_co)[3]; + /* The rest is temporary storage that isn't saved as a property */ bool first_time; /* Beginning of stroke may do some things special */ diff --git a/source/blender/makesdna/DNA_brush_enums.h b/source/blender/makesdna/DNA_brush_enums.h index 96e870cff8e..f12934c9104 100644 --- a/source/blender/makesdna/DNA_brush_enums.h +++ b/source/blender/makesdna/DNA_brush_enums.h @@ -457,6 +457,7 @@ typedef enum eBrushSculptTool { SCULPT_TOOL_SMEAR = 29, SCULPT_TOOL_BOUNDARY = 30, SCULPT_TOOL_DISPLACEMENT_ERASER = 31, + SCULPT_TOOL_DISPLACEMENT_SMEAR = 32, } eBrushSculptTool; /* Brush.uv_sculpt_tool */ diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h index 4b020019062..1709ea5dc63 100644 --- a/source/blender/makesdna/DNA_brush_types.h +++ b/source/blender/makesdna/DNA_brush_types.h @@ -373,7 +373,7 @@ typedef struct Brush { typedef struct tPaletteColorHSV { float rgb[3]; float value; - float h; + float h; float s; float v; } tPaletteColorHSV; diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c index 08c655d493c..a361feba439 100644 --- a/source/blender/makesrna/intern/rna_brush.c +++ b/source/blender/makesrna/intern/rna_brush.c @@ -134,6 +134,7 @@ const EnumPropertyItem rna_enum_brush_sculpt_tool_items[] = { {SCULPT_TOOL_SIMPLIFY, "SIMPLIFY", ICON_BRUSH_DATA, "Simplify", ""}, {SCULPT_TOOL_MASK, "MASK", ICON_BRUSH_MASK, "Mask", ""}, {SCULPT_TOOL_DISPLACEMENT_ERASER, "DISPLACEMENT_ERASER", ICON_BRUSH_SCULPT_DRAW, "Multires Displacement Eraser", ""}, + {SCULPT_TOOL_DISPLACEMENT_SMEAR, "DISPLACEMENT_SMEAR", ICON_BRUSH_SCULPT_DRAW, "Multires Displacement Smear", ""}, {SCULPT_TOOL_PAINT, "PAINT", ICON_BRUSH_SCULPT_DRAW, "Paint", ""}, {SCULPT_TOOL_SMEAR, "SMEAR", ICON_BRUSH_SCULPT_DRAW, "Smear", ""}, {SCULPT_TOOL_DRAW_FACE_SETS, "DRAW_FACE_SETS", ICON_BRUSH_MASK, "Draw Face Sets", ""}, -- cgit v1.2.3 From a7628ec22abca8d1aaada75a8227638947168a3a Mon Sep 17 00:00:00 2001 From: Dalai Felinto Date: Wed, 16 Dec 2020 16:59:30 +0100 Subject: Geometry Nodes: Poisson disk point distribution node/method This patch does two things: * Introduce a Seed to the random distribution method * Bring in a new distribution method for the point scattering node Patch Review: https://developer.blender.org/D9787 Note: This commit doesn't not handle doversion. Which means that users need to manually update their files that were using the Point Distribute node and reconnect inputs to the "Maximum Density" socket. Original patch by Sebastian Parborg, with changes to not rely on the cy libraries and overall cleanup. Patch review by Jacques Lucke, besides help with the new "heap" system that was required for this algorithm. Based on Cem Yuksel. 2015. Sample Elimination for Generating Poisson Disk Sample. Sets. Computer Graphics Forum 34, 2 (May 2015), 25-32 http://www.cemyuksel.com/research/sampleelimination/ --- source/blender/blenlib/BLI_kdopbvh.h | 1 + source/blender/blenlib/intern/BLI_kdopbvh.c | 19 ++ source/blender/editors/space_node/drawnode.c | 10 + source/blender/makesdna/DNA_node_types.h | 5 + source/blender/makesrna/intern/rna_nodetree.c | 26 ++ source/blender/nodes/CMakeLists.txt | 1 + source/blender/nodes/NOD_static_types.h | 2 +- .../blender/nodes/geometry/node_geometry_util.hh | 8 +- .../geometry/nodes/node_geo_point_distribute.cc | 178 ++++++++++++- .../node_geo_point_distribute_poisson_disk.cc | 280 +++++++++++++++++++++ 10 files changed, 521 insertions(+), 9 deletions(-) create mode 100644 source/blender/nodes/geometry/nodes/node_geo_point_distribute_poisson_disk.cc diff --git a/source/blender/blenlib/BLI_kdopbvh.h b/source/blender/blenlib/BLI_kdopbvh.h index c34b71a60f9..5e0ea4f2a99 100644 --- a/source/blender/blenlib/BLI_kdopbvh.h +++ b/source/blender/blenlib/BLI_kdopbvh.h @@ -178,6 +178,7 @@ int *BLI_bvhtree_intersect_plane(BVHTree *tree, float plane[4], uint *r_intersec int BLI_bvhtree_get_len(const BVHTree *tree); int BLI_bvhtree_get_tree_type(const BVHTree *tree); float BLI_bvhtree_get_epsilon(const BVHTree *tree); +void BLI_bvhtree_get_bounding_box(BVHTree *tree, float r_bb_min[3], float r_bb_max[3]); /* find nearest node to the given coordinates * (if nearest is given it will only search nodes where diff --git a/source/blender/blenlib/intern/BLI_kdopbvh.c b/source/blender/blenlib/intern/BLI_kdopbvh.c index f126c5a977b..0f90ad3a490 100644 --- a/source/blender/blenlib/intern/BLI_kdopbvh.c +++ b/source/blender/blenlib/intern/BLI_kdopbvh.c @@ -1076,6 +1076,25 @@ float BLI_bvhtree_get_epsilon(const BVHTree *tree) return tree->epsilon; } +/** + * This function returns the bounding box of the BVH tree. + */ +void BLI_bvhtree_get_bounding_box(BVHTree *tree, float r_bb_min[3], float r_bb_max[3]) +{ + BVHNode *root = tree->nodes[tree->totleaf]; + if (root != NULL) { + const float bb_min[3] = {root->bv[0], root->bv[2], root->bv[4]}; + const float bb_max[3] = {root->bv[1], root->bv[3], root->bv[5]}; + copy_v3_v3(r_bb_min, bb_min); + copy_v3_v3(r_bb_max, bb_max); + } + else { + BLI_assert(false); + zero_v3(r_bb_min); + zero_v3(r_bb_max); + } +} + /** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index 421d645d7bd..2857c08cad6 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -3208,6 +3208,13 @@ static void node_geometry_buts_attribute_mix(uiLayout *layout, uiItemR(col, ptr, "input_type_b", DEFAULT_FLAGS, IFACE_("B"), ICON_NONE); } +static void node_geometry_buts_attribute_point_distribute(uiLayout *layout, + bContext *UNUSED(C), + PointerRNA *ptr) +{ + uiItemR(layout, ptr, "distribute_method", DEFAULT_FLAGS, "", ICON_NONE); +} + static void node_geometry_set_butfunc(bNodeType *ntype) { switch (ntype->type) { @@ -3235,6 +3242,9 @@ static void node_geometry_set_butfunc(bNodeType *ntype) case GEO_NODE_ATTRIBUTE_MIX: ntype->draw_buttons = node_geometry_buts_attribute_mix; break; + case GEO_NODE_POINT_DISTRIBUTE: + ntype->draw_buttons = node_geometry_buts_attribute_point_distribute; + break; } } diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index 9cf64743843..34a5372892c 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -1501,6 +1501,11 @@ typedef enum GeometryNodeAttributeInputMode { GEO_NODE_ATTRIBUTE_INPUT_COLOR = 3, } GeometryNodeAttributeInputMode; +typedef enum GeometryNodePointDistributeMethod { + GEO_NODE_POINT_DISTRIBUTE_RANDOM = 0, + GEO_NODE_POINT_DISTRIBUTE_POISSON = 1, +} GeometryNodePointDistributeMethod; + #ifdef __cplusplus } #endif diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 34f4d287d6e..1731a42583b 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -452,6 +452,20 @@ static const EnumPropertyItem rna_node_geometry_attribute_input_type_items[] = { {0, NULL, 0, NULL, NULL}, }; +static const EnumPropertyItem rna_node_geometry_point_distribute_method_items[] = { + {GEO_NODE_POINT_DISTRIBUTE_RANDOM, + "RANDOM", + 0, + "Random", + "Distribute points randomly on the surface"}, + {GEO_NODE_POINT_DISTRIBUTE_POISSON, + "POISSON", + 0, + "Poisson Disk", + "Project points on the surface evenly with a Poisson disk distribution"}, + {0, NULL, 0, NULL, NULL}, +}; + #endif #ifdef RNA_RUNTIME @@ -8481,6 +8495,18 @@ static void def_geo_attribute_mix(StructRNA *srna) RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); } +static void def_geo_point_distribute(StructRNA *srna) +{ + PropertyRNA *prop; + + prop = RNA_def_property(srna, "distribute_method", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "custom1"); + RNA_def_property_enum_items(prop, rna_node_geometry_point_distribute_method_items); + RNA_def_property_enum_default(prop, GEO_NODE_POINT_DISTRIBUTE_RANDOM); + RNA_def_property_ui_text(prop, "Distribution Method", "Method to use for scattering points"); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); +} + /* -------------------------------------------------------------------------- */ static void rna_def_shader_node(BlenderRNA *brna) diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt index 779680a5da7..46536903d55 100644 --- a/source/blender/nodes/CMakeLists.txt +++ b/source/blender/nodes/CMakeLists.txt @@ -148,6 +148,7 @@ set(SRC geometry/nodes/node_geo_attribute_mix.cc geometry/nodes/node_geo_object_info.cc geometry/nodes/node_geo_point_distribute.cc + geometry/nodes/node_geo_point_distribute_poisson_disk.cc geometry/nodes/node_geo_point_instance.cc geometry/nodes/node_geo_subdivision_surface.cc geometry/nodes/node_geo_transform.cc diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h index 681286ae5ab..68efb0806fd 100644 --- a/source/blender/nodes/NOD_static_types.h +++ b/source/blender/nodes/NOD_static_types.h @@ -271,7 +271,7 @@ DefNode(GeometryNode, GEO_NODE_EDGE_SPLIT, 0, "EDGE_SPLIT", EdgeSplit, "Edge Spl DefNode(GeometryNode, GEO_NODE_TRANSFORM, 0, "TRANSFORM", Transform, "Transform", "") DefNode(GeometryNode, GEO_NODE_SUBDIVISION_SURFACE, 0, "SUBDIVISION_SURFACE", SubdivisionSurface, "Subdivision Surface", "") DefNode(GeometryNode, GEO_NODE_BOOLEAN, def_geo_boolean, "BOOLEAN", Boolean, "Boolean", "") -DefNode(GeometryNode, GEO_NODE_POINT_DISTRIBUTE, 0, "POINT_DISTRIBUTE", PointDistribute, "Point Distribute", "") +DefNode(GeometryNode, GEO_NODE_POINT_DISTRIBUTE, def_geo_point_distribute, "POINT_DISTRIBUTE", PointDistribute, "Point Distribute", "") DefNode(GeometryNode, GEO_NODE_POINT_INSTANCE, def_geo_point_instance, "POINT_INSTANCE", PointInstance, "Point Instance", "") DefNode(GeometryNode, GEO_NODE_OBJECT_INFO, 0, "OBJECT_INFO", ObjectInfo, "Object Info", "") DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_RANDOMIZE, def_geo_attribute_randomize, "ATTRIBUTE_RANDOMIZE", AttributeRandomize, "Attribute Randomize", "") diff --git a/source/blender/nodes/geometry/node_geometry_util.hh b/source/blender/nodes/geometry/node_geometry_util.hh index ec389961615..c97463cdc22 100644 --- a/source/blender/nodes/geometry/node_geometry_util.hh +++ b/source/blender/nodes/geometry/node_geometry_util.hh @@ -42,4 +42,10 @@ namespace blender::nodes { void update_attribute_input_socket_availabilities(bNode &node, const StringRef name, const GeometryNodeAttributeInputMode mode); -} + +void poisson_disk_point_elimination(Vector const *input_points, + Vector *output_points, + float maximum_distance, + float3 boundbox); + +} // namespace blender::nodes diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc b/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc index 2f5f7e264bc..8be9636e14d 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc @@ -24,6 +24,7 @@ #include "DNA_meshdata_types.h" #include "DNA_pointcloud_types.h" +#include "BKE_bvhutils.h" #include "BKE_deform.h" #include "BKE_mesh.h" #include "BKE_mesh_runtime.h" @@ -33,8 +34,10 @@ static bNodeSocketTemplate geo_node_point_distribute_in[] = { {SOCK_GEOMETRY, N_("Geometry")}, - {SOCK_FLOAT, N_("Density"), 10.0f, 0.0f, 0.0f, 0.0f, 0.0f, 100000.0f, PROP_NONE}, + {SOCK_FLOAT, N_("Minimum Distance"), 0.1f, 0.0f, 0.0f, 0.0f, 0.0f, 100000.0f, PROP_NONE}, + {SOCK_FLOAT, N_("Maximum Density"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 100000.0f, PROP_NONE}, {SOCK_STRING, N_("Density Attribute")}, + {SOCK_INT, N_("Seed"), 0, 0, 0, 0, -10000, 10000}, {-1, ""}, }; @@ -43,11 +46,19 @@ static bNodeSocketTemplate geo_node_point_distribute_out[] = { {-1, ""}, }; +static void node_point_distribute_update(bNodeTree *UNUSED(ntree), bNode *node) +{ + bNodeSocket *sock_min_dist = (bNodeSocket *)BLI_findlink(&node->inputs, 1); + + nodeSetSocketAvailability(sock_min_dist, ELEM(node->custom1, GEO_NODE_POINT_DISTRIBUTE_POISSON)); +} + namespace blender::nodes { -static Vector scatter_points_from_mesh(const Mesh *mesh, - const float density, - const FloatReadAttribute &density_factors) +static Vector random_scatter_points_from_mesh(const Mesh *mesh, + const float density, + const FloatReadAttribute &density_factors, + const int seed) { /* This only updates a cache and can be considered to be logically const. */ const MLoopTri *looptris = BKE_mesh_runtime_looptri_ensure(const_cast(mesh)); @@ -71,7 +82,7 @@ static Vector scatter_points_from_mesh(const Mesh *mesh, 3.0f; const float area = area_tri_v3(v0_pos, v1_pos, v2_pos); - const int looptri_seed = BLI_hash_int(looptri_index); + const int looptri_seed = BLI_hash_int(looptri_index + seed); RandomNumberGenerator looptri_rng(looptri_seed); const float points_amount_fl = area * density * looptri_density_factor; @@ -90,17 +101,158 @@ static Vector scatter_points_from_mesh(const Mesh *mesh, return points; } +struct RayCastAll_Data { + void *bvhdata; + + BVHTree_RayCastCallback raycast_callback; + + const Mesh *mesh; + float base_weight; + FloatReadAttribute *density_factors; + Vector *projected_points; + float cur_point_weight; +}; + +static void project_2d_bvh_callback(void *userdata, + int index, + const BVHTreeRay *ray, + BVHTreeRayHit *hit) +{ + struct RayCastAll_Data *data = (RayCastAll_Data *)userdata; + data->raycast_callback(data->bvhdata, index, ray, hit); + if (hit->index != -1) { + /* This only updates a cache and can be considered to be logically const. */ + const MLoopTri *looptris = BKE_mesh_runtime_looptri_ensure(const_cast(data->mesh)); + const MVert *mvert = data->mesh->mvert; + + const MLoopTri &looptri = looptris[index]; + const FloatReadAttribute &density_factors = data->density_factors[0]; + + const int v0_index = data->mesh->mloop[looptri.tri[0]].v; + const int v1_index = data->mesh->mloop[looptri.tri[1]].v; + const int v2_index = data->mesh->mloop[looptri.tri[2]].v; + + const float v0_density_factor = std::max(0.0f, density_factors[v0_index]); + const float v1_density_factor = std::max(0.0f, density_factors[v1_index]); + const float v2_density_factor = std::max(0.0f, density_factors[v2_index]); + + /* Calculate barycentric weights for hit point. */ + float3 weights; + interp_weights_tri_v3( + weights, mvert[v0_index].co, mvert[v1_index].co, mvert[v2_index].co, hit->co); + + float point_weight = weights[0] * v0_density_factor + weights[1] * v1_density_factor + + weights[2] * v2_density_factor; + + point_weight *= data->base_weight; + + if (point_weight >= FLT_EPSILON && data->cur_point_weight <= point_weight) { + data->projected_points->append(hit->co); + } + } +} + +static Vector poisson_scatter_points_from_mesh(const Mesh *mesh, + const float density, + const float minimum_distance, + const FloatReadAttribute &density_factors, + const int seed) +{ + Vector points; + + if (minimum_distance <= FLT_EPSILON || density <= FLT_EPSILON) { + return points; + } + + /* Scatter points randomly on the mesh with higher density (5-7) times higher than desired for + * good quality possion disk distributions. */ + int quality = 5; + const int output_points_target = 1000; + points.resize(output_points_target * quality); + + const float required_area = output_points_target * + (2.0f * sqrtf(3.0f) * minimum_distance * minimum_distance); + const float point_scale_multiplier = sqrtf(required_area); + + { + const int rnd_seed = BLI_hash_int(seed); + RandomNumberGenerator point_rng(rnd_seed); + + for (int i = 0; i < points.size(); i++) { + points[i].x = point_rng.get_float() * point_scale_multiplier; + points[i].y = point_rng.get_float() * point_scale_multiplier; + points[i].z = 0.0f; + } + } + + /* Eliminate the scattered points until we get a possion distribution. */ + Vector output_points(output_points_target); + + const float3 bounds_max = float3(point_scale_multiplier, point_scale_multiplier, 0); + poisson_disk_point_elimination(&points, &output_points, 2.0f * minimum_distance, bounds_max); + Vector final_points; + final_points.reserve(output_points_target); + + /* Check if we have any points we should remove from the final possion distribition. */ + BVHTreeFromMesh treedata; + BKE_bvhtree_from_mesh_get(&treedata, const_cast(mesh), BVHTREE_FROM_LOOPTRI, 2); + + float3 bb_min, bb_max; + BLI_bvhtree_get_bounding_box(treedata.tree, bb_min, bb_max); + + struct RayCastAll_Data data; + data.bvhdata = &treedata; + data.raycast_callback = treedata.raycast_callback; + data.mesh = mesh; + data.projected_points = &final_points; + data.density_factors = const_cast(&density_factors); + data.base_weight = std::min( + 1.0f, density / (output_points.size() / (point_scale_multiplier * point_scale_multiplier))); + + const float max_dist = bb_max[2] - bb_min[2] + 2.0f; + const float3 dir = float3(0, 0, -1); + float3 raystart; + raystart.z = bb_max[2] + 1.0f; + + float tile_start_x_coord = bb_min[0]; + int tile_repeat_x = ceilf((bb_max[0] - bb_min[0]) / point_scale_multiplier); + + float tile_start_y_coord = bb_min[1]; + int tile_repeat_y = ceilf((bb_max[1] - bb_min[1]) / point_scale_multiplier); + + for (int x = 0; x < tile_repeat_x; x++) { + float tile_curr_x_coord = x * point_scale_multiplier + tile_start_x_coord; + for (int y = 0; y < tile_repeat_y; y++) { + float tile_curr_y_coord = y * point_scale_multiplier + tile_start_y_coord; + for (int idx = 0; idx < output_points.size(); idx++) { + raystart.x = output_points[idx].x + tile_curr_x_coord; + raystart.y = output_points[idx].y + tile_curr_y_coord; + + data.cur_point_weight = (float)idx / (float)output_points.size(); + + BLI_bvhtree_ray_cast_all( + treedata.tree, raystart, dir, 0.0f, max_dist, project_2d_bvh_callback, &data); + } + } + } + + return final_points; +} + static void geo_node_point_distribute_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input("Geometry"); GeometrySet geometry_set_out; + GeometryNodePointDistributeMethod distribute_method = + static_cast(params.node().custom1); + if (!geometry_set.has_mesh()) { params.set_output("Geometry", std::move(geometry_set_out)); return; } - const float density = params.extract_input("Density"); + const float density = params.extract_input("Maximum Density"); const std::string density_attribute = params.extract_input("Density Attribute"); if (density <= 0.0f) { @@ -113,8 +265,19 @@ static void geo_node_point_distribute_exec(GeoNodeExecParams params) const FloatReadAttribute density_factors = mesh_component.attribute_get_for_read( density_attribute, ATTR_DOMAIN_POINT, 1.0f); + const int seed = params.get_input("Seed"); - Vector points = scatter_points_from_mesh(mesh_in, density, density_factors); + Vector points; + + switch (distribute_method) { + case GEO_NODE_POINT_DISTRIBUTE_RANDOM: + points = random_scatter_points_from_mesh(mesh_in, density, density_factors, seed); + break; + case GEO_NODE_POINT_DISTRIBUTE_POISSON: + const float min_dist = params.extract_input("Minimum Distance"); + points = poisson_scatter_points_from_mesh(mesh_in, density, min_dist, density_factors, seed); + break; + } PointCloud *pointcloud = BKE_pointcloud_new_nomain(points.size()); memcpy(pointcloud->co, points.data(), sizeof(float3) * points.size()); @@ -135,6 +298,7 @@ void register_node_type_geo_point_distribute() geo_node_type_base( &ntype, GEO_NODE_POINT_DISTRIBUTE, "Point Distribute", NODE_CLASS_GEOMETRY, 0); node_type_socket_templates(&ntype, geo_node_point_distribute_in, geo_node_point_distribute_out); + node_type_update(&ntype, node_point_distribute_update); ntype.geometry_node_execute = blender::nodes::geo_node_point_distribute_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_distribute_poisson_disk.cc b/source/blender/nodes/geometry/nodes/node_geo_point_distribute_poisson_disk.cc new file mode 100644 index 00000000000..5dfdfce0e68 --- /dev/null +++ b/source/blender/nodes/geometry/nodes/node_geo_point_distribute_poisson_disk.cc @@ -0,0 +1,280 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/* + * Based on Cem Yuksel. 2015. Sample Elimination for Generating Poisson Disk Sample + * ! Sets. Computer Graphics Forum 34, 2 (May 2015), 25-32. + * ! http://www.cemyuksel.com/research/sampleelimination/ + * Copyright (c) 2016, Cem Yuksel + * All rights reserved. + */ + +#include "BLI_inplace_priority_queue.hh" +#include "BLI_kdtree.h" + +#include "node_geometry_util.hh" + +#include + +namespace blender::nodes { + +static void tile_point(Vector *tiled_points, + Vector *indices, + const float maximum_distance, + const float3 boundbox, + float3 const &point, + size_t index, + int dimension = 0) +{ + for (int dimension_iter = dimension; dimension_iter < 3; dimension_iter++) { + if (boundbox[dimension_iter] - point[dimension_iter] < maximum_distance) { + float3 point_tiled = point; + point_tiled[dimension_iter] -= boundbox[dimension_iter]; + + tiled_points->append(point_tiled); + indices->append(index); + + tile_point(tiled_points, + indices, + maximum_distance, + boundbox, + point_tiled, + index, + dimension_iter + 1); + } + + if (point[dimension_iter] < maximum_distance) { + float3 point_tiled = point; + point_tiled[dimension_iter] += boundbox[dimension_iter]; + + tiled_points->append(point_tiled); + indices->append(index); + + tile_point(tiled_points, + indices, + maximum_distance, + boundbox, + point_tiled, + index, + dimension_iter + 1); + } + } +} + +/** + * Returns the weight the point gets based on the distance to another point. + */ +static float point_weight_influence_get(const float maximum_distance, + const float minimum_distance, + float distance) +{ + const float alpha = 8.0f; + + if (distance < minimum_distance) { + distance = minimum_distance; + } + + return std::pow(1.0f - distance / maximum_distance, alpha); +} + +/** + * Weight each point based on their proximity to its neighbors + * + * For each index in the weight array add a weight based on the proximity the + * corresponding point has with its neighboors. + **/ +static void points_distance_weight_calculate(Vector *weights, + const size_t point_id, + const float3 *input_points, + const void *kd_tree, + const float minimum_distance, + const float maximum_distance, + InplacePriorityQueue *heap) +{ + KDTreeNearest_3d *nearest_point = nullptr; + int neighbors = BLI_kdtree_3d_range_search( + (KDTree_3d *)kd_tree, input_points[point_id], &nearest_point, maximum_distance); + + for (int i = 0; i < neighbors; i++) { + size_t neighbor_point_id = nearest_point[i].index; + + if (neighbor_point_id >= weights->size()) { + continue; + } + + /* The point should not influence itself. */ + if (neighbor_point_id == point_id) { + continue; + } + + const float weight_influence = point_weight_influence_get( + maximum_distance, minimum_distance, nearest_point[i].dist); + + /* In the first pass we just the weights. */ + if (heap == nullptr) { + (*weights)[point_id] += weight_influence; + } + /* When we run again we need to update the weights and the heap. */ + else { + (*weights)[neighbor_point_id] -= weight_influence; + heap->priority_decreased(neighbor_point_id); + } + } + + if (nearest_point) { + MEM_freeN(nearest_point); + } +} + +/** + * Returns the minimum radius fraction used by the default weight function. + */ +static float weight_limit_fraction_get(const size_t input_size, const size_t output_size) +{ + const float beta = 0.65f; + const float gamma = 1.5f; + float ratio = float(output_size) / float(input_size); + return (1.0f - std::pow(ratio, gamma)) * beta; +} + +/** + * Tile the input points. + */ +static void points_tiling(const float3 *input_points, + const size_t input_size, + void **kd_tree, + const float maximum_distance, + const float3 boundbox) + +{ + Vector tiled_points(input_points, input_points + input_size); + Vector indices(input_size); + + for (size_t i = 0; i < input_size; i++) { + indices[i] = i; + } + + /* Tile the tree based on the boundbox. */ + for (size_t i = 0; i < input_size; i++) { + tile_point(&tiled_points, &indices, maximum_distance, boundbox, input_points[i], i); + } + + /* Build a new tree with the new indices and tiled points. */ + *kd_tree = BLI_kdtree_3d_new(tiled_points.size()); + for (size_t i = 0; i < tiled_points.size(); i++) { + BLI_kdtree_3d_insert(*(KDTree_3d **)kd_tree, indices[i], tiled_points[i]); + } + BLI_kdtree_3d_balance(*(KDTree_3d **)kd_tree); +} + +static void weighted_sample_elimination(const float3 *input_points, + const size_t input_size, + float3 *output_points, + const size_t output_size, + const float maximum_distance, + const float3 boundbox, + const bool do_copy_eliminated) +{ + const float minimum_distance = maximum_distance * + weight_limit_fraction_get(input_size, output_size); + + void *kd_tree = nullptr; + points_tiling(input_points, input_size, &kd_tree, maximum_distance, boundbox); + + /* Assign weights to each sample. */ + Vector weights(input_size, 0.0f); + for (size_t point_id = 0; point_id < weights.size(); point_id++) { + points_distance_weight_calculate( + &weights, point_id, input_points, kd_tree, minimum_distance, maximum_distance, nullptr); + } + + /* Remove the points based on their weight. */ + InplacePriorityQueue heap(weights); + + size_t sample_size = input_size; + while (sample_size > output_size) { + /* For each sample around it, remove its weight contribution and update the heap. */ + size_t point_id = heap.pop_index(); + points_distance_weight_calculate( + &weights, point_id, input_points, kd_tree, minimum_distance, maximum_distance, &heap); + sample_size--; + } + + /* Copy the samples to the output array. */ + size_t target_size = do_copy_eliminated ? input_size : output_size; + for (size_t i = 0; i < target_size; i++) { + size_t index = heap.all_indices()[i]; + output_points[i] = input_points[index]; + } + + /* Cleanup. */ + BLI_kdtree_3d_free((KDTree_3d *)kd_tree); +} + +static void progressive_sampling_reorder(Vector *output_points, + float maximum_density, + float3 boundbox) +{ + /* Re-order the points for progressive sampling. */ + Vector temporary_points(output_points->size()); + float3 *source_points = output_points->data(); + float3 *dest_points = temporary_points.data(); + size_t source_size = output_points->size(); + size_t dest_size = 0; + + while (source_size >= 3) { + dest_size = source_size * 0.5f; + + /* Changes the weight function radius using half of the number of samples. + * It is used for progressive sampling. */ + maximum_density *= std::sqrt(2.0f); + weighted_sample_elimination( + source_points, source_size, dest_points, dest_size, maximum_density, boundbox, true); + + if (dest_points != output_points->data()) { + mempcpy((*output_points)[dest_size], + dest_points[dest_size], + (source_size - dest_size) * sizeof(float3)); + } + + /* Swap the arrays around. */ + float3 *points_iter = source_points; + source_points = dest_points; + dest_points = points_iter; + source_size = dest_size; + } + if (source_points != output_points->data()) { + memcpy(output_points->data(), source_points, dest_size * sizeof(float3)); + } +} + +void poisson_disk_point_elimination(Vector const *input_points, + Vector *output_points, + float maximum_density, + float3 boundbox) +{ + weighted_sample_elimination(input_points->data(), + input_points->size(), + output_points->data(), + output_points->size(), + maximum_density, + boundbox, + false); + + progressive_sampling_reorder(output_points, maximum_density, boundbox); +} + +} // namespace blender::nodes -- cgit v1.2.3 From ebd8a703ccb6b8884b26e78771a9fec8ba919f9a Mon Sep 17 00:00:00 2001 From: Philipp Oeser Date: Wed, 16 Dec 2020 16:41:47 +0100 Subject: Fix T83851: Python: operator macros cause a crash Caused by rB7447eb7e7430. This is just a copy-paste error [previous LISTBASE_FOREACH substitution of marco loop in that file has a different starting point which is not appropriate here] Maniphest Tasks: T83851 Differential Revision: https://developer.blender.org/D9872 --- source/blender/windowmanager/intern/wm_event_system.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 61624ad9d7c..c1ae307eb55 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -1204,7 +1204,7 @@ static wmOperator *wm_operator_create(wmWindowManager *wm, RNA_STRUCT_END; } else { - LISTBASE_FOREACH (wmOperatorTypeMacro *, macro, &op->opm->type->macro) { + LISTBASE_FOREACH (wmOperatorTypeMacro *, macro, &ot->macro) { wmOperatorType *otm = WM_operatortype_find(macro->idname, 0); wmOperator *opm = wm_operator_create(wm, otm, macro->ptr, NULL); -- cgit v1.2.3 From c06c5d617a8b0e72acdeb60674172d748093bf24 Mon Sep 17 00:00:00 2001 From: Dalai Felinto Date: Wed, 16 Dec 2020 17:48:05 +0100 Subject: Cleanup: Replace mempcpy with memcpy There is no need of using mempcpy here, memcpy is enough. Note: This also fix building in Windows which was broken since a7628ec22a. --- .../nodes/geometry/nodes/node_geo_point_distribute_poisson_disk.cc | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_distribute_poisson_disk.cc b/source/blender/nodes/geometry/nodes/node_geo_point_distribute_poisson_disk.cc index 5dfdfce0e68..47764efa15d 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_point_distribute_poisson_disk.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_point_distribute_poisson_disk.cc @@ -28,6 +28,7 @@ #include "node_geometry_util.hh" #include +#include namespace blender::nodes { @@ -245,9 +246,9 @@ static void progressive_sampling_reorder(Vector *output_points, source_points, source_size, dest_points, dest_size, maximum_density, boundbox, true); if (dest_points != output_points->data()) { - mempcpy((*output_points)[dest_size], - dest_points[dest_size], - (source_size - dest_size) * sizeof(float3)); + memcpy((*output_points)[dest_size], + dest_points[dest_size], + (source_size - dest_size) * sizeof(float3)); } /* Swap the arrays around. */ -- cgit v1.2.3 From c484b54453e6072399dd79daccf237bb4bd73b41 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Wed, 16 Dec 2020 12:33:13 -0600 Subject: Geometry Nodes: Boolean attribute type This adds a boolean attribute and custom data type, to be used in the point separate node. It also adds it as supported data types in the random attribute and attribute fill nodes. There are more clever ways of storing a boolean attribute that make more sense in certain situations-- sets, bitfields, and others, this commit keeps it simple, saving those changes for when there is a proper use case for them. In any case, we will still probably always want the idea of a boolean attribute. Differential Revision: https://developer.blender.org/D9818 --- source/blender/blenkernel/BKE_attribute_access.hh | 2 ++ .../blender/blenkernel/intern/attribute_access.cc | 21 +++++++++++++++++++-- source/blender/blenkernel/intern/customdata.c | 16 ++++++++++++++++ source/blender/makesdna/DNA_customdata_types.h | 8 +++++--- source/blender/makesrna/intern/rna_attribute.c | 1 + source/blender/makesrna/intern/rna_nodetree.c | 4 ++-- source/blender/nodes/NOD_geometry_exec.hh | 2 ++ .../nodes/geometry/nodes/node_geo_attribute_fill.cc | 11 +++++++++++ .../geometry/nodes/node_geo_attribute_randomize.cc | 15 +++++++++++++++ .../nodes/intern/node_tree_multi_function.cc | 4 ++++ 10 files changed, 77 insertions(+), 7 deletions(-) diff --git a/source/blender/blenkernel/BKE_attribute_access.hh b/source/blender/blenkernel/BKE_attribute_access.hh index 564e912551a..eafd86d176b 100644 --- a/source/blender/blenkernel/BKE_attribute_access.hh +++ b/source/blender/blenkernel/BKE_attribute_access.hh @@ -264,9 +264,11 @@ template class TypedWriteAttribute { } }; +using BooleanReadAttribute = TypedReadAttribute; using FloatReadAttribute = TypedReadAttribute; using Float3ReadAttribute = TypedReadAttribute; using Color4fReadAttribute = TypedReadAttribute; +using BooleanWriteAttribute = TypedWriteAttribute; using FloatWriteAttribute = TypedWriteAttribute; using Float3WriteAttribute = TypedWriteAttribute; using Color4fWriteAttribute = TypedWriteAttribute; diff --git a/source/blender/blenkernel/intern/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc index 282e9bc2962..623335f65a1 100644 --- a/source/blender/blenkernel/intern/attribute_access.cc +++ b/source/blender/blenkernel/intern/attribute_access.cc @@ -392,6 +392,8 @@ const blender::fn::CPPType *custom_data_type_to_cpp_type(const CustomDataType ty return &CPPType::get(); case CD_PROP_COLOR: return &CPPType::get(); + case CD_PROP_BOOL: + return &CPPType::get(); default: return nullptr; } @@ -415,6 +417,9 @@ CustomDataType cpp_type_to_custom_data_type(const blender::fn::CPPType &type) if (type.is()) { return CD_PROP_COLOR; } + if (type.is()) { + return CD_PROP_BOOL; + } return static_cast(-1); } @@ -449,6 +454,9 @@ static ReadAttributePtr read_attribute_from_custom_data(const CustomData &custom case CD_PROP_COLOR: return std::make_unique>( domain, Span(static_cast(layer.data), size)); + case CD_PROP_BOOL: + return std::make_unique>( + domain, Span(static_cast(layer.data), size)); } } } @@ -490,6 +498,9 @@ static WriteAttributePtr write_attribute_from_custom_data( case CD_PROP_COLOR: return std::make_unique>( domain, MutableSpan(static_cast(layer.data), size)); + case CD_PROP_BOOL: + return std::make_unique>( + domain, MutableSpan(static_cast(layer.data), size)); } } } @@ -751,6 +762,7 @@ bool PointCloudComponent::attribute_domain_with_type_supported( const AttributeDomain domain, const CustomDataType data_type) const { return domain == ATTR_DOMAIN_POINT && ELEM(data_type, + CD_PROP_BOOL, CD_PROP_FLOAT, CD_PROP_FLOAT2, CD_PROP_FLOAT3, @@ -874,8 +886,13 @@ bool MeshComponent::attribute_domain_with_type_supported(const AttributeDomain d if (!this->attribute_domain_supported(domain)) { return false; } - return ELEM( - data_type, CD_PROP_FLOAT, CD_PROP_FLOAT2, CD_PROP_FLOAT3, CD_PROP_INT32, CD_PROP_COLOR); + return ELEM(data_type, + CD_PROP_BOOL, + CD_PROP_FLOAT, + CD_PROP_FLOAT2, + CD_PROP_FLOAT3, + CD_PROP_INT32, + CD_PROP_COLOR); } int MeshComponent::attribute_domain_size(const AttributeDomain domain) const diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c index fdb3e246382..1e2bc570c65 100644 --- a/source/blender/blenkernel/intern/customdata.c +++ b/source/blender/blenkernel/intern/customdata.c @@ -1837,6 +1837,21 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { layerMultiply_propfloat2, NULL, layerAdd_propfloat2}, + /* 50: CD_PROP_POOL */ + {sizeof(bool), + "bool", + 1, + N_("Boolean"), + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL}, }; static const char *LAYERTYPENAMES[CD_NUMTYPES] = { @@ -1892,6 +1907,7 @@ static const char *LAYERTYPENAMES[CD_NUMTYPES] = { "CDPropCol", "CDPropFloat3", "CDPropFloat2", + "CDPropBoolean", }; const CustomData_MeshMasks CD_MASK_BAREMESH = { diff --git a/source/blender/makesdna/DNA_customdata_types.h b/source/blender/makesdna/DNA_customdata_types.h index ae0bb20e529..832d55ea151 100644 --- a/source/blender/makesdna/DNA_customdata_types.h +++ b/source/blender/makesdna/DNA_customdata_types.h @@ -75,8 +75,7 @@ typedef struct CustomData { * MUST be >= CD_NUMTYPES, but we cant use a define here. * Correct size is ensured in CustomData_update_typemap assert(). */ - int typemap[50]; - char _pad[4]; + int typemap[51]; /** Number of layers, size of layers array. */ int totlayer, maxlayer; /** In editmode, total size of all data layers. */ @@ -156,7 +155,9 @@ typedef enum CustomDataType { CD_PROP_FLOAT3 = 48, CD_PROP_FLOAT2 = 49, - CD_NUMTYPES = 50, + CD_PROP_BOOL = 50, + + CD_NUMTYPES = 51, } CustomDataType; /* Bits for CustomDataMask */ @@ -208,6 +209,7 @@ typedef enum CustomDataType { #define CD_MASK_PROP_COLOR (1ULL << CD_PROP_COLOR) #define CD_MASK_PROP_FLOAT3 (1ULL << CD_PROP_FLOAT3) #define CD_MASK_PROP_FLOAT2 (1ULL << CD_PROP_FLOAT2) +#define CD_MASK_PROP_BOOL (1ULL << CD_PROP_BOOL) /** Multires loop data. */ #define CD_MASK_MULTIRES_GRIDS (CD_MASK_MDISPS | CD_GRID_PAINT_MASK) diff --git a/source/blender/makesrna/intern/rna_attribute.c b/source/blender/makesrna/intern/rna_attribute.c index 95f6340174a..f98ca47d767 100644 --- a/source/blender/makesrna/intern/rna_attribute.c +++ b/source/blender/makesrna/intern/rna_attribute.c @@ -44,6 +44,7 @@ const EnumPropertyItem rna_enum_attribute_type_items[] = { {CD_PROP_COLOR, "FLOAT_COLOR", 0, "Float Color", "RGBA color with floating-point precisions"}, {CD_MLOOPCOL, "BYTE_COLOR", 0, "Byte Color", "RGBA color with 8-bit precision"}, {CD_PROP_STRING, "STRING", 0, "String", "Text string"}, + {CD_PROP_BOOL, "BOOLEAN", 0, "Boolean", "True or false"}, {0, NULL, 0, NULL, NULL}, }; diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 1731a42583b..4cd5b45ce78 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -1890,7 +1890,7 @@ static const EnumPropertyItem *itemf_function_check( static bool attribute_random_type_supported(const EnumPropertyItem *item) { - return ELEM(item->value, CD_PROP_FLOAT, CD_PROP_FLOAT3); + return ELEM(item->value, CD_PROP_FLOAT, CD_PROP_FLOAT3, CD_PROP_BOOL); } static const EnumPropertyItem *rna_GeometryNodeAttributeRandom_type_itemf( bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free) @@ -1912,7 +1912,7 @@ static const EnumPropertyItem *rna_GeometryNodeAttributeRandom_domain_itemf( static bool attribute_fill_type_supported(const EnumPropertyItem *item) { - return ELEM(item->value, CD_PROP_FLOAT, CD_PROP_FLOAT3, CD_PROP_COLOR); + return ELEM(item->value, CD_PROP_FLOAT, CD_PROP_FLOAT3, CD_PROP_COLOR, CD_PROP_BOOL); } static const EnumPropertyItem *rna_GeometryNodeAttributeFill_type_itemf(bContext *UNUSED(C), PointerRNA *UNUSED(ptr), diff --git a/source/blender/nodes/NOD_geometry_exec.hh b/source/blender/nodes/NOD_geometry_exec.hh index 5fe554e0478..445e1ed6af2 100644 --- a/source/blender/nodes/NOD_geometry_exec.hh +++ b/source/blender/nodes/NOD_geometry_exec.hh @@ -26,6 +26,8 @@ namespace blender::nodes { +using bke::BooleanReadAttribute; +using bke::BooleanWriteAttribute; using bke::Color4fReadAttribute; using bke::Color4fWriteAttribute; using bke::Float3ReadAttribute; diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_fill.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_fill.cc index d3c7e86b708..5cdbd18ecc8 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_attribute_fill.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_fill.cc @@ -27,6 +27,7 @@ static bNodeSocketTemplate geo_node_attribute_fill_in[] = { {SOCK_VECTOR, N_("Value"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX}, {SOCK_FLOAT, N_("Value"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX}, {SOCK_RGBA, N_("Value"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX}, + {SOCK_BOOLEAN, N_("Value"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX}, {-1, ""}, }; @@ -45,12 +46,14 @@ static void geo_node_attribute_fill_update(bNodeTree *UNUSED(ntree), bNode *node bNodeSocket *socket_value_vector = (bNodeSocket *)BLI_findlink(&node->inputs, 2); bNodeSocket *socket_value_float = socket_value_vector->next; bNodeSocket *socket_value_color4f = socket_value_float->next; + bNodeSocket *socket_value_boolean = socket_value_color4f->next; const CustomDataType data_type = static_cast(node->custom1); nodeSetSocketAvailability(socket_value_vector, data_type == CD_PROP_FLOAT3); nodeSetSocketAvailability(socket_value_float, data_type == CD_PROP_FLOAT); nodeSetSocketAvailability(socket_value_color4f, data_type == CD_PROP_COLOR); + nodeSetSocketAvailability(socket_value_boolean, data_type == CD_PROP_BOOL); } namespace blender::nodes { @@ -96,6 +99,14 @@ static void fill_attribute(GeometryComponent &component, const GeoNodeExecParams color4f_attribute.apply_span(); break; } + case CD_PROP_BOOL: { + BooleanWriteAttribute boolean_attribute = std::move(attribute); + const bool value = params.get_input("Value_003"); + MutableSpan attribute_span = boolean_attribute.get_span(); + attribute_span.fill(value); + boolean_attribute.apply_span(); + break; + } default: break; } diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_randomize.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_randomize.cc index bde9a2a695e..53df2e8c087 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_attribute_randomize.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_randomize.cc @@ -59,6 +59,16 @@ static void geo_node_attribute_randomize_update(bNodeTree *UNUSED(ntree), bNode namespace blender::nodes { +static void randomize_attribute(BooleanWriteAttribute &attribute, RandomNumberGenerator &rng) +{ + MutableSpan attribute_span = attribute.get_span(); + for (const int i : IndexRange(attribute.size())) { + const bool value = rng.get_float() > 0.5f; + attribute_span[i] = value; + } + attribute.apply_span(); +} + static void randomize_attribute(FloatWriteAttribute &attribute, float min, float max, @@ -121,6 +131,11 @@ static void randomize_attribute(GeometryComponent &component, randomize_attribute(float3_attribute, min_value, max_value, rng); break; } + case CD_PROP_BOOL: { + BooleanWriteAttribute boolean_attribute = std::move(attribute); + randomize_attribute(boolean_attribute, rng); + break; + } default: break; } diff --git a/source/blender/nodes/intern/node_tree_multi_function.cc b/source/blender/nodes/intern/node_tree_multi_function.cc index ec5527a2970..2e4196af156 100644 --- a/source/blender/nodes/intern/node_tree_multi_function.cc +++ b/source/blender/nodes/intern/node_tree_multi_function.cc @@ -208,6 +208,10 @@ static DataTypeConversions create_implicit_conversions() conversions, "float to Color4f", [](float a) { return Color4f(a, a, a, 1.0f); }); add_implicit_conversion( conversions, "Color4f to float", [](Color4f a) { return rgb_to_grayscale(a); }); + add_implicit_conversion( + conversions, "float3 to boolean", [](float3 a) { return a.length_squared() == 0.0f; }); + add_implicit_conversion( + conversions, "boolean to float3", [](bool a) { return (a) ? float3(1.0f) : float3(0.0f); }); return conversions; } -- cgit v1.2.3 From a8da70f70a1f581412982d1f858b7b9a96ab8c37 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Wed, 16 Dec 2020 12:50:45 -0600 Subject: Geometry Nodes: Add boolean attribute in utility function This follows up rBc484b54453e607, adding the boolean custom property data type in one more place that was missed. --- source/blender/nodes/intern/node_geometry_exec.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/source/blender/nodes/intern/node_geometry_exec.cc b/source/blender/nodes/intern/node_geometry_exec.cc index 6a22adb25a7..eef2c6c9125 100644 --- a/source/blender/nodes/intern/node_geometry_exec.cc +++ b/source/blender/nodes/intern/node_geometry_exec.cc @@ -96,6 +96,9 @@ CustomDataType GeoNodeExecParams::get_input_attribute_data_type( if (found_socket->type == SOCK_RGBA) { return CD_PROP_COLOR; } + if (found_socket->type == SOCK_BOOLEAN) { + return CD_PROP_BOOL; + } BLI_assert(false); return default_type; -- cgit v1.2.3 From 9d152263837f0ac5e790e0b12d3b3cfed31bed0f Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Wed, 16 Dec 2020 20:28:15 +0100 Subject: Ghost/Linux: Avoid error print if special directory can't be determined The function is supposed to fail gracefully if there is some error. That includes not being able to find `xdg-user-dir`. So don't let the error be printed to the console, it's misleading/annoying. From what I can tell we'll detect that problem fine and return NULL then. --- intern/ghost/intern/GHOST_SystemPathsUnix.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/intern/ghost/intern/GHOST_SystemPathsUnix.cpp b/intern/ghost/intern/GHOST_SystemPathsUnix.cpp index fdfde13b915..86f3a0a31fb 100644 --- a/intern/ghost/intern/GHOST_SystemPathsUnix.cpp +++ b/intern/ghost/intern/GHOST_SystemPathsUnix.cpp @@ -142,7 +142,8 @@ const GHOST_TUns8 *GHOST_SystemPathsUnix::getUserSpecialDir(GHOST_TUserSpecialDi } static string path = ""; - string command = string("xdg-user-dir ") + type_str; + /* Pipe stderr to /dev/null to avoid error prints. We will fail gracefully still. */ + string command = string("xdg-user-dir ") + type_str + " 2> /dev/null"; FILE *fstream = popen(command.c_str(), "r"); if (fstream == NULL) { @@ -163,7 +164,7 @@ const GHOST_TUns8 *GHOST_SystemPathsUnix::getUserSpecialDir(GHOST_TUserSpecialDi } path = path_stream.str(); - return (const GHOST_TUns8 *)path.c_str(); + return path[0] ? (const GHOST_TUns8 *)path.c_str() : NULL; } const GHOST_TUns8 *GHOST_SystemPathsUnix::getBinaryDir() const -- cgit v1.2.3 From 571362642201a743168cdf4c827a59c09c40414b Mon Sep 17 00:00:00 2001 From: Richard Antalik Date: Wed, 16 Dec 2020 20:34:26 +0100 Subject: VSE: Improve motion-picture workflow This commit resolves problem introduced in e1665c3d3190 - it was difficult to import media at their original resolution. This is done by using original resolution as reference for scale. All crop and strip transform values and their animation is converted form old files. To make both workflows easy to use, sequencer tool settings have been created with preset for preffered scaling method. This setting is in sequencer timeline header and add image or movie strip operator properties. Two new operators have been added: `sequencer.strip_transform_fit` operator with 3 options: Scale To Fit, Scale to Fill and Stretch To Fill. Operator can fail if strip image or video is not loaded currently, this case should be either sanitized or data loaded on demand. `sequencer.strip_transform_clear` operator with 4 options: Clear position, scale, rotation and all (previous 3 options combined). Reviewed By: sergey, fsiddi Differential Revision: https://developer.blender.org/D9582 --- release/scripts/startup/bl_ui/space_sequencer.py | 28 +++- source/blender/blenkernel/BKE_blender_version.h | 2 +- source/blender/blenkernel/intern/scene.c | 12 ++ source/blender/blenloader/intern/versioning_290.c | 182 +++++++++++++++++---- .../editors/space_sequencer/sequencer_add.c | 29 +++- .../editors/space_sequencer/sequencer_edit.c | 145 ++++++++++++++++ .../editors/space_sequencer/sequencer_intern.h | 2 + .../editors/space_sequencer/sequencer_ops.c | 2 + source/blender/imbuf/IMB_imbuf.h | 2 + source/blender/imbuf/intern/anim_movie.c | 10 ++ source/blender/makesdna/DNA_scene_types.h | 15 ++ source/blender/makesrna/intern/rna_scene.c | 38 +++++ source/blender/sequencer/SEQ_sequencer.h | 27 +++ source/blender/sequencer/intern/render.c | 18 +- source/blender/sequencer/intern/sequencer.c | 33 ++++ source/blender/sequencer/intern/strip_add.c | 14 ++ source/blender/sequencer/intern/utils.c | 34 ++++ 17 files changed, 541 insertions(+), 52 deletions(-) diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py index 84602057e18..e79b5d3e2c8 100644 --- a/release/scripts/startup/bl_ui/space_sequencer.py +++ b/release/scripts/startup/bl_ui/space_sequencer.py @@ -129,6 +129,8 @@ class SEQUENCER_HT_header(Header): layout = self.layout st = context.space_data + scene = context.scene + sequencer_tool_settings = context.tool_settings.sequencer_tool_settings show_region_tool_header = st.show_region_tool_header @@ -139,9 +141,15 @@ class SEQUENCER_HT_header(Header): SEQUENCER_MT_editor_menus.draw_collapsible(context, layout) - layout.separator_spacer() + if st.view_type in {'SEQUENCER', 'SEQUENCER_PREVIEW'}: + layout.separator_spacer() + row = layout.row(align=True) + row.prop(sequencer_tool_settings, "fit_method", text="") + layout.separator_spacer() if st.view_type in {'PREVIEW', 'SEQUENCER_PREVIEW'}: + if st.view_type == 'PREVIEW': + layout.separator_spacer() layout.prop(st, "display_mode", text="", icon_only=True) layout.prop(st, "preview_channels", text="", icon_only=True) @@ -700,6 +708,22 @@ class SEQUENCER_MT_add_effect(Menu): col.enabled = selected_sequences_len(context) != 0 +class SEQUENCER_MT_strip_image_transform(Menu): + bl_label = "Image Transform" + + def draw(self, _context): + layout = self.layout + + layout.operator("sequencer.strip_transform_fit", text="Scale To Fit").fit_method = 'FIT' + layout.operator("sequencer.strip_transform_fit", text="Scale to Fill").fit_method = 'FILL' + layout.operator("sequencer.strip_transform_fit", text="Stretch To Fill").fit_method = 'STRETCH' + layout.separator() + + layout.operator("sequencer.strip_transform_clear", text="Clear Position").property = 'POSITION' + layout.operator("sequencer.strip_transform_clear", text="Clear Scale").property = 'SCALE' + layout.operator("sequencer.strip_transform_clear", text="Clear Rotation").property = 'ROTATION' + layout.operator("sequencer.strip_transform_clear", text="Clear All").property = 'ALL' + class SEQUENCER_MT_strip_transform(Menu): bl_label = "Transform" @@ -794,6 +818,7 @@ class SEQUENCER_MT_strip(Menu): layout.separator() layout.menu("SEQUENCER_MT_strip_transform") + layout.menu("SEQUENCER_MT_strip_image_transform") layout.separator() layout.operator("sequencer.split", text="Split").type = 'SOFT' @@ -2285,6 +2310,7 @@ classes = ( SEQUENCER_MT_strip_effect, SEQUENCER_MT_strip_movie, SEQUENCER_MT_strip, + SEQUENCER_MT_strip_image_transform, SEQUENCER_MT_strip_transform, SEQUENCER_MT_strip_input, SEQUENCER_MT_strip_lock_mute, diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index ca95ca8bda0..1ed4d1183a1 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -39,7 +39,7 @@ extern "C" { /* Blender file format version. */ #define BLENDER_FILE_VERSION BLENDER_VERSION -#define BLENDER_FILE_SUBVERSION 7 +#define BLENDER_FILE_SUBVERSION 8 /* Minimum Blender version that supports reading file written with the current * version. Older Blender versions will test this and show a warning if the file diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index f63d443d29f..cc192c1c3c0 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -222,6 +222,7 @@ static void scene_init_data(ID *id) /* Curve Profile */ scene->toolsettings->custom_bevel_profile_preset = BKE_curveprofile_add(PROF_PRESET_LINE); + scene->toolsettings->sequencer_tool_settings = SEQ_tool_settings_init(); for (size_t i = 0; i < ARRAY_SIZE(scene->orientation_slots); i++) { scene->orientation_slots[i].index_custom = -1; @@ -862,6 +863,9 @@ static void scene_blend_write(BlendWriter *writer, ID *id, const void *id_addres if (tos->custom_bevel_profile_preset) { BKE_curveprofile_blend_write(writer, tos->custom_bevel_profile_preset); } + if (tos->sequencer_tool_settings) { + BLO_write_struct(writer, SequencerToolSettings, tos->sequencer_tool_settings); + } BKE_paint_blend_write(writer, &tos->imapaint.paint); @@ -1121,6 +1125,8 @@ static void scene_blend_read_data(BlendDataReader *reader, ID *id) if (sce->toolsettings->custom_bevel_profile_preset) { BKE_curveprofile_blend_read(reader, sce->toolsettings->custom_bevel_profile_preset); } + + BLO_read_data_address(reader, &sce->toolsettings->sequencer_tool_settings); } if (sce->ed) { @@ -1792,6 +1798,8 @@ ToolSettings *BKE_toolsettings_copy(ToolSettings *toolsettings, const int flag) ts->gp_sculpt.cur_primitive = BKE_curvemapping_copy(ts->gp_sculpt.cur_primitive); ts->custom_bevel_profile_preset = BKE_curveprofile_copy(ts->custom_bevel_profile_preset); + + ts->sequencer_tool_settings = SEQ_tool_settings_copy(ts->sequencer_tool_settings); return ts; } @@ -1850,6 +1858,10 @@ void BKE_toolsettings_free(ToolSettings *toolsettings) BKE_curveprofile_free(toolsettings->custom_bevel_profile_preset); } + if (toolsettings->sequencer_tool_settings) { + SEQ_tool_settings_free(toolsettings->sequencer_tool_settings); + } + MEM_freeN(toolsettings); } diff --git a/source/blender/blenloader/intern/versioning_290.c b/source/blender/blenloader/intern/versioning_290.c index 49e1b057b39..753cc861982 100644 --- a/source/blender/blenloader/intern/versioning_290.c +++ b/source/blender/blenloader/intern/versioning_290.c @@ -74,6 +74,29 @@ /* Make preferences read-only, use versioning_userdef.c. */ #define U (*((const UserDef *)&U)) +static eSpaceSeq_Proxy_RenderSize get_sequencer_render_size(Main *bmain) +{ + eSpaceSeq_Proxy_RenderSize render_size = 100; + + for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) { + LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { + LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) { + switch (sl->spacetype) { + case SPACE_SEQ: { + SpaceSeq *sseq = (SpaceSeq *)sl; + if (sseq->mainb == SEQ_DRAW_IMG_IMBUF) { + render_size = sseq->render_size; + break; + } + } + } + } + } + } + + return render_size; +} + /* image_size is width or height depending what RNA property is converted - X or Y. */ static void seq_convert_transform_animation(const Scene *scene, const char *path, @@ -212,6 +235,90 @@ static void seq_convert_transform_crop_lb(const Scene *scene, } } +static void seq_convert_transform_animation_2(const Scene *scene, + const char *path, + const float scale_to_fit_factor) +{ + if (scene->adt == NULL || scene->adt->action == NULL) { + return; + } + + FCurve *fcu = BKE_fcurve_find(&scene->adt->action->curves, path, 0); + if (fcu != NULL && !BKE_fcurve_is_empty(fcu)) { + BezTriple *bezt = fcu->bezt; + for (int i = 0; i < fcu->totvert; i++, bezt++) { + /* Same math as with old_image_center_*, but simplified. */ + bezt->vec[1][1] *= scale_to_fit_factor; + } + } +} + +static void seq_convert_transform_crop_2(const Scene *scene, + Sequence *seq, + const eSpaceSeq_Proxy_RenderSize render_size) +{ + const StripElem *s_elem = SEQ_render_give_stripelem(seq, seq->start); + if (s_elem == NULL) { + return; + } + + StripCrop *c = seq->strip->crop; + StripTransform *t = seq->strip->transform; + int image_size_x = s_elem->orig_width; + int image_size_y = s_elem->orig_height; + + if (SEQ_can_use_proxy(seq, SEQ_rendersize_to_proxysize(render_size))) { + image_size_x /= SEQ_rendersize_to_scale_factor(render_size); + image_size_y /= SEQ_rendersize_to_scale_factor(render_size); + } + + /* Calculate scale factor, so image fits in preview area with original aspect ratio. */ + const float scale_to_fit_factor = MIN2((float)scene->r.xsch / (float)image_size_x, + (float)scene->r.ysch / (float)image_size_y); + t->scale_x *= scale_to_fit_factor; + t->scale_y *= scale_to_fit_factor; + c->top /= scale_to_fit_factor; + c->bottom /= scale_to_fit_factor; + c->left /= scale_to_fit_factor; + c->right /= scale_to_fit_factor; + + char name_esc[(sizeof(seq->name) - 2) * 2], *path; + BLI_str_escape(name_esc, seq->name + 2, sizeof(name_esc)); + path = BLI_sprintfN("sequence_editor.sequences_all[\"%s\"].transform.offset_x", name_esc); + seq_convert_transform_animation_2(scene, path, scale_to_fit_factor); + MEM_freeN(path); + path = BLI_sprintfN("sequence_editor.sequences_all[\"%s\"].transform.offset_y", name_esc); + seq_convert_transform_animation_2(scene, path, scale_to_fit_factor); + MEM_freeN(path); + path = BLI_sprintfN("sequence_editor.sequences_all[\"%s\"].crop.min_x", name_esc); + seq_convert_transform_animation_2(scene, path, 1 / scale_to_fit_factor); + MEM_freeN(path); + path = BLI_sprintfN("sequence_editor.sequences_all[\"%s\"].crop.max_x", name_esc); + seq_convert_transform_animation_2(scene, path, 1 / scale_to_fit_factor); + MEM_freeN(path); + path = BLI_sprintfN("sequence_editor.sequences_all[\"%s\"].crop.min_y", name_esc); + seq_convert_transform_animation_2(scene, path, 1 / scale_to_fit_factor); + MEM_freeN(path); + path = BLI_sprintfN("sequence_editor.sequences_all[\"%s\"].crop.max_x", name_esc); + seq_convert_transform_animation_2(scene, path, 1 / scale_to_fit_factor); + MEM_freeN(path); +} + +static void seq_convert_transform_crop_lb_2(const Scene *scene, + const ListBase *lb, + const eSpaceSeq_Proxy_RenderSize render_size) +{ + + LISTBASE_FOREACH (Sequence *, seq, lb) { + if (seq->type != SEQ_TYPE_SOUND_RAM) { + seq_convert_transform_crop_2(scene, seq, render_size); + } + if (seq->type == SEQ_TYPE_META) { + seq_convert_transform_crop_lb_2(scene, &seq->seqbase, render_size); + } + } +} + void do_versions_after_linking_290(Main *bmain, ReportList *UNUSED(reports)) { if (!MAIN_VERSION_ATLEAST(bmain, 290, 1)) { @@ -441,25 +548,35 @@ void do_versions_after_linking_290(Main *bmain, ReportList *UNUSED(reports)) if (!MAIN_VERSION_ATLEAST(bmain, 292, 2)) { - eSpaceSeq_Proxy_RenderSize render_size = 100; + eSpaceSeq_Proxy_RenderSize render_size = get_sequencer_render_size(bmain); - for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) { - LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { - LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) { - switch (sl->spacetype) { - case SPACE_SEQ: { - SpaceSeq *sseq = (SpaceSeq *)sl; - render_size = sseq->render_size; - break; - } - } - } + LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { + if (scene->ed != NULL) { + seq_convert_transform_crop_lb(scene, &scene->ed->seqbase, render_size); } } + } + if (!MAIN_VERSION_ATLEAST(bmain, 292, 8)) { + /* Systematically rebuild posebones to ensure consistent ordering matching the one of bones in + * Armature obdata. */ + LISTBASE_FOREACH (Object *, ob, &bmain->objects) { + if (ob->type == OB_ARMATURE) { + BKE_pose_rebuild(bmain, ob, ob->data, true); + } + } + + /* Wet Paint Radius Factor */ + for (Brush *br = bmain->brushes.first; br; br = br->id.next) { + if (br->ob_mode & OB_MODE_SCULPT && br->wet_paint_radius_factor == 0.0f) { + br->wet_paint_radius_factor = 1.0f; + } + } + + eSpaceSeq_Proxy_RenderSize render_size = get_sequencer_render_size(bmain); LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { if (scene->ed != NULL) { - seq_convert_transform_crop_lb(scene, &scene->ed->seqbase, render_size); + seq_convert_transform_crop_lb_2(scene, &scene->ed->seqbase, render_size); } } } @@ -476,21 +593,6 @@ void do_versions_after_linking_290(Main *bmain, ReportList *UNUSED(reports)) */ { /* Keep this block, even when empty. */ - - /* Systematically rebuild posebones to ensure consistent ordering matching the one of bones in - * Armature obdata. */ - LISTBASE_FOREACH (Object *, ob, &bmain->objects) { - if (ob->type == OB_ARMATURE) { - BKE_pose_rebuild(bmain, ob, ob->data, true); - } - } - } - - /* Wet Paint Radius Factor */ - for (Brush *br = bmain->brushes.first; br; br = br->id.next) { - if (br->ob_mode & OB_MODE_SCULPT && br->wet_paint_radius_factor == 0.0f) { - br->wet_paint_radius_factor = 1.0f; - } } } @@ -1305,6 +1407,22 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain) } } + if (!MAIN_VERSION_ATLEAST(bmain, 292, 8)) { + LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) { + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { + if (STREQ(node->idname, "GeometryNodeRandomAttribute")) { + STRNCPY(node->idname, "GeometryNodeAttributeRandomize"); + } + } + } + + LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { + if (scene->ed != NULL) { + scene->toolsettings->sequencer_tool_settings = SEQ_tool_settings_init(); + } + } + } + /** * Versioning code until next subversion bump goes here. * @@ -1316,13 +1434,5 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain) */ { /* Keep this block, even when empty. */ - - LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) { - LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { - if (STREQ(node->idname, "GeometryNodeRandomAttribute")) { - STRNCPY(node->idname, "GeometryNodeAttributeRandomize"); - } - } - } } } diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c index 37dfcdbc765..71433a6978a 100644 --- a/source/blender/editors/space_sequencer/sequencer_add.c +++ b/source/blender/editors/space_sequencer/sequencer_add.c @@ -81,9 +81,18 @@ typedef struct SequencerAddData { #define SEQPROP_ENDFRAME (1 << 1) #define SEQPROP_NOPATHS (1 << 2) #define SEQPROP_NOCHAN (1 << 3) +#define SEQPROP_FIT_METHOD (1 << 4) #define SELECT 1 +static const EnumPropertyItem scale_fit_methods[] = { + {SEQ_SCALE_TO_FIT, "FIT", 0, "Scale to Fit", "Scale image to fit within the canvas"}, + {SEQ_SCALE_TO_FILL, "FILL", 0, "Scale to Fill", "Scale image to completely fill the canvas"}, + {SEQ_STRETCH_TO_FILL, "STRETCH", 0, "Stretch to Fill", "Stretch image to fill the canvas"}, + {SEQ_USE_ORIGINAL_SIZE, "ORIGINAL", 0, "Use Original Size", "Keep image at its original size"}, + {0, NULL, 0, NULL, NULL}, +}; + static void sequencer_generic_props__internal(wmOperatorType *ot, int flag) { PropertyRNA *prop; @@ -123,6 +132,15 @@ static void sequencer_generic_props__internal(wmOperatorType *ot, int flag) prop = RNA_def_boolean( ot->srna, "overlap", 0, "Allow Overlap", "Don't correct overlap on new sequence strips"); RNA_def_property_flag(prop, PROP_HIDDEN); + + if (flag & SEQPROP_FIT_METHOD) { + ot->prop = RNA_def_enum(ot->srna, + "fit_method", + scale_fit_methods, + SEQ_SCALE_TO_FIT, + "Fit Method", + "Scale fit method"); + } } static void sequencer_generic_invoke_path__internal(bContext *C, @@ -206,6 +224,8 @@ static void seq_load_operator_info(SeqLoadInfo *seq_load, bContext *C, wmOperato seq_load->end_frame = seq_load->start_frame; seq_load->channel = RNA_int_get(op->ptr, "channel"); seq_load->len = 1; + seq_load->fit_method = RNA_enum_get(op->ptr, "fit_method"); + SEQ_tool_settings_fit_method_set(CTX_data_scene(C), seq_load->fit_method); if ((prop = RNA_struct_find_property(op->ptr, "filepath"))) { /* Full path, file is set by the caller. */ @@ -659,6 +679,7 @@ static int sequencer_add_movie_strip_invoke(bContext *C, if (ed && ed->seqbasep && ed->seqbasep->first) { RNA_boolean_set(op->ptr, "use_framerate", false); } + RNA_enum_set(op->ptr, "fit_method", SEQ_tool_settings_fit_method_get(scene)); /* This is for drag and drop. */ if ((RNA_struct_property_is_set(op->ptr, "files") && RNA_collection_length(op->ptr, "files")) || @@ -725,7 +746,7 @@ void SEQUENCER_OT_movie_strip_add(struct wmOperatorType *ot) WM_FILESEL_SHOW_PROPS | WM_FILESEL_DIRECTORY, FILE_DEFAULTDISPLAY, FILE_SORT_DEFAULT); - sequencer_generic_props__internal(ot, SEQPROP_STARTFRAME); + sequencer_generic_props__internal(ot, SEQPROP_STARTFRAME | SEQPROP_FIT_METHOD); RNA_def_boolean(ot->srna, "sound", true, "Sound", "Load sound with the movie"); RNA_def_boolean(ot->srna, "use_framerate", @@ -928,6 +949,9 @@ static int sequencer_add_image_strip_invoke(bContext *C, PropertyRNA *prop; Scene *scene = CTX_data_scene(C); + const SequencerToolSettings *tool_settings = scene->toolsettings->sequencer_tool_settings; + RNA_enum_set(op->ptr, "fit_method", tool_settings->fit_method); + /* Name set already by drag and drop. */ if (RNA_struct_property_is_set(op->ptr, "files") && RNA_collection_length(op->ptr, "files")) { sequencer_generic_invoke_xy__internal( @@ -972,7 +996,8 @@ void SEQUENCER_OT_image_strip_add(struct wmOperatorType *ot) WM_FILESEL_SHOW_PROPS | WM_FILESEL_DIRECTORY, FILE_DEFAULTDISPLAY, FILE_SORT_DEFAULT); - sequencer_generic_props__internal(ot, SEQPROP_STARTFRAME | SEQPROP_ENDFRAME); + sequencer_generic_props__internal(ot, + SEQPROP_STARTFRAME | SEQPROP_ENDFRAME | SEQPROP_FIT_METHOD); RNA_def_boolean(ot->srna, "use_placeholders", diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c index 1e3529a9607..ddc9ba2e0f6 100644 --- a/source/blender/editors/space_sequencer/sequencer_edit.c +++ b/source/blender/editors/space_sequencer/sequencer_edit.c @@ -3414,3 +3414,148 @@ Sequence *find_nearest_seq(Scene *scene, View2D *v2d, int *hand, const int mval[ } /** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Clear Strip Transform Operator + * \{ */ + +enum { + STRIP_TRANSFORM_POSITION, + STRIP_TRANSFORM_SCALE, + STRIP_TRANSFORM_ROTATION, + STRIP_TRANSFORM_ALL, +}; + +static const EnumPropertyItem transform_reset_properties[] = { + {STRIP_TRANSFORM_POSITION, "POSITION", 0, "Position", "Reset strip transform location"}, + {STRIP_TRANSFORM_SCALE, "SCALE", 0, "Scale", "Reset strip transform scale"}, + {STRIP_TRANSFORM_ROTATION, "ROTATION", 0, "Rotation", "Reset strip transform rotation"}, + {STRIP_TRANSFORM_ALL, "ALL", 0, "All", "Reset strip transform location, scale and rotation"}, + {0, NULL, 0, NULL, NULL}, +}; + +static int sequencer_strip_transform_clear_exec(bContext *C, wmOperator *op) +{ + Scene *scene = CTX_data_scene(C); + const Editing *ed = BKE_sequencer_editing_get(scene, false); + Sequence *seq; + const int property = RNA_enum_get(op->ptr, "property"); + + for (seq = ed->seqbasep->first; seq; seq = seq->next) { + if (seq->flag & SELECT && seq->type != SEQ_TYPE_SOUND_RAM) { + StripTransform *transform = seq->strip->transform; + switch (property) { + case STRIP_TRANSFORM_POSITION: + transform->xofs = 0; + transform->yofs = 0; + break; + case STRIP_TRANSFORM_SCALE: + transform->scale_x = 1.0f; + transform->scale_y = 1.0f; + break; + case STRIP_TRANSFORM_ROTATION: + transform->rotation = 0.0f; + break; + case STRIP_TRANSFORM_ALL: + transform->xofs = 0; + transform->yofs = 0; + transform->scale_x = 1.0f; + transform->scale_y = 1.0f; + transform->rotation = 0.0f; + break; + } + BKE_sequence_invalidate_cache_preprocessed(scene, seq); + } + } + + WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); + return OPERATOR_FINISHED; +} + +void SEQUENCER_OT_strip_transform_clear(struct wmOperatorType *ot) +{ + /* Identifiers. */ + ot->name = "Clear Strip Transform"; + ot->idname = "SEQUENCER_OT_strip_transform_clear"; + ot->description = "Reset image transformation to default value"; + + /* Api callbacks. */ + ot->exec = sequencer_strip_transform_clear_exec; + ot->poll = sequencer_edit_poll; + + /* Flags. */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + ot->prop = RNA_def_enum(ot->srna, + "property", + transform_reset_properties, + STRIP_TRANSFORM_ALL, + "Property", + "Strip transform property to be reset"); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Transform Set Fit Operator + * \{ */ + +static const EnumPropertyItem scale_fit_methods[] = { + {SEQ_SCALE_TO_FIT, "FIT", 0, "Scale to Fit", "Scale image so fits in preview"}, + {SEQ_SCALE_TO_FILL, "FILL", 0, "Scale to Fill", "Scale image so it fills preview completely"}, + {SEQ_STRETCH_TO_FILL, "STRETCH", 0, "Stretch to Fill", "Stretch image so it fills preview"}, + {0, NULL, 0, NULL, NULL}, +}; + +static int sequencer_strip_transform_fit_exec(bContext *C, wmOperator *op) +{ + Scene *scene = CTX_data_scene(C); + const Editing *ed = BKE_sequencer_editing_get(scene, false); + Sequence *seq; + const eSeqImageFitMethod fit_method = RNA_enum_get(op->ptr, "fit_method"); + + for (seq = ed->seqbasep->first; seq; seq = seq->next) { + if (seq->flag & SELECT && seq->type != SEQ_TYPE_SOUND_RAM) { + const int timeline_frame = CFRA; + StripElem *strip_elem = SEQ_render_give_stripelem(seq, timeline_frame); + + if (strip_elem == NULL) { + continue; + } + + SEQ_set_scale_to_fit(seq, + strip_elem->orig_width, + strip_elem->orig_height, + scene->r.xsch, + scene->r.ysch, + fit_method); + BKE_sequence_invalidate_cache_preprocessed(scene, seq); + } + } + + WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); + return OPERATOR_FINISHED; +} + +void SEQUENCER_OT_strip_transform_fit(struct wmOperatorType *ot) +{ + /* Identifiers. */ + ot->name = "Strip Transform Set Fit"; + ot->idname = "SEQUENCER_OT_strip_transform_fit"; + + /* Api callbacks. */ + ot->exec = sequencer_strip_transform_fit_exec; + ot->poll = sequencer_edit_poll; + + /* Flags. */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + ot->prop = RNA_def_enum(ot->srna, + "fit_method", + scale_fit_methods, + SEQ_SCALE_TO_FIT, + "Fit Method", + "Scale fit fit_method"); +} + +/** \} */ diff --git a/source/blender/editors/space_sequencer/sequencer_intern.h b/source/blender/editors/space_sequencer/sequencer_intern.h index 6ccfd3a9045..4c942a83f2b 100644 --- a/source/blender/editors/space_sequencer/sequencer_intern.h +++ b/source/blender/editors/space_sequencer/sequencer_intern.h @@ -144,6 +144,8 @@ void SEQUENCER_OT_enable_proxies(struct wmOperatorType *ot); void SEQUENCER_OT_export_subtitles(struct wmOperatorType *ot); void SEQUENCER_OT_set_range_to_strips(struct wmOperatorType *ot); +void SEQUENCER_OT_strip_transform_clear(struct wmOperatorType *ot); +void SEQUENCER_OT_strip_transform_fit(struct wmOperatorType *ot); /* sequencer_select.c */ void SEQUENCER_OT_select_all(struct wmOperatorType *ot); diff --git a/source/blender/editors/space_sequencer/sequencer_ops.c b/source/blender/editors/space_sequencer/sequencer_ops.c index bdf6e4ece7f..7bfc8600544 100644 --- a/source/blender/editors/space_sequencer/sequencer_ops.c +++ b/source/blender/editors/space_sequencer/sequencer_ops.c @@ -81,6 +81,8 @@ void sequencer_operatortypes(void) WM_operatortype_append(SEQUENCER_OT_change_path); WM_operatortype_append(SEQUENCER_OT_set_range_to_strips); + WM_operatortype_append(SEQUENCER_OT_strip_transform_clear); + WM_operatortype_append(SEQUENCER_OT_strip_transform_fit); /* sequencer_select.c */ WM_operatortype_append(SEQUENCER_OT_select_all); diff --git a/source/blender/imbuf/IMB_imbuf.h b/source/blender/imbuf/IMB_imbuf.h index 957352595ed..58ddc918f61 100644 --- a/source/blender/imbuf/IMB_imbuf.h +++ b/source/blender/imbuf/IMB_imbuf.h @@ -382,6 +382,8 @@ bool IMB_anim_can_produce_frames(const struct anim *anim); int ismovie(const char *filepath); void IMB_anim_set_preseek(struct anim *anim, int preseek); int IMB_anim_get_preseek(struct anim *anim); +int IMB_anim_get_image_width(struct anim *anim); +int IMB_anim_get_image_height(struct anim *anim); /** * diff --git a/source/blender/imbuf/intern/anim_movie.c b/source/blender/imbuf/intern/anim_movie.c index d825b20f5f2..9b01ea0840f 100644 --- a/source/blender/imbuf/intern/anim_movie.c +++ b/source/blender/imbuf/intern/anim_movie.c @@ -1506,3 +1506,13 @@ int IMB_anim_get_preseek(struct anim *anim) { return anim->preseek; } + +int IMB_anim_get_image_width(struct anim *anim) +{ + return anim->x; +} + +int IMB_anim_get_image_height(struct anim *anim) +{ + return anim->y; +} diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index 8d43483dfe4..f73f99eb4e7 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -1339,6 +1339,18 @@ typedef struct MeshStatVis { float sharp_min, sharp_max; } MeshStatVis; +typedef struct SequencerToolSettings { + /* eSeqImageFitMethod */ + int fit_method; +} SequencerToolSettings; + +typedef enum eSeqImageFitMethod { + SEQ_SCALE_TO_FIT, + SEQ_SCALE_TO_FILL, + SEQ_STRETCH_TO_FILL, + SEQ_USE_ORIGINAL_SIZE, +} eSeqImageFitMethod; + /* *************************************************************** */ /* Tool Settings */ @@ -1513,6 +1525,9 @@ typedef struct ToolSettings { * Temporary until there is a proper preset system that stores the profiles or maybe stores * entire bevel configurations. */ struct CurveProfile *custom_bevel_profile_preset; + + struct SequencerToolSettings *sequencer_tool_settings; + } ToolSettings; /* *************************************************************** */ diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index e149bb4ecad..7cae88d292b 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -2200,6 +2200,11 @@ static char *rna_CurvePaintSettings_path(PointerRNA *UNUSED(ptr)) return BLI_strdup("tool_settings.curve_paint_settings"); } +static char *rna_SequencerToolSettings_path(PointerRNA *UNUSED(ptr)) +{ + return BLI_strdup("tool_settings.sequencer_tool_settings"); +} + /* generic function to recalc geometry */ static void rna_EditMesh_update(bContext *C, PointerRNA *UNUSED(ptr)) { @@ -3584,6 +3589,38 @@ static void rna_def_tool_settings(BlenderRNA *brna) RNA_def_property_pointer_sdna(prop, NULL, "custom_bevel_profile_preset"); RNA_def_property_struct_type(prop, "CurveProfile"); RNA_def_property_ui_text(prop, "Curve Profile Widget", "Used for defining a profile's path"); + + /* Sequencer tool settings */ + prop = RNA_def_property(srna, "sequencer_tool_settings", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); + RNA_def_property_struct_type(prop, "SequencerToolSettings"); + RNA_def_property_ui_text(prop, "Sequencer Tool Settings", NULL); +} + +static void rna_def_sequencer_tool_settings(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + static const EnumPropertyItem scale_fit_methods[] = { + {SEQ_SCALE_TO_FIT, "FIT", 0, "Scale to Fit", "Scale image to fit within the canvas"}, + {SEQ_SCALE_TO_FILL, "FILL", 0, "Scale to Fill", "Scale image to completely fill the canvas"}, + {SEQ_STRETCH_TO_FILL, "STRETCH", 0, "Stretch to Fill", "Stretch image to fill the canvas"}, + {SEQ_USE_ORIGINAL_SIZE, + "ORIGINAL", + 0, + "Use Original Size", + "Keep image at its original size"}, + {0, NULL, 0, NULL, NULL}, + }; + + srna = RNA_def_struct(brna, "SequencerToolSettings", NULL); + RNA_def_struct_path_func(srna, "rna_SequencerToolSettings_path"); + RNA_def_struct_ui_text(srna, "Sequencer Tool Settings", ""); + + prop = RNA_def_property(srna, "fit_method", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, scale_fit_methods); + RNA_def_property_ui_text(prop, "Fit Method", "Scale fit method"); } static void rna_def_unified_paint_settings(BlenderRNA *brna) @@ -7968,6 +8005,7 @@ void RNA_def_scene(BlenderRNA *brna) rna_def_gpencil_interpolate(brna); rna_def_unified_paint_settings(brna); rna_def_curve_paint_settings(brna); + rna_def_sequencer_tool_settings(brna); rna_def_statvis(brna); rna_def_unit_settings(brna); rna_def_scene_image_format_data(brna); diff --git a/source/blender/sequencer/SEQ_sequencer.h b/source/blender/sequencer/SEQ_sequencer.h index 8c4863d98ed..9b4c88520b4 100644 --- a/source/blender/sequencer/SEQ_sequencer.h +++ b/source/blender/sequencer/SEQ_sequencer.h @@ -23,6 +23,8 @@ * \ingroup sequencer */ +#include "DNA_scene_types.h" + #ifdef __cplusplus extern "C" { #endif @@ -47,6 +49,10 @@ struct StripElem; struct TextVars; struct bContext; struct bSound; +struct BlendWriter; +struct BlendDataReader; +struct BlendLibReader; +struct SequencerToolSettings; /* Wipe effect */ enum { @@ -179,6 +185,12 @@ void SEQ_render_pixel_from_sequencer_space_v4(struct Scene *scene, float pixel[4 * Sequencer scene functions * ********************************************************************** */ +struct SequencerToolSettings *SEQ_tool_settings_init(void); +void SEQ_tool_settings_free(struct SequencerToolSettings *tool_settings); +eSeqImageFitMethod SEQ_tool_settings_fit_method_get(struct Scene *scene); +void SEQ_tool_settings_fit_method_set(struct Scene *scene, eSeqImageFitMethod fit_method); + +struct SequencerToolSettings *SEQ_tool_settings_copy(struct SequencerToolSettings *tool_settings); struct Editing *BKE_sequencer_editing_get(struct Scene *scene, bool alloc); struct Editing *BKE_sequencer_editing_ensure(struct Scene *scene); void BKE_sequencer_editing_free(struct Scene *scene, const bool do_id_user); @@ -360,6 +372,20 @@ void BKE_sequence_invalidate_cache_in_range(struct Scene *scene, int invalidate_types); void BKE_sequencer_all_free_anim_ibufs(struct Scene *scene, int timeline_frame); +/* ********************************************************************** + * util.c + * + * Add strips + * ********************************************************************** + */ + +void SEQ_set_scale_to_fit(const struct Sequence *seq, + const int image_width, + const int image_height, + const int preview_width, + const int preview_height, + const eSeqImageFitMethod fit_method); + /* ********************************************************************** * sequencer.c * @@ -376,6 +402,7 @@ typedef struct SeqLoadInfo { int type; int len; /* only for image strips */ char path[1024]; /* 1024 = FILE_MAX */ + eSeqImageFitMethod fit_method; /* multiview */ char views_format; diff --git a/source/blender/sequencer/intern/render.c b/source/blender/sequencer/intern/render.c index 155258dc2c3..2e757a06751 100644 --- a/source/blender/sequencer/intern/render.c +++ b/source/blender/sequencer/intern/render.c @@ -528,7 +528,6 @@ static void sequencer_image_transform_init(void *handle_v, handle->ibuf_source = init_data->ibuf_source; handle->ibuf_out = init_data->ibuf_out; handle->transform = init_data->transform; - handle->scale_to_fit = init_data->scale_to_fit; handle->image_scale_factor = init_data->image_scale_factor; handle->for_render = init_data->for_render; @@ -540,8 +539,8 @@ static void *sequencer_image_transform_do_thread(void *data_v) { const ImageTransformThreadData *data = (ImageTransformThreadData *)data_v; const StripTransform *transform = data->transform; - const float scale_x = transform->scale_x * data->scale_to_fit; - const float scale_y = transform->scale_y * data->scale_to_fit; + const float scale_x = transform->scale_x * data->image_scale_factor; + const float scale_y = transform->scale_y * data->image_scale_factor; const float scale_to_fit_offs_x = (data->ibuf_out->x - data->ibuf_source->x) / 2; const float scale_to_fit_offs_y = (data->ibuf_out->y - data->ibuf_source->y) / 2; const float translate_x = transform->xofs * data->image_scale_factor + scale_to_fit_offs_x; @@ -626,10 +625,6 @@ static ImBuf *input_preprocess(const SeqRenderData *context, IMB_filtery(preprocessed_ibuf); } - /* Calculate scale factor, so image fits in preview area with original aspect ratio. */ - const float scale_to_fit_factor = MIN2((float)context->rectx / (float)ibuf->x, - (float)context->recty / (float)ibuf->y); - /* Get scale factor if preview resolution doesn't match project resolution. */ float preview_scale_factor; if (context->preview_render_size == SEQ_RENDER_SIZE_SCENE) { @@ -648,10 +643,10 @@ static ImBuf *input_preprocess(const SeqRenderData *context, const int height = ibuf->y; const StripCrop *c = seq->strip->crop; - const int left = c->left / scale_to_fit_factor * preview_scale_factor; - const int right = c->right / scale_to_fit_factor * preview_scale_factor; - const int top = c->top / scale_to_fit_factor * preview_scale_factor; - const int bottom = c->bottom / scale_to_fit_factor * preview_scale_factor; + const int left = c->left; + const int right = c->right; + const int top = c->top; + const int bottom = c->bottom; const float col[4] = {0.0f, 0.0f, 0.0f, 0.0f}; /* Left. */ @@ -673,7 +668,6 @@ static ImBuf *input_preprocess(const SeqRenderData *context, init_data.ibuf_source = ibuf; init_data.ibuf_out = preprocessed_ibuf; init_data.transform = seq->strip->transform; - init_data.scale_to_fit = scale_to_fit_factor; init_data.image_scale_factor = preview_scale_factor; init_data.for_render = context->for_render; IMB_processor_apply_threaded(context->recty, diff --git a/source/blender/sequencer/intern/sequencer.c b/source/blender/sequencer/intern/sequencer.c index c998886626c..82971a30c31 100644 --- a/source/blender/sequencer/intern/sequencer.c +++ b/source/blender/sequencer/intern/sequencer.c @@ -301,6 +301,32 @@ static void seq_new_fix_links_recursive(Sequence *seq) } } } + +SequencerToolSettings *SEQ_tool_settings_init(void) +{ + SequencerToolSettings *tool_settings = MEM_callocN(sizeof(SequencerToolSettings), + "Sequencer tool settings"); + tool_settings->fit_method = SEQ_SCALE_TO_FIT; + return tool_settings; +} + +void SEQ_tool_settings_free(SequencerToolSettings *tool_settings) +{ + MEM_freeN(tool_settings); +} + +eSeqImageFitMethod SEQ_tool_settings_fit_method_get(Scene *scene) +{ + const SequencerToolSettings *tool_settings = scene->toolsettings->sequencer_tool_settings; + return tool_settings->fit_method; +} + +void SEQ_tool_settings_fit_method_set(Scene *scene, eSeqImageFitMethod fit_method) +{ + SequencerToolSettings *tool_settings = scene->toolsettings->sequencer_tool_settings; + tool_settings->fit_method = fit_method; +} + /** \} */ /* -------------------------------------------------------------------- */ @@ -609,4 +635,11 @@ static void seq_free_animdata(Scene *scene, Sequence *seq) } #undef SEQ_RNAPATH_MAXSTR + +SequencerToolSettings *SEQ_tool_settings_copy(SequencerToolSettings *tool_settings) +{ + SequencerToolSettings *tool_settings_copy = MEM_dupallocN(tool_settings); + return tool_settings_copy; +} + /** \} */ diff --git a/source/blender/sequencer/intern/strip_add.c b/source/blender/sequencer/intern/strip_add.c index d2e4025bdfc..9c9d51e9286 100644 --- a/source/blender/sequencer/intern/strip_add.c +++ b/source/blender/sequencer/intern/strip_add.c @@ -118,6 +118,15 @@ Sequence *BKE_sequencer_add_image_strip(bContext *C, ListBase *seqbasep, SeqLoad seq->flag |= seq_load->flag & SEQ_USE_VIEWS; seq_load_apply(CTX_data_main(C), scene, seq, seq_load); + + char file_path[FILE_MAX]; + BLI_join_dirfile(file_path, sizeof(file_path), seq_load->path, seq_load->name); + ImBuf *ibuf = IMB_loadiffname(file_path, IB_rect, seq->strip->colorspace_settings.name); + if (ibuf != NULL) { + SEQ_set_scale_to_fit(seq, ibuf->x, ibuf->y, scene->r.xsch, scene->r.ysch, seq_load->fit_method); + IMB_freeImBuf(ibuf); + } + BKE_sequence_invalidate_cache_composite(scene, seq); return seq; @@ -275,6 +284,11 @@ Sequence *BKE_sequencer_add_movie_strip(bContext *C, ListBase *seqbasep, SeqLoad IMB_anim_load_metadata(anim_arr[0]); seq->anim_preseek = IMB_anim_get_preseek(anim_arr[0]); + + const float width = IMB_anim_get_image_width(anim_arr[0]); + const float height = IMB_anim_get_image_height(anim_arr[0]); + SEQ_set_scale_to_fit(seq, width, height, scene->r.xsch, scene->r.ysch, seq_load->fit_method); + BLI_strncpy(seq->name + 2, "Movie", SEQ_NAME_MAXSTR - 2); BKE_sequence_base_unique_name_recursive(&scene->ed->seqbase, seq); diff --git a/source/blender/sequencer/intern/utils.c b/source/blender/sequencer/intern/utils.c index 2b1d36a7709..ab0b65dba7f 100644 --- a/source/blender/sequencer/intern/utils.c +++ b/source/blender/sequencer/intern/utils.c @@ -36,6 +36,7 @@ #include "BLI_listbase.h" #include "BLI_path_util.h" #include "BLI_string.h" +#include "BLI_utildefines.h" #include "BKE_image.h" #include "BKE_main.h" @@ -547,3 +548,36 @@ bool sequencer_seq_generates_image(Sequence *seq) } return false; } + +void SEQ_set_scale_to_fit(const Sequence *seq, + const int image_width, + const int image_height, + const int preview_width, + const int preview_height, + const eSeqImageFitMethod fit_method) +{ + StripTransform *transform = seq->strip->transform; + + switch (fit_method) { + case SEQ_SCALE_TO_FIT: + transform->scale_x = transform->scale_y = MIN2((float)preview_width / (float)image_width, + (float)preview_height / (float)image_height); + + break; + case SEQ_SCALE_TO_FILL: + + transform->scale_x = transform->scale_y = MAX2((float)preview_width / (float)image_width, + (float)preview_height / (float)image_height); + break; + case SEQ_STRETCH_TO_FILL: + transform->scale_x = (float)preview_width / (float)image_width; + transform->scale_y = (float)preview_height / (float)image_height; + break; + case SEQ_USE_ORIGINAL_SIZE: + transform->scale_x = 1.0f; + transform->scale_y = 1.0f; + break; + } + + return; +} -- cgit v1.2.3 From ad7682ffdb3db5d368fd5d16f1649da780cc069f Mon Sep 17 00:00:00 2001 From: Gaia Clary Date: Wed, 16 Dec 2020 20:37:29 +0100 Subject: Allow vertex tools to operate on weight groups when armature is in object mode Since a few versions (even before 2.79) we have an option that allows to restrict the vertex tools to operate only on deform groups. This was originally implemented for working with vertex groups for skeletal animation. In that case it is fortunate to have weight tools operate only on deforming vertext groups (vgroups assigned to bones) In previous versions of Blender (up to 2.79) we have been able to use this option in Mesh Edit mode regardless of the armature mode. The current implementation (since 2.80 as far as i know) enables this option only when the associated armature is in pose mode. this has a bad consequence: It is not at all intuitive that you have to put the armature into Pose mode before you can make use of the option in mesh edit mode. Besides this it is not even necessary in the case when the user wants to restrict the tool only to all pose bones. In that case the armature can safely be kept in Object mode. However, when the tool shall apply only to selected pose bones, then it actually makes sense to have the armature in pose mode (as it is implemented right now) I do not know why this feature has been restricted as described above. It must have got lost somewhere on the way to Blender 2.90 This patch fixes the issue as it allows to select the "restrict to pose bones" option when the armature is in any mode. I see no downsides of this change, actually this is a fix for a feature that once worked and apparently got forgotten in newer releases. Reviewed By: sybren, campbellbarton Differential Revision: https://developer.blender.org/D9658 --- source/blender/editors/object/object_vgroup.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c index 3d6a6abfe0d..23f1718cb2e 100644 --- a/source/blender/editors/object/object_vgroup.c +++ b/source/blender/editors/object/object_vgroup.c @@ -741,6 +741,9 @@ const EnumPropertyItem *ED_object_vgroup_selection_itemf_helper(const bContext * RNA_enum_items_add_value( &item, &totitem, WT_vertex_group_select_item, WT_VGROUP_BONE_SELECT); } + } + + if (BKE_modifiers_is_deformed_by_armature(ob)) { if (selection_mask & (1 << WT_VGROUP_BONE_DEFORM)) { RNA_enum_items_add_value( &item, &totitem, WT_vertex_group_select_item, WT_VGROUP_BONE_DEFORM); -- cgit v1.2.3 From 247b10e6a25ba58e8a74c64d4890a4c4885e51d0 Mon Sep 17 00:00:00 2001 From: Richard Antalik Date: Wed, 16 Dec 2020 21:24:42 +0100 Subject: Fix sequencer transform test failing This was casued by incorrect versioning keyframe conversion in recent commit 571362642201. --- source/blender/blenloader/intern/versioning_290.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/source/blender/blenloader/intern/versioning_290.c b/source/blender/blenloader/intern/versioning_290.c index 753cc861982..4df681002a0 100644 --- a/source/blender/blenloader/intern/versioning_290.c +++ b/source/blender/blenloader/intern/versioning_290.c @@ -284,12 +284,6 @@ static void seq_convert_transform_crop_2(const Scene *scene, char name_esc[(sizeof(seq->name) - 2) * 2], *path; BLI_str_escape(name_esc, seq->name + 2, sizeof(name_esc)); - path = BLI_sprintfN("sequence_editor.sequences_all[\"%s\"].transform.offset_x", name_esc); - seq_convert_transform_animation_2(scene, path, scale_to_fit_factor); - MEM_freeN(path); - path = BLI_sprintfN("sequence_editor.sequences_all[\"%s\"].transform.offset_y", name_esc); - seq_convert_transform_animation_2(scene, path, scale_to_fit_factor); - MEM_freeN(path); path = BLI_sprintfN("sequence_editor.sequences_all[\"%s\"].crop.min_x", name_esc); seq_convert_transform_animation_2(scene, path, 1 / scale_to_fit_factor); MEM_freeN(path); -- cgit v1.2.3 From 07c46154318e321fe76c818c357439b79ea982cc Mon Sep 17 00:00:00 2001 From: Philipp Oeser Date: Wed, 16 Dec 2020 19:00:12 +0100 Subject: Fix T83856: Sculpt: anchored brushes with spherical falloff ignore topology automasking Anchored brushes with spherical falloff start off with zero radius, thus we have no pbvh nodes on the first brush step. This would prevent initializing the automasking cache [which only happens on the first brush step]. Maniphest Tasks: T83856 Differential Revision: https://developer.blender.org/D9873 --- source/blender/editors/sculpt_paint/sculpt.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index 26db2673335..38d2bed7d97 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -5923,6 +5923,17 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe } } + /* Initialize automasking cache. For anchored brushes with spherical falloff, we start off with + * zero radius, thus we have no pbvh nodes on the first brush step. */ + if (totnode || + ((brush->falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) && (brush->flag & BRUSH_ANCHORED))) { + if (SCULPT_stroke_is_first_brush_step(ss->cache)) { + if (SCULPT_is_automasking_enabled(sd, ss, brush)) { + ss->cache->automasking = SCULPT_automasking_cache_init(sd, brush, ob); + } + } + } + /* Only act if some verts are inside the brush area. */ if (totnode) { float location[3]; @@ -5946,12 +5957,6 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe update_brush_local_mat(sd, ob); } - if (SCULPT_stroke_is_first_brush_step(ss->cache)) { - if (SCULPT_is_automasking_enabled(sd, ss, brush)) { - ss->cache->automasking = SCULPT_automasking_cache_init(sd, brush, ob); - } - } - if (brush->sculpt_tool == SCULPT_TOOL_POSE && SCULPT_stroke_is_first_brush_step(ss->cache)) { SCULPT_pose_brush_init(sd, ob, ss, brush); } -- cgit v1.2.3 From 9f588432e9dbf4dc8f0c822fdbad2f7dc4b5ca47 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Wed, 16 Dec 2020 14:40:30 -0600 Subject: Fix T83861: Snapping panel from shortcut dissapears after click This simple change sets the call_panel operator's "keep_open" property to True for the viewport snapping panel called with `ctrl-shift-tab`. There are quite a few settings in this panel, it often makes sense to change more than one of them at a time, especially because multiple snap elements can be active at the same time. --- release/scripts/presets/keyconfig/keymap_data/blender_default.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release/scripts/presets/keyconfig/keymap_data/blender_default.py b/release/scripts/presets/keyconfig/keymap_data/blender_default.py index 86b2f6f9005..d3990851e2c 100644 --- a/release/scripts/presets/keyconfig/keymap_data/blender_default.py +++ b/release/scripts/presets/keyconfig/keymap_data/blender_default.py @@ -1217,7 +1217,7 @@ def km_view3d(params): ("transform.mirror", {"type": 'M', "value": 'PRESS', "ctrl": True}, None), ("wm.context_toggle", {"type": 'TAB', "value": 'PRESS', "shift": True}, {"properties": [("data_path", 'tool_settings.use_snap')]}), - op_panel("VIEW3D_PT_snapping", {"type": 'TAB', "value": 'PRESS', "shift": True, "ctrl": True}, [("keep_open", False)]), + op_panel("VIEW3D_PT_snapping", {"type": 'TAB', "value": 'PRESS', "shift": True, "ctrl": True}, [("keep_open", True)]), ("object.transform_axis_target", {"type": 'T', "value": 'PRESS', "shift": True}, None), ("transform.skin_resize", {"type": 'A', "value": 'PRESS', "ctrl": True}, None), ]) -- cgit v1.2.3 From 3a1d1aaa86d0d7cc6aaf0e6633d557bbcdd0b514 Mon Sep 17 00:00:00 2001 From: Nicholas Rishel Date: Wed, 16 Dec 2020 15:32:18 -0800 Subject: Synchronize Wintab and Win32 time. Time is synchronized by the difference between the WT_PACKET receive time and the last received PACKET's pkTime. This is used to prevent Wintab packets from being prematurely expired. --- intern/ghost/intern/GHOST_SystemWin32.cpp | 2 +- intern/ghost/intern/GHOST_WindowWin32.cpp | 69 +++++++++++++++++++------------ intern/ghost/intern/GHOST_WindowWin32.h | 14 ++++++- 3 files changed, 55 insertions(+), 30 deletions(-) diff --git a/intern/ghost/intern/GHOST_SystemWin32.cpp b/intern/ghost/intern/GHOST_SystemWin32.cpp index d2aebab026f..2bf1d0c2d35 100644 --- a/intern/ghost/intern/GHOST_SystemWin32.cpp +++ b/intern/ghost/intern/GHOST_SystemWin32.cpp @@ -1614,7 +1614,7 @@ LRESULT WINAPI GHOST_SystemWin32::s_wndProc(HWND hwnd, UINT msg, WPARAM wParam, break; } case WT_PACKET: - window->updatePendingWintabEvents(); + window->updateWintabEventsSyncTime(); break; //////////////////////////////////////////////////////////////////////// // Pointer events, processed diff --git a/intern/ghost/intern/GHOST_WindowWin32.cpp b/intern/ghost/intern/GHOST_WindowWin32.cpp index af02663985d..a4cbf66b22d 100644 --- a/intern/ghost/intern/GHOST_WindowWin32.cpp +++ b/intern/ghost/intern/GHOST_WindowWin32.cpp @@ -1292,7 +1292,7 @@ GHOST_TSuccess GHOST_WindowWin32::getWintabInfo(std::vector &outWintabInfo); /** - * Updates stored pending Wintab events. + * Updates pending Wintab events and syncs Wintab time with OS time. */ - void updatePendingWintabEvents(); + void updateWintabEventsSyncTime(); + + /** + * Updates pending Wintab events. + */ + void updateWintabEvents(); GHOST_TSuccess beginFullScreen() const { @@ -629,6 +634,7 @@ class GHOST_WindowWin32 : public GHOST_Window { GHOST_TUns8 numSysButtons = 0; /** Cursors currently in contact mapped to system buttons */ DWORD sysButtonsPressed = 0; + DWORD sysTimeOffset = 0; LONG maxPressure = 0; LONG maxAzimuth = 0, maxAltitude = 0; /** Reusable buffer to read in Wintab Packets. */ @@ -642,6 +648,10 @@ class GHOST_WindowWin32 : public GHOST_Window { */ void initializeWintab(); + void readWintabEvents(); + + void expireWintabEvents(); + /** * Convert Wintab system mapped (mouse) buttons into Ghost button mask. * \param cursor: The Wintab cursor associated to the button. -- cgit v1.2.3 From d11b219d40d7c72156fd11c335fde27212997957 Mon Sep 17 00:00:00 2001 From: Richard Antalik Date: Thu, 17 Dec 2020 02:11:22 +0100 Subject: Fix T83869: Crash when creating Sequencer in new scene Crash on null dereference in `SEQ_timeline_boundbox()`. This function was generalized in rB9e4a4c2e996c to work on arbitrary `seqbase`. Fixed by refactoring `SEQ_timeline_boundbox()` functions to return default sane values if `seqbase` is `NULL` Reviewed By: HooglyBoogly Differential Revision: https://developer.blender.org/D9878 --- .../editors/space_sequencer/sequencer_draw.c | 2 +- .../editors/space_sequencer/sequencer_view.c | 6 +---- source/blender/sequencer/SEQ_sequencer.h | 1 + source/blender/sequencer/intern/sequencer.c | 14 ++++++++++ source/blender/sequencer/intern/strip_time.c | 30 ++++++++++------------ 5 files changed, 31 insertions(+), 22 deletions(-) diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c index 5ad1e2399f5..d7d601a3c76 100644 --- a/source/blender/editors/space_sequencer/sequencer_draw.c +++ b/source/blender/editors/space_sequencer/sequencer_draw.c @@ -2305,7 +2305,7 @@ void draw_timeline_seq(const bContext *C, ARegion *region) UI_view2d_view_ortho(v2d); /* Get timeline bound-box, needed for the scroll-bars. */ - SEQ_timeline_boundbox(scene, ed->seqbasep, &v2d->tot); + SEQ_timeline_boundbox(scene, SEQ_active_seqbase_get(ed), &v2d->tot); draw_seq_backdrop(v2d); UI_view2d_constant_grid_draw(v2d, FPS); diff --git a/source/blender/editors/space_sequencer/sequencer_view.c b/source/blender/editors/space_sequencer/sequencer_view.c index d2166705943..e12c43b7804 100644 --- a/source/blender/editors/space_sequencer/sequencer_view.c +++ b/source/blender/editors/space_sequencer/sequencer_view.c @@ -90,11 +90,7 @@ static int sequencer_view_all_exec(bContext *C, wmOperator *op) Scene *scene = CTX_data_scene(C); const Editing *ed = BKE_sequencer_editing_get(scene, false); - if (ed == NULL) { - return OPERATOR_FINISHED; - } - - SEQ_timeline_boundbox(scene, ed->seqbasep, &box); + SEQ_timeline_boundbox(scene, SEQ_active_seqbase_get(ed), &box); UI_view2d_smooth_view(C, region, &box, smooth_viewtx); return OPERATOR_FINISHED; } diff --git a/source/blender/sequencer/SEQ_sequencer.h b/source/blender/sequencer/SEQ_sequencer.h index 9b4c88520b4..3a9c23de5cc 100644 --- a/source/blender/sequencer/SEQ_sequencer.h +++ b/source/blender/sequencer/SEQ_sequencer.h @@ -194,6 +194,7 @@ struct SequencerToolSettings *SEQ_tool_settings_copy(struct SequencerToolSetting struct Editing *BKE_sequencer_editing_get(struct Scene *scene, bool alloc); struct Editing *BKE_sequencer_editing_ensure(struct Scene *scene); void BKE_sequencer_editing_free(struct Scene *scene, const bool do_id_user); +struct ListBase *SEQ_active_seqbase_get(const struct Editing *ed); void BKE_sequencer_sort(struct Scene *scene); struct Sequence *BKE_sequencer_from_elem(ListBase *seqbase, struct StripElem *se); struct Sequence *BKE_sequencer_active_get(struct Scene *scene); diff --git a/source/blender/sequencer/intern/sequencer.c b/source/blender/sequencer/intern/sequencer.c index 82971a30c31..87b608ef141 100644 --- a/source/blender/sequencer/intern/sequencer.c +++ b/source/blender/sequencer/intern/sequencer.c @@ -327,6 +327,20 @@ void SEQ_tool_settings_fit_method_set(Scene *scene, eSeqImageFitMethod fit_metho tool_settings->fit_method = fit_method; } +/** + * Get seqbase that is being viewed currently. This can be main seqbase or meta strip seqbase + * + * \param ed: sequence editor data + * \return pointer to active seqbase. returns NULL if ed is NULL + */ +ListBase *SEQ_active_seqbase_get(const Editing *ed) +{ + if (ed == NULL) { + return NULL; + } + + return ed->seqbasep; +} /** \} */ /* -------------------------------------------------------------------- */ diff --git a/source/blender/sequencer/intern/strip_time.c b/source/blender/sequencer/intern/strip_time.c index 015d81cc217..d9074b2a683 100644 --- a/source/blender/sequencer/intern/strip_time.c +++ b/source/blender/sequencer/intern/strip_time.c @@ -361,28 +361,26 @@ float BKE_sequence_get_fps(Scene *scene, Sequence *seq) */ void SEQ_timeline_boundbox(const Scene *scene, const ListBase *seqbase, rctf *rect) { - float min[2], max[2]; - min[0] = scene->r.sfra; - max[0] = scene->r.efra + 1; - min[1] = 0.0; - max[1] = 8.0; + rect->xmin = scene->r.sfra; + rect->xmax = scene->r.efra + 1; + rect->ymin = 0.0f; + rect->ymax = 8.0f; + + if (seqbase == NULL) { + return; + } LISTBASE_FOREACH (Sequence *, seq, seqbase) { - if (min[0] > seq->startdisp - 1) { - min[0] = seq->startdisp - 1; + if (rect->xmin > seq->startdisp - 1) { + rect->xmin = seq->startdisp - 1; } - if (max[0] < seq->enddisp + 1) { - max[0] = seq->enddisp + 1; + if (rect->xmax < seq->enddisp + 1) { + rect->xmax = seq->enddisp + 1; } - if (max[1] < seq->machine + 2) { - max[1] = seq->machine + 2; + if (rect->ymax < seq->machine + 2) { + rect->ymax = seq->machine + 2; } } - - rect->xmin = min[0]; - rect->xmax = max[0]; - rect->ymin = min[1]; - rect->ymax = max[1]; } /** -- cgit v1.2.3 From 8df6589585a19efb7c9515bc40b81a55d43b3c9a Mon Sep 17 00:00:00 2001 From: Richard Antalik Date: Thu, 17 Dec 2020 02:32:24 +0100 Subject: VSE: Fix crash when adding image strip Crash happens when using relative path to image in operator properties and checking image dimensions by loading image with `IMB_loadiffname()` Ensure path is absolute. --- source/blender/sequencer/intern/strip_add.c | 1 + 1 file changed, 1 insertion(+) diff --git a/source/blender/sequencer/intern/strip_add.c b/source/blender/sequencer/intern/strip_add.c index 9c9d51e9286..e56dcf888a7 100644 --- a/source/blender/sequencer/intern/strip_add.c +++ b/source/blender/sequencer/intern/strip_add.c @@ -121,6 +121,7 @@ Sequence *BKE_sequencer_add_image_strip(bContext *C, ListBase *seqbasep, SeqLoad char file_path[FILE_MAX]; BLI_join_dirfile(file_path, sizeof(file_path), seq_load->path, seq_load->name); + BLI_path_abs(file_path, BKE_main_blendfile_path(CTX_data_main(C))); ImBuf *ibuf = IMB_loadiffname(file_path, IB_rect, seq->strip->colorspace_settings.name); if (ibuf != NULL) { SEQ_set_scale_to_fit(seq, ibuf->x, ibuf->y, scene->r.xsch, scene->r.ysch, seq_load->fit_method); -- cgit v1.2.3 From 7e535499d5f691876a50aede97e52cbb07c3b636 Mon Sep 17 00:00:00 2001 From: Ray Molenkamp Date: Wed, 16 Dec 2020 21:03:42 -0700 Subject: Clean-up: Fix build warning with MSVC Callback function was using int while update_render_passes_cb_t was using eNodeSocketDatatype leading to a build warning about different argument types with MSVC. --- source/blender/blenkernel/intern/layer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c index 8a699e31f37..fbad0d920ed 100644 --- a/source/blender/blenkernel/intern/layer.c +++ b/source/blender/blenkernel/intern/layer.c @@ -2054,7 +2054,7 @@ static void bke_view_layer_verify_aov_cb(void *userdata, const char *name, int UNUSED(channels), const char *UNUSED(chanid), - int UNUSED(type)) + eNodeSocketDatatype UNUSED(type)) { GHash *name_count = userdata; void **value_p; -- cgit v1.2.3 From 6203a3ee684d704f2270edde4df80e2549d1a38d Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Thu, 17 Dec 2020 11:20:12 +0100 Subject: Fix T83878: Crash right-clicking in Asset Browser with no asset active Data of the File Browser context callback needs to be validated and return `CTX_RESULT_NO_DATA` if the context member is valid but not set in the current context. --- source/blender/editors/space_file/space_file.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c index 5bd7f6c17f6..774dc54700c 100644 --- a/source/blender/editors/space_file/space_file.c +++ b/source/blender/editors/space_file/space_file.c @@ -803,16 +803,25 @@ static int /*eContextResult*/ file_context(const bContext *C, if (CTX_data_equals(member, "active_file")) { FileDirEntry *file = filelist_file(sfile->files, params->active_file); + if (file == NULL) { + return CTX_RESULT_NO_DATA; + } + CTX_data_pointer_set(result, &screen->id, &RNA_FileSelectEntry, file); return CTX_RESULT_OK; } if (CTX_data_equals(member, "id")) { const FileDirEntry *file = filelist_file(sfile->files, params->active_file); + if (file == NULL) { + return CTX_RESULT_NO_DATA; + } ID *id = filelist_file_get_id(file); - if (id) { - CTX_data_id_pointer_set(result, id); + if (id == NULL) { + return CTX_RESULT_NO_DATA; } + + CTX_data_id_pointer_set(result, id); return CTX_RESULT_OK; } -- cgit v1.2.3 From 2945c1e3e55ee12c90464246977de17d28870eb8 Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Thu, 17 Dec 2020 11:39:45 +0100 Subject: Fix asset data-block name button not showing up in custom repositories The Python syntax was wrong, as noted by Campbell in 0ae15e68c785. --- release/scripts/startup/bl_ui/space_filebrowser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/release/scripts/startup/bl_ui/space_filebrowser.py b/release/scripts/startup/bl_ui/space_filebrowser.py index 58a4269ab96..98b155d8a21 100644 --- a/release/scripts/startup/bl_ui/space_filebrowser.py +++ b/release/scripts/startup/bl_ui/space_filebrowser.py @@ -593,7 +593,7 @@ class ASSETBROWSER_PT_metadata(asset_utils.AssetBrowserPanel, Panel): return # If the active file is an ID, use its name directly so renaming is possible from right here. - layout.prop(context.id if not None else active_file, "name", text="") + layout.prop(context.id if context.id is not None else active_file, "name", text="") class ASSETBROWSER_PT_metadata_preview(asset_utils.AssetMetaDataPanel, Panel): -- cgit v1.2.3 From 0eedba328df3cbc326900c34cdfc39b8554ad5ec Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Thu, 17 Dec 2020 11:55:45 +0100 Subject: Geometry Nodes: add Attribute Color Ramp node Differential Revision: https://developer.blender.org/D9861 Ref T82585. --- release/scripts/startup/nodeitems_builtins.py | 1 + source/blender/blenkernel/BKE_node.h | 1 + source/blender/blenkernel/intern/node.c | 1 + source/blender/editors/space_node/drawnode.c | 10 ++ source/blender/makesdna/DNA_node_types.h | 4 + source/blender/makesrna/intern/rna_nodetree.c | 12 +++ source/blender/nodes/CMakeLists.txt | 1 + source/blender/nodes/NOD_geometry.h | 1 + source/blender/nodes/NOD_static_types.h | 1 + .../nodes/node_geo_attribute_color_ramp.cc | 107 +++++++++++++++++++++ 10 files changed, 139 insertions(+) create mode 100644 source/blender/nodes/geometry/nodes/node_geo_attribute_color_ramp.cc diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py index 484f0b12400..c3ab1b3db97 100644 --- a/release/scripts/startup/nodeitems_builtins.py +++ b/release/scripts/startup/nodeitems_builtins.py @@ -485,6 +485,7 @@ geometry_node_categories = [ NodeItem("GeometryNodeAttributeMath"), NodeItem("GeometryNodeAttributeFill"), NodeItem("GeometryNodeAttributeMix"), + NodeItem("GeometryNodeAttributeColorRamp"), ]), GeometryNodeCategory("GEO_COLOR", "Color", items=[ NodeItem("ShaderNodeValToRGB"), diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index f8ce364d694..5f69fc397e8 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -1352,6 +1352,7 @@ int ntreeTexExecTree(struct bNodeTree *ntree, #define GEO_NODE_JOIN_GEOMETRY 1010 #define GEO_NODE_ATTRIBUTE_FILL 1011 #define GEO_NODE_ATTRIBUTE_MIX 1012 +#define GEO_NODE_ATTRIBUTE_COLOR_RAMP 1013 /** \} */ diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c index 06ff7c2e65c..415eb14be66 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -4741,6 +4741,7 @@ static void registerGeometryNodes(void) register_node_type_geo_attribute_math(); register_node_type_geo_join_geometry(); register_node_type_geo_attribute_mix(); + register_node_type_geo_attribute_color_ramp(); } static void registerFunctionNodes(void) diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index 2857c08cad6..45f3b6cf9c9 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -3215,6 +3215,13 @@ static void node_geometry_buts_attribute_point_distribute(uiLayout *layout, uiItemR(layout, ptr, "distribute_method", DEFAULT_FLAGS, "", ICON_NONE); } +static void node_geometry_buts_attribute_color_ramp(uiLayout *layout, + bContext *UNUSED(C), + PointerRNA *ptr) +{ + uiTemplateColorRamp(layout, ptr, "color_ramp", 0); +} + static void node_geometry_set_butfunc(bNodeType *ntype) { switch (ntype->type) { @@ -3245,6 +3252,9 @@ static void node_geometry_set_butfunc(bNodeType *ntype) case GEO_NODE_POINT_DISTRIBUTE: ntype->draw_buttons = node_geometry_buts_attribute_point_distribute; break; + case GEO_NODE_ATTRIBUTE_COLOR_RAMP: + ntype->draw_buttons = node_geometry_buts_attribute_color_ramp; + break; } } diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index 34a5372892c..7ad339c66af 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -1084,6 +1084,10 @@ typedef struct NodeAttributeMix { uint8_t input_type_b; } NodeAttributeMix; +typedef struct NodeAttributeColorRamp { + ColorBand color_ramp; +} NodeAttributeColorRamp; + /* script node mode */ #define NODE_SCRIPT_INTERNAL 0 #define NODE_SCRIPT_EXTERNAL 1 diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 4cd5b45ce78..d4ac3d1b084 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -8507,6 +8507,18 @@ static void def_geo_point_distribute(StructRNA *srna) RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); } +static void def_geo_attribute_color_ramp(StructRNA *srna) +{ + PropertyRNA *prop; + + RNA_def_struct_sdna_from(srna, "NodeAttributeColorRamp", "storage"); + + prop = RNA_def_property(srna, "color_ramp", PROP_POINTER, PROP_NONE); + RNA_def_property_struct_type(prop, "ColorRamp"); + RNA_def_property_ui_text(prop, "Color Ramp", ""); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); +} + /* -------------------------------------------------------------------------- */ static void rna_def_shader_node(BlenderRNA *brna) diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt index 46536903d55..bc0e7972bcb 100644 --- a/source/blender/nodes/CMakeLists.txt +++ b/source/blender/nodes/CMakeLists.txt @@ -138,6 +138,7 @@ set(SRC function/nodes/node_fn_switch.cc function/node_function_util.cc + geometry/nodes/node_geo_attribute_color_ramp.cc geometry/nodes/node_geo_attribute_fill.cc geometry/nodes/node_geo_attribute_math.cc geometry/nodes/node_geo_attribute_randomize.cc diff --git a/source/blender/nodes/NOD_geometry.h b/source/blender/nodes/NOD_geometry.h index 5ac4af9fc14..f1cd55ce048 100644 --- a/source/blender/nodes/NOD_geometry.h +++ b/source/blender/nodes/NOD_geometry.h @@ -39,6 +39,7 @@ void register_node_type_geo_attribute_randomize(void); void register_node_type_geo_attribute_math(void); void register_node_type_geo_join_geometry(void); void register_node_type_geo_attribute_mix(void); +void register_node_type_geo_attribute_color_ramp(void); #ifdef __cplusplus } diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h index 68efb0806fd..662952abb59 100644 --- a/source/blender/nodes/NOD_static_types.h +++ b/source/blender/nodes/NOD_static_types.h @@ -279,6 +279,7 @@ DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_MATH, def_geo_attribute_math, "ATTRIBUT DefNode(GeometryNode, GEO_NODE_JOIN_GEOMETRY, 0, "JOIN_GEOMETRY", JoinGeometry, "Join Geometry", "") DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_FILL, def_geo_attribute_fill, "ATTRIBUTE_FILL", AttributeFill, "Attribute Fill", "") DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_MIX, def_geo_attribute_mix, "ATTRIBUTE_MIX", AttributeMix, "Attribute Mix", "") +DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_COLOR_RAMP, def_geo_attribute_color_ramp, "ATTRIBUTE_COLOR_RAMP", AttributeColorRamp, "Attribute Color Ramp", "") /* undefine macros */ #undef DefNode diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_color_ramp.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_color_ramp.cc new file mode 100644 index 00000000000..3f7023ba88f --- /dev/null +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_color_ramp.cc @@ -0,0 +1,107 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "node_geometry_util.hh" + +#include "BKE_colorband.h" + +static bNodeSocketTemplate geo_node_attribute_color_ramp_in[] = { + {SOCK_GEOMETRY, N_("Geometry")}, + {SOCK_STRING, N_("Attribute")}, + {SOCK_STRING, N_("Result")}, + {-1, ""}, +}; + +static bNodeSocketTemplate geo_node_attribute_color_ramp_out[] = { + {SOCK_GEOMETRY, N_("Geometry")}, + {-1, ""}, +}; + +namespace blender::nodes { + +static void execute_on_component(const GeoNodeExecParams ¶ms, GeometryComponent &component) +{ + const bNode &bnode = params.node(); + NodeAttributeColorRamp *node_storage = (NodeAttributeColorRamp *)bnode.storage; + + const std::string result_name = params.get_input("Result"); + /* Once we support more domains at the user level, we have to decide how the result domain is + * choosen. */ + const AttributeDomain result_domain = ATTR_DOMAIN_POINT; + const CustomDataType result_type = CD_PROP_COLOR; + + WriteAttributePtr attribute_result = component.attribute_try_ensure_for_write( + result_name, result_domain, result_type); + if (!attribute_result) { + return; + } + + Color4fWriteAttribute attribute_out = std::move(attribute_result); + + const std::string input_name = params.get_input("Attribute"); + FloatReadAttribute attribute_in = component.attribute_get_for_read( + input_name, result_domain, 0.0f); + + Span data_in = attribute_in.get_span(); + MutableSpan data_out = attribute_out.get_span(); + + ColorBand *color_ramp = &node_storage->color_ramp; + for (const int i : data_in.index_range()) { + BKE_colorband_evaluate(color_ramp, data_in[i], data_out[i]); + } + + attribute_out.apply_span(); +} + +static void geo_node_attribute_color_ramp_exec(GeoNodeExecParams params) +{ + GeometrySet geometry_set = params.extract_input("Geometry"); + + if (geometry_set.has()) { + execute_on_component(params, geometry_set.get_component_for_write()); + } + if (geometry_set.has()) { + execute_on_component(params, geometry_set.get_component_for_write()); + } + + params.set_output("Geometry", std::move(geometry_set)); +} + +static void geo_node_attribute_color_ramp_init(bNodeTree *UNUSED(ntree), bNode *node) +{ + NodeAttributeColorRamp *node_storage = (NodeAttributeColorRamp *)MEM_callocN( + sizeof(NodeAttributeColorRamp), __func__); + BKE_colorband_init(&node_storage->color_ramp, true); + node->storage = node_storage; +} + +} // namespace blender::nodes + +void register_node_type_geo_attribute_color_ramp() +{ + static bNodeType ntype; + + geo_node_type_base( + &ntype, GEO_NODE_ATTRIBUTE_COLOR_RAMP, "Attribute Color Ramp", NODE_CLASS_ATTRIBUTE, 0); + node_type_socket_templates( + &ntype, geo_node_attribute_color_ramp_in, geo_node_attribute_color_ramp_out); + node_type_storage( + &ntype, "NodeAttributeColorRamp", node_free_standard_storage, node_copy_standard_storage); + node_type_init(&ntype, blender::nodes::geo_node_attribute_color_ramp_init); + node_type_size_preset(&ntype, NODE_SIZE_LARGE); + ntype.geometry_node_execute = blender::nodes::geo_node_attribute_color_ramp_exec; + nodeRegisterType(&ntype); +} -- cgit v1.2.3 From cf2ebaf27c78b3f8f79d9d014ca2261228f87e70 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Thu, 17 Dec 2020 12:03:34 +0100 Subject: Fix T83875: Converting Proxy to override crashes blender. Some weird proxies apparently can have a local collection instancing... Not sure this is even really valid for proxies, but in any case we cannot override that, just detect and properly cancel the operation then. Should be backported to 2.91.1 should we do it. --- source/blender/blenkernel/intern/lib_override.c | 6 ++++++ source/blender/editors/object/object_relations.c | 11 ++++++++++- source/blender/editors/space_outliner/outliner_tools.c | 13 ++++++++++--- 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/source/blender/blenkernel/intern/lib_override.c b/source/blender/blenkernel/intern/lib_override.c index 11544d83ba9..cabc80d4024 100644 --- a/source/blender/blenkernel/intern/lib_override.c +++ b/source/blender/blenkernel/intern/lib_override.c @@ -702,6 +702,12 @@ bool BKE_lib_override_library_proxy_convert(Main *bmain, &ob_proxy->proxy->id; ID *id_reference = is_override_instancing_object ? &ob_proxy_group->id : &ob_proxy->id; + /* In some cases the instance collection of a proxy object may be local (see e.g. T83875). Not + * sure this is a valid state, but for now just abort the overriding process. */ + if (!ID_IS_OVERRIDABLE_LIBRARY(id_root)) { + return false; + } + /* We manually convert the proxy object into a library override, further override handling will * then be handled by `BKE_lib_override_library_create()` just as for a regular override * creation. diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index 8ec9f7af184..5caa7c71e83 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -2527,7 +2527,7 @@ static bool convert_proxy_to_override_poll(bContext *C) return obact != NULL && obact->proxy != NULL; } -static int convert_proxy_to_override_exec(bContext *C, wmOperator *UNUSED(op)) +static int convert_proxy_to_override_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); @@ -2541,6 +2541,15 @@ static int convert_proxy_to_override_exec(bContext *C, wmOperator *UNUSED(op)) const bool success = BKE_lib_override_library_proxy_convert(bmain, scene, view_layer, ob_proxy); + if (!success) { + BKE_reportf( + op->reports, + RPT_ERROR_INVALID_INPUT, + "Could not create a library override from proxy '%s' (might use already local data?)", + ob_proxy->id.name + 2); + return OPERATOR_CANCELLED; + } + /* Remove the instance empty from this scene, the items now have an overridden collection * instead. */ if (success && is_override_instancing_object) { diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c index e4c3ebfdff5..492fc5c23bc 100644 --- a/source/blender/editors/space_outliner/outliner_tools.c +++ b/source/blender/editors/space_outliner/outliner_tools.c @@ -737,7 +737,7 @@ static void id_local_fn(bContext *C, } static void object_proxy_to_override_convert_fn(bContext *C, - ReportList *UNUSED(reports), + ReportList *reports, Scene *UNUSED(scene), TreeElement *UNUSED(te), TreeStoreElem *UNUSED(tsep), @@ -754,8 +754,15 @@ static void object_proxy_to_override_convert_fn(bContext *C, return; } - BKE_lib_override_library_proxy_convert( - CTX_data_main(C), scene, CTX_data_view_layer(C), ob_proxy); + if (!BKE_lib_override_library_proxy_convert( + CTX_data_main(C), scene, CTX_data_view_layer(C), ob_proxy)) { + BKE_reportf( + reports, + RPT_ERROR_INVALID_INPUT, + "Could not create a library override from proxy '%s' (might use already local data?)", + ob_proxy->id.name + 2); + return; + } DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS | ID_RECALC_COPY_ON_WRITE); WM_event_add_notifier(C, NC_WINDOW, NULL); -- cgit v1.2.3