Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorJacques Lucke <mail@jlucke.com>2019-11-05 00:09:23 +0300
committerJacques Lucke <mail@jlucke.com>2019-11-05 00:09:23 +0300
commit62cd4cca56fc2b13f9573430513a3542afaccf7b (patch)
treea2077627f501f0e91c2e7f0add213c62b54c13b2 /source
parentf52e43554f58a2db9b62231a19bbc7be899eabab (diff)
parenta63b896055c96c422e8d9d547022188729922500 (diff)
Merge branch 'functions' into functions-experimental-refactor
Diffstat (limited to 'source')
-rw-r--r--source/blender/blenkernel/BKE_idprop.h1
-rw-r--r--source/blender/blenkernel/BKE_sequencer.h2
-rw-r--r--source/blender/blenkernel/intern/brush.c1
-rw-r--r--source/blender/blenkernel/intern/idprop.c6
-rw-r--r--source/blender/blenkernel/intern/layer.c2
-rw-r--r--source/blender/blenkernel/intern/sequencer.c17
-rw-r--r--source/blender/blenlib/BLI_task.h40
-rw-r--r--source/blender/blenlib/intern/task.c362
-rw-r--r--source/blender/blenloader/intern/versioning_280.c5
-rw-r--r--source/blender/blenloader/intern/versioning_defaults.c3
-rw-r--r--source/blender/blenloader/intern/versioning_userdef.c1
-rw-r--r--source/blender/compositor/operations/COM_OpenCLKernels.cl16
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.cc83
-rw-r--r--source/blender/draw/engines/eevee/eevee_materials.c56
-rw-r--r--source/blender/draw/engines/eevee/eevee_private.h13
-rw-r--r--source/blender/draw/engines/eevee/eevee_shadows.c6
-rw-r--r--source/blender/draw/engines/eevee/eevee_volumes.c5
-rw-r--r--source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl1
-rw-r--r--source/blender/draw/engines/eevee/shaders/common_uniforms_lib.glsl4
-rw-r--r--source/blender/draw/engines/eevee/shaders/default_frag.glsl5
-rw-r--r--source/blender/draw/engines/eevee/shaders/prepass_frag.glsl7
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_draw_utils.c13
-rw-r--r--source/blender/draw/intern/draw_armature.c44
-rw-r--r--source/blender/draw/modes/object_mode.c45
-rw-r--r--source/blender/draw/modes/sculpt_mode.c2
-rw-r--r--source/blender/editors/datafiles/CMakeLists.txt2
-rw-r--r--source/blender/editors/gpencil/gpencil_edit.c1
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c7
-rw-r--r--source/blender/editors/gpencil/gpencil_utils.c9
-rw-r--r--source/blender/editors/include/ED_gpencil.h4
-rw-r--r--source/blender/editors/include/ED_mask.h30
-rw-r--r--source/blender/editors/include/ED_screen.h9
-rw-r--r--source/blender/editors/include/ED_transform_snap_object_context.h2
-rw-r--r--source/blender/editors/include/UI_icons.h16
-rw-r--r--source/blender/editors/interface/interface_widgets.c33
-rw-r--r--source/blender/editors/mask/mask_add.c227
-rw-r--r--source/blender/editors/mask/mask_draw.c118
-rw-r--r--source/blender/editors/mask/mask_edit.c10
-rw-r--r--source/blender/editors/mask/mask_editaction.c183
-rw-r--r--source/blender/editors/mask/mask_intern.h10
-rw-r--r--source/blender/editors/mask/mask_ops.c229
-rw-r--r--source/blender/editors/mask/mask_relationships.c24
-rw-r--r--source/blender/editors/mask/mask_select.c144
-rw-r--r--source/blender/editors/mask/mask_shapekey.c179
-rw-r--r--source/blender/editors/mesh/editmesh_extrude_spin.c5
-rw-r--r--source/blender/editors/mesh/editmesh_mask_extract.c5
-rw-r--r--source/blender/editors/mesh/editmesh_polybuild.c2
-rw-r--r--source/blender/editors/render/render_view.c5
-rw-r--r--source/blender/editors/screen/area.c63
-rw-r--r--source/blender/editors/screen/screen_edit.c27
-rw-r--r--source/blender/editors/sculpt_paint/paint_image_2d.c7
-rw-r--r--source/blender/editors/sculpt_paint/paint_vertex.c4
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_undo.c7
-rw-r--r--source/blender/editors/space_clip/clip_ops.c2
-rw-r--r--source/blender/editors/space_file/filelist.c2
-rw-r--r--source/blender/editors/space_graph/space_graph.c6
-rw-r--r--source/blender/editors/space_image/image_draw.c8
-rw-r--r--source/blender/editors/space_image/image_ops.c7
-rw-r--r--source/blender/editors/space_image/image_undo.c20
-rw-r--r--source/blender/editors/space_info/info_ops.c1
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.c77
-rw-r--r--source/blender/editors/space_outliner/outliner_edit.c6
-rw-r--r--source/blender/editors/space_outliner/outliner_intern.h30
-rw-r--r--source/blender/editors/space_outliner/outliner_select.c133
-rw-r--r--source/blender/editors/space_outliner/outliner_sync.c17
-rw-r--r--source/blender/editors/space_outliner/outliner_utils.c43
-rw-r--r--source/blender/editors/space_sequencer/sequencer_draw.c4
-rw-r--r--source/blender/editors/space_sequencer/sequencer_edit.c75
-rw-r--r--source/blender/editors/space_sequencer/sequencer_intern.h4
-rw-r--r--source/blender/editors/space_sequencer/sequencer_ops.c4
-rw-r--r--source/blender/editors/space_sequencer/sequencer_select.c86
-rw-r--r--source/blender/editors/space_view3d/view3d_gizmo_ruler.c4
-rw-r--r--source/blender/editors/transform/transform_snap.c4
-rw-r--r--source/blender/editors/transform/transform_snap_object.c186
-rw-r--r--source/blender/imbuf/intern/indexer.c16
-rw-r--r--source/blender/makesdna/DNA_brush_defaults.h1
-rw-r--r--source/blender/makesdna/DNA_brush_types.h10
-rw-r--r--source/blender/makesdna/DNA_gpencil_types.h9
-rw-r--r--source/blender/makesdna/DNA_modifier_types.h30
-rw-r--r--source/blender/makesdna/DNA_scene_types.h1
-rw-r--r--source/blender/makesdna/DNA_screen_types.h5
-rw-r--r--source/blender/makesdna/DNA_space_types.h16
-rw-r--r--source/blender/makesrna/intern/rna_brush.c5
-rw-r--r--source/blender/makesrna/intern/rna_mesh.c8
-rw-r--r--source/blender/makesrna/intern/rna_modifier.c78
-rw-r--r--source/blender/makesrna/intern/rna_packedfile.c1
-rw-r--r--source/blender/makesrna/intern/rna_scene.c5
-rw-r--r--source/blender/makesrna/intern/rna_sequencer.c17
-rw-r--r--source/blender/makesrna/intern/rna_userdef.c6
-rw-r--r--source/blender/modifiers/CMakeLists.txt3
-rw-r--r--source/blender/modifiers/intern/MOD_solidify.c933
-rw-r--r--source/blender/modifiers/intern/MOD_solidify_extrude.c1105
-rw-r--r--source/blender/modifiers/intern/MOD_solidify_nonmanifold.c2268
-rw-r--r--source/blender/modifiers/intern/MOD_solidify_util.h34
94 files changed, 5381 insertions, 1991 deletions
diff --git a/source/blender/blenkernel/BKE_idprop.h b/source/blender/blenkernel/BKE_idprop.h
index 0eb8df1b19d..94c2a94d420 100644
--- a/source/blender/blenkernel/BKE_idprop.h
+++ b/source/blender/blenkernel/BKE_idprop.h
@@ -136,6 +136,7 @@ struct IDProperty *IDP_New(const char type,
void IDP_FreePropertyContent_ex(struct IDProperty *prop, const bool do_id_user);
void IDP_FreePropertyContent(struct IDProperty *prop);
+void IDP_FreeProperty_ex(IDProperty *prop, const bool do_id_user);
void IDP_FreeProperty(struct IDProperty *prop);
void IDP_ClearProperty(IDProperty *prop);
diff --git a/source/blender/blenkernel/BKE_sequencer.h b/source/blender/blenkernel/BKE_sequencer.h
index a5b223a73f2..c1bb60737ff 100644
--- a/source/blender/blenkernel/BKE_sequencer.h
+++ b/source/blender/blenkernel/BKE_sequencer.h
@@ -289,7 +289,7 @@ bool BKE_sequencer_input_have_to_preprocess(const SeqRenderData *context,
struct Sequence *seq,
float cfra);
-void BKE_sequencer_proxy_rebuild_context(struct Main *bmain,
+bool BKE_sequencer_proxy_rebuild_context(struct Main *bmain,
struct Depsgraph *depsgraph,
struct Scene *scene,
struct Sequence *seq,
diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c
index fe740f4898e..73b7b1e2858 100644
--- a/source/blender/blenkernel/intern/brush.c
+++ b/source/blender/blenkernel/intern/brush.c
@@ -84,6 +84,7 @@ static void brush_defaults(Brush *brush)
FROM_DEFAULT(normal_weight);
FROM_DEFAULT(fill_threshold);
FROM_DEFAULT(flag);
+ FROM_DEFAULT(sampling_flag);
FROM_DEFAULT_PTR(rgb);
FROM_DEFAULT_PTR(secondary_rgb);
FROM_DEFAULT(spacing);
diff --git a/source/blender/blenkernel/intern/idprop.c b/source/blender/blenkernel/intern/idprop.c
index 016da52252a..1125047be32 100644
--- a/source/blender/blenkernel/intern/idprop.c
+++ b/source/blender/blenkernel/intern/idprop.c
@@ -1085,6 +1085,12 @@ void IDP_FreePropertyContent(IDProperty *prop)
IDP_FreePropertyContent_ex(prop, true);
}
+void IDP_FreeProperty_ex(IDProperty *prop, const bool do_id_user)
+{
+ IDP_FreePropertyContent_ex(prop, do_id_user);
+ MEM_freeN(prop);
+}
+
void IDP_FreeProperty(IDProperty *prop)
{
IDP_FreePropertyContent(prop);
diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c
index f12999b033d..34c1c5ecab4 100644
--- a/source/blender/blenkernel/intern/layer.c
+++ b/source/blender/blenkernel/intern/layer.c
@@ -239,7 +239,7 @@ void BKE_view_layer_free_ex(ViewLayer *view_layer, const bool do_id_user)
BKE_freestyle_config_free(&view_layer->freestyle_config, do_id_user);
if (view_layer->id_properties) {
- IDP_FreeProperty(view_layer->id_properties);
+ IDP_FreeProperty_ex(view_layer->id_properties, do_id_user);
}
MEM_SAFE_FREE(view_layer->object_bases_array);
diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c
index 26dd9aab511..b99d6e1684a 100644
--- a/source/blender/blenkernel/intern/sequencer.c
+++ b/source/blender/blenkernel/intern/sequencer.c
@@ -2093,7 +2093,7 @@ static int seq_proxy_context_count(Sequence *seq, Scene *scene)
return num_views;
}
-void BKE_sequencer_proxy_rebuild_context(Main *bmain,
+bool BKE_sequencer_proxy_rebuild_context(Main *bmain,
Depsgraph *depsgraph,
Scene *scene,
Sequence *seq,
@@ -2107,11 +2107,11 @@ void BKE_sequencer_proxy_rebuild_context(Main *bmain,
int i;
if (!seq->strip || !seq->strip->proxy) {
- return;
+ return true;
}
if (!(seq->flag & SEQ_USE_PROXY)) {
- return;
+ return true;
}
num_files = seq_proxy_context_count(seq, scene);
@@ -2138,9 +2138,6 @@ void BKE_sequencer_proxy_rebuild_context(Main *bmain,
context->view_id = i; /* only for images */
- link = BLI_genericNodeN(context);
- BLI_addtail(queue, link);
-
if (nseq->type == SEQ_TYPE_MOVIE) {
StripAnim *sanim;
@@ -2155,8 +2152,16 @@ void BKE_sequencer_proxy_rebuild_context(Main *bmain,
context->overwrite,
file_list);
}
+ if (!context->index_context) {
+ MEM_freeN(context);
+ return false;
+ }
}
+
+ link = BLI_genericNodeN(context);
+ BLI_addtail(queue, link);
}
+ return true;
}
void BKE_sequencer_proxy_rebuild(SeqIndexBuildContext *context,
diff --git a/source/blender/blenlib/BLI_task.h b/source/blender/blenlib/BLI_task.h
index 568d6c9a84a..7ef5e518cc8 100644
--- a/source/blender/blenlib/BLI_task.h
+++ b/source/blender/blenlib/BLI_task.h
@@ -198,11 +198,45 @@ void BLI_task_parallel_range(const int start,
TaskParallelRangeFunc func,
const TaskParallelSettings *settings);
-typedef void (*TaskParallelListbaseFunc)(void *userdata, struct Link *iter, int index);
+/* This data is shared between all tasks, its access needs thread lock or similar protection. */
+typedef struct TaskParallelIteratorStateShared {
+ /* Maximum amount of items to acquire at once. */
+ int chunk_size;
+ /* Next item to be acquired. */
+ void *next_item;
+ /* Index of the next item to be acquired. */
+ int next_index;
+ /* Indicates that end of iteration has been reached. */
+ bool is_finished;
+ /* Helper lock to protect access to this data in iterator getter callback,
+ * can be ignored (if the callback implements its own protection system, using atomics e.g.).
+ * Will be NULL when iterator is actually processed in a single thread. */
+ SpinLock *spin_lock;
+} TaskParallelIteratorStateShared;
+
+typedef void (*TaskParallelIteratorIterFunc)(void *__restrict userdata,
+ const TaskParallelTLS *__restrict tls,
+ void **r_next_item,
+ int *r_next_index,
+ bool *r_do_abort);
+
+typedef void (*TaskParallelIteratorFunc)(void *__restrict userdata,
+ void *item,
+ int index,
+ const TaskParallelTLS *__restrict tls);
+
+void BLI_task_parallel_iterator(void *userdata,
+ TaskParallelIteratorIterFunc iter_func,
+ void *init_item,
+ const int init_index,
+ const int tot_items,
+ TaskParallelIteratorFunc func,
+ const TaskParallelSettings *settings);
+
void BLI_task_parallel_listbase(struct ListBase *listbase,
void *userdata,
- TaskParallelListbaseFunc func,
- const bool use_threading);
+ TaskParallelIteratorFunc func,
+ const TaskParallelSettings *settings);
typedef struct MempoolIterData MempoolIterData;
typedef void (*TaskParallelMempoolFunc)(void *userdata, MempoolIterData *iter);
diff --git a/source/blender/blenlib/intern/task.c b/source/blender/blenlib/intern/task.c
index 6cdaec97d9a..bb69dc6452f 100644
--- a/source/blender/blenlib/intern/task.c
+++ b/source/blender/blenlib/intern/task.c
@@ -149,7 +149,7 @@ typedef struct TaskThreadLocalStorage {
* without "interrupting" for task execution.
*
* We try to accumulate as much tasks as possible in a local queue without
- * any locks first, and then we push all of them into a schedulers queue
+ * any locks first, and then we push all of them into a scheduler's queue
* from within a single mutex lock.
*/
bool do_delayed_push;
@@ -1052,14 +1052,20 @@ typedef struct ParallelRangeState {
int chunk_size;
} ParallelRangeState;
-BLI_INLINE void task_parallel_range_calc_chunk_size(const TaskParallelSettings *settings,
- const int num_tasks,
- ParallelRangeState *state)
+BLI_INLINE void task_parallel_calc_chunk_size(const TaskParallelSettings *settings,
+ const int tot_items,
+ int num_tasks,
+ int *r_chunk_size)
{
- const int tot_items = state->stop - state->start;
int chunk_size = 0;
- if (settings->min_iter_per_thread > 0) {
+ if (!settings->use_threading) {
+ /* Some users of this helper will still need a valid chunk size in case processing is not
+ * threaded. We can use a bigger one than in default threaded case then. */
+ chunk_size = 1024;
+ num_tasks = 1;
+ }
+ else if (settings->min_iter_per_thread > 0) {
/* Already set by user, no need to do anything here. */
chunk_size = settings->min_iter_per_thread;
}
@@ -1091,16 +1097,30 @@ BLI_INLINE void task_parallel_range_calc_chunk_size(const TaskParallelSettings *
BLI_assert(chunk_size > 0);
- switch (settings->scheduling_mode) {
- case TASK_SCHEDULING_STATIC:
- state->chunk_size = max_ii(chunk_size, tot_items / (num_tasks));
- break;
- case TASK_SCHEDULING_DYNAMIC:
- state->chunk_size = chunk_size;
- break;
+ if (tot_items > 0) {
+ switch (settings->scheduling_mode) {
+ case TASK_SCHEDULING_STATIC:
+ *r_chunk_size = max_ii(chunk_size, tot_items / num_tasks);
+ break;
+ case TASK_SCHEDULING_DYNAMIC:
+ *r_chunk_size = chunk_size;
+ break;
+ }
+ }
+ else {
+ /* If total amount of items is unknown, we can only use dynamic scheduling. */
+ *r_chunk_size = chunk_size;
}
}
+BLI_INLINE void task_parallel_range_calc_chunk_size(const TaskParallelSettings *settings,
+ const int num_tasks,
+ ParallelRangeState *state)
+{
+ task_parallel_calc_chunk_size(
+ settings, state->stop - state->start, num_tasks, &state->chunk_size);
+}
+
BLI_INLINE bool parallel_range_next_iter_get(ParallelRangeState *__restrict state,
int *__restrict iter,
int *__restrict count)
@@ -1256,77 +1276,239 @@ void BLI_task_parallel_range(const int start,
}
}
-#undef MALLOCA
-#undef MALLOCA_FREE
-
-typedef struct ParallelListbaseState {
+typedef struct TaskParallelIteratorState {
void *userdata;
- TaskParallelListbaseFunc func;
+ TaskParallelIteratorIterFunc iter_func;
+ TaskParallelIteratorFunc func;
+
+ /* *** Data used to 'acquire' chunks of items from the iterator. *** */
+ /* Common data also passed to the generator callback. */
+ TaskParallelIteratorStateShared iter_shared;
+ /* Total number of items. If unknown, set it to a negative number. */
+ int tot_items;
+} TaskParallelIteratorState;
+
+BLI_INLINE void task_parallel_iterator_calc_chunk_size(const TaskParallelSettings *settings,
+ const int num_tasks,
+ TaskParallelIteratorState *state)
+{
+ task_parallel_calc_chunk_size(
+ settings, state->tot_items, num_tasks, &state->iter_shared.chunk_size);
+}
- int chunk_size;
- int index;
- Link *link;
- SpinLock lock;
-} ParallelListState;
-
-BLI_INLINE Link *parallel_listbase_next_iter_get(ParallelListState *__restrict state,
- int *__restrict index,
- int *__restrict count)
+static void parallel_iterator_func_do(TaskParallelIteratorState *__restrict state,
+ void *userdata_chunk,
+ int threadid)
{
- int task_count = 0;
- BLI_spin_lock(&state->lock);
- Link *result = state->link;
- if (LIKELY(result != NULL)) {
- *index = state->index;
- while (state->link != NULL && task_count < state->chunk_size) {
- task_count++;
- state->link = state->link->next;
+ TaskParallelTLS tls = {
+ .thread_id = threadid,
+ .userdata_chunk = userdata_chunk,
+ };
+
+ void **current_chunk_items;
+ int *current_chunk_indices;
+ int current_chunk_size;
+
+ const size_t items_size = sizeof(*current_chunk_items) * (size_t)state->iter_shared.chunk_size;
+ const size_t indices_size = sizeof(*current_chunk_indices) *
+ (size_t)state->iter_shared.chunk_size;
+
+ current_chunk_items = MALLOCA(items_size);
+ current_chunk_indices = MALLOCA(indices_size);
+ current_chunk_size = 0;
+
+ for (bool do_abort = false; !do_abort;) {
+ if (state->iter_shared.spin_lock != NULL) {
+ BLI_spin_lock(state->iter_shared.spin_lock);
+ }
+
+ /* Get current status. */
+ int index = state->iter_shared.next_index;
+ void *item = state->iter_shared.next_item;
+ int i;
+
+ /* 'Acquire' a chunk of items from the iterator function. */
+ for (i = 0; i < state->iter_shared.chunk_size && !state->iter_shared.is_finished; i++) {
+ current_chunk_indices[i] = index;
+ current_chunk_items[i] = item;
+ state->iter_func(state->userdata, &tls, &item, &index, &state->iter_shared.is_finished);
+ }
+
+ /* Update current status. */
+ state->iter_shared.next_index = index;
+ state->iter_shared.next_item = item;
+ current_chunk_size = i;
+
+ do_abort = state->iter_shared.is_finished;
+
+ if (state->iter_shared.spin_lock != NULL) {
+ BLI_spin_unlock(state->iter_shared.spin_lock);
+ }
+
+ for (i = 0; i < current_chunk_size; ++i) {
+ state->func(state->userdata, current_chunk_items[i], current_chunk_indices[i], &tls);
}
- state->index += task_count;
}
- BLI_spin_unlock(&state->lock);
- *count = task_count;
- return result;
+
+ MALLOCA_FREE(current_chunk_items, items_size);
+ MALLOCA_FREE(current_chunk_indices, indices_size);
}
-static void parallel_listbase_func(TaskPool *__restrict pool,
- void *UNUSED(taskdata),
- int UNUSED(threadid))
+static void parallel_iterator_func(TaskPool *__restrict pool, void *userdata_chunk, int threadid)
{
- ParallelListState *__restrict state = BLI_task_pool_userdata(pool);
- Link *link;
- int index, count;
+ TaskParallelIteratorState *__restrict state = BLI_task_pool_userdata(pool);
- while ((link = parallel_listbase_next_iter_get(state, &index, &count)) != NULL) {
- for (int i = 0; i < count; i++) {
- state->func(state->userdata, link, index + i);
- link = link->next;
+ parallel_iterator_func_do(state, userdata_chunk, threadid);
+}
+
+static void task_parallel_iterator_no_threads(const TaskParallelSettings *settings,
+ TaskParallelIteratorState *state)
+{
+ /* Prepare user's TLS data. */
+ void *userdata_chunk = settings->userdata_chunk;
+ const size_t userdata_chunk_size = settings->userdata_chunk_size;
+ void *userdata_chunk_local = NULL;
+ const bool use_userdata_chunk = (userdata_chunk_size != 0) && (userdata_chunk != NULL);
+ if (use_userdata_chunk) {
+ userdata_chunk_local = MALLOCA(userdata_chunk_size);
+ memcpy(userdata_chunk_local, userdata_chunk, userdata_chunk_size);
+ }
+
+ /* Also marking it as non-threaded for the iterator callback. */
+ state->iter_shared.spin_lock = NULL;
+
+ parallel_iterator_func_do(state, userdata_chunk, 0);
+
+ if (use_userdata_chunk) {
+ if (settings->func_finalize != NULL) {
+ settings->func_finalize(state->userdata, userdata_chunk_local);
}
+ MALLOCA_FREE(userdata_chunk_local, userdata_chunk_size);
}
}
-static void task_parallel_listbase_no_threads(struct ListBase *listbase,
- void *userdata,
- TaskParallelListbaseFunc func)
+static void task_parallel_iterator_do(const TaskParallelSettings *settings,
+ TaskParallelIteratorState *state)
{
- int i = 0;
- for (Link *link = listbase->first; link != NULL; link = link->next, i++) {
- func(userdata, link, i);
+ TaskScheduler *task_scheduler = BLI_task_scheduler_get();
+ const int num_threads = BLI_task_scheduler_num_threads(task_scheduler);
+
+ task_parallel_iterator_calc_chunk_size(settings, num_threads, state);
+
+ if (!settings->use_threading) {
+ task_parallel_iterator_no_threads(settings, state);
+ return;
}
+
+ const int chunk_size = state->iter_shared.chunk_size;
+ const int tot_items = state->tot_items;
+ const size_t num_tasks = tot_items >= 0 ?
+ (size_t)min_ii(num_threads, state->tot_items / chunk_size) :
+ (size_t)num_threads;
+
+ BLI_assert(num_tasks > 0);
+ if (num_tasks == 1) {
+ task_parallel_iterator_no_threads(settings, state);
+ return;
+ }
+
+ SpinLock spin_lock;
+ BLI_spin_init(&spin_lock);
+ state->iter_shared.spin_lock = &spin_lock;
+
+ void *userdata_chunk = settings->userdata_chunk;
+ const size_t userdata_chunk_size = settings->userdata_chunk_size;
+ void *userdata_chunk_local = NULL;
+ void *userdata_chunk_array = NULL;
+ const bool use_userdata_chunk = (userdata_chunk_size != 0) && (userdata_chunk != NULL);
+
+ TaskPool *task_pool = BLI_task_pool_create_suspended(task_scheduler, state);
+
+ if (use_userdata_chunk) {
+ userdata_chunk_array = MALLOCA(userdata_chunk_size * num_tasks);
+ }
+
+ for (size_t i = 0; i < num_tasks; i++) {
+ if (use_userdata_chunk) {
+ userdata_chunk_local = (char *)userdata_chunk_array + (userdata_chunk_size * i);
+ memcpy(userdata_chunk_local, userdata_chunk, userdata_chunk_size);
+ }
+ /* Use this pool's pre-allocated tasks. */
+ BLI_task_pool_push_from_thread(task_pool,
+ parallel_iterator_func,
+ userdata_chunk_local,
+ false,
+ TASK_PRIORITY_HIGH,
+ task_pool->thread_id);
+ }
+
+ BLI_task_pool_work_and_wait(task_pool);
+ BLI_task_pool_free(task_pool);
+
+ if (use_userdata_chunk) {
+ if (settings->func_finalize != NULL) {
+ for (size_t i = 0; i < num_tasks; i++) {
+ userdata_chunk_local = (char *)userdata_chunk_array + (userdata_chunk_size * i);
+ settings->func_finalize(state->userdata, userdata_chunk_local);
+ }
+ }
+ MALLOCA_FREE(userdata_chunk_array, userdata_chunk_size * num_tasks);
+ }
+
+ BLI_spin_end(&spin_lock);
+ state->iter_shared.spin_lock = NULL;
}
-/* NOTE: The idea here is to compensate for rather measurable threading
- * overhead caused by fetching tasks. With too many CPU threads we are starting
- * to spend too much time in those overheads. */
-BLI_INLINE int task_parallel_listbasecalc_chunk_size(const int num_threads)
+/**
+ * This function allows to parallelize for loops using a generic iterator.
+ *
+ * \param userdata: Common userdata passed to all instances of \a func.
+ * \param iter_func: Callback function used to generate chunks of items.
+ * \param init_item: The initial item, if necessary (may be NULL if unused).
+ * \param init_index: The initial index.
+ * \param tot_items: The total amount of items to iterate over
+ * (if unkown, set it to a negative number).
+ * \param func: Callback function.
+ * \param settings: See public API doc of TaskParallelSettings for description of all settings.
+ *
+ * \note Static scheduling is only available when \a tot_items is >= 0.
+ */
+
+void BLI_task_parallel_iterator(void *userdata,
+ TaskParallelIteratorIterFunc iter_func,
+ void *init_item,
+ const int init_index,
+ const int tot_items,
+ TaskParallelIteratorFunc func,
+ const TaskParallelSettings *settings)
{
- if (num_threads > 32) {
- return 128;
- }
- else if (num_threads > 16) {
- return 64;
+ TaskParallelIteratorState state = {0};
+
+ state.tot_items = tot_items;
+ state.iter_shared.next_index = init_index;
+ state.iter_shared.next_item = init_item;
+ state.iter_shared.is_finished = false;
+ state.userdata = userdata;
+ state.iter_func = iter_func;
+ state.func = func;
+
+ task_parallel_iterator_do(settings, &state);
+}
+
+static void task_parallel_listbase_get(void *__restrict UNUSED(userdata),
+ const TaskParallelTLS *__restrict UNUSED(tls),
+ void **r_next_item,
+ int *r_next_index,
+ bool *r_do_abort)
+{
+ /* Get current status. */
+ Link *link = *r_next_item;
+
+ if (link->next == NULL) {
+ *r_do_abort = true;
}
- return 32;
+ *r_next_item = link->next;
+ (*r_next_index)++;
}
/**
@@ -1335,58 +1517,36 @@ BLI_INLINE int task_parallel_listbasecalc_chunk_size(const int num_threads)
* \param listbase: The double linked list to loop over.
* \param userdata: Common userdata passed to all instances of \a func.
* \param func: Callback function.
- * \param use_threading: If \a true, actually split-execute loop in threads,
- * else just do a sequential forloop
- * (allows caller to use any kind of test to switch on parallelization or not).
+ * \param settings: See public API doc of ParallelRangeSettings for description of all settings.
*
* \note There is no static scheduling here,
* since it would need another full loop over items to count them.
*/
-void BLI_task_parallel_listbase(struct ListBase *listbase,
+void BLI_task_parallel_listbase(ListBase *listbase,
void *userdata,
- TaskParallelListbaseFunc func,
- const bool use_threading)
+ TaskParallelIteratorFunc func,
+ const TaskParallelSettings *settings)
{
if (BLI_listbase_is_empty(listbase)) {
return;
}
- if (!use_threading) {
- task_parallel_listbase_no_threads(listbase, userdata, func);
- return;
- }
- TaskScheduler *task_scheduler = BLI_task_scheduler_get();
- const int num_threads = BLI_task_scheduler_num_threads(task_scheduler);
- /* TODO(sergey): Consider making chunk size configurable. */
- const int chunk_size = task_parallel_listbasecalc_chunk_size(num_threads);
- const int num_tasks = min_ii(num_threads, BLI_listbase_count(listbase) / chunk_size);
- if (num_tasks <= 1) {
- task_parallel_listbase_no_threads(listbase, userdata, func);
- return;
- }
- ParallelListState state;
- TaskPool *task_pool = BLI_task_pool_create_suspended(task_scheduler, &state);
+ TaskParallelIteratorState state = {0};
- state.index = 0;
- state.link = listbase->first;
+ state.tot_items = BLI_listbase_count(listbase);
+ state.iter_shared.next_index = 0;
+ state.iter_shared.next_item = listbase->first;
+ state.iter_shared.is_finished = false;
state.userdata = userdata;
+ state.iter_func = task_parallel_listbase_get;
state.func = func;
- state.chunk_size = chunk_size;
- BLI_spin_init(&state.lock);
- BLI_assert(num_tasks > 0);
- for (int i = 0; i < num_tasks; i++) {
- /* Use this pool's pre-allocated tasks. */
- BLI_task_pool_push_from_thread(
- task_pool, parallel_listbase_func, NULL, false, TASK_PRIORITY_HIGH, task_pool->thread_id);
- }
-
- BLI_task_pool_work_and_wait(task_pool);
- BLI_task_pool_free(task_pool);
-
- BLI_spin_end(&state.lock);
+ task_parallel_iterator_do(settings, &state);
}
+#undef MALLOCA
+#undef MALLOCA_FREE
+
typedef struct ParallelMempoolState {
void *userdata;
TaskParallelMempoolFunc func;
diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c
index 9e0d3b7a419..50363e3f42a 100644
--- a/source/blender/blenloader/intern/versioning_280.c
+++ b/source/blender/blenloader/intern/versioning_280.c
@@ -3932,5 +3932,10 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain)
{
/* Versioning code until next subversion bump goes here. */
+ for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ sa->flag &= ~AREA_FLAG_UNUSED_6;
+ }
+ }
}
}
diff --git a/source/blender/blenloader/intern/versioning_defaults.c b/source/blender/blenloader/intern/versioning_defaults.c
index c9fb8b6990b..9fce89558b6 100644
--- a/source/blender/blenloader/intern/versioning_defaults.c
+++ b/source/blender/blenloader/intern/versioning_defaults.c
@@ -435,6 +435,9 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template)
* Note that sculpt is an exception,
* it's values are overwritten by #BKE_brush_sculpt_reset below. */
brush->alpha = 1.0;
+
+ /* Enable antialiasing by default */
+ brush->sampling_flag |= BRUSH_PAINT_ANTIALIASING;
}
{
diff --git a/source/blender/blenloader/intern/versioning_userdef.c b/source/blender/blenloader/intern/versioning_userdef.c
index 53a6b8b08cd..e8783f68bcb 100644
--- a/source/blender/blenloader/intern/versioning_userdef.c
+++ b/source/blender/blenloader/intern/versioning_userdef.c
@@ -160,6 +160,7 @@ static void do_versions_theme(const UserDef *userdef, bTheme *btheme)
* Include next version bump.
*/
{
+ FROM_DEFAULT_V4_UCHAR(space_sequencer.anim_preview_range);
}
#undef FROM_DEFAULT_V4_UCHAR
diff --git a/source/blender/compositor/operations/COM_OpenCLKernels.cl b/source/blender/compositor/operations/COM_OpenCLKernels.cl
index 4dfca1777f1..ebe8a6d08ec 100644
--- a/source/blender/compositor/operations/COM_OpenCLKernels.cl
+++ b/source/blender/compositor/operations/COM_OpenCLKernels.cl
@@ -26,22 +26,22 @@
const sampler_t SAMPLER_NEAREST = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP_TO_EDGE | CLK_FILTER_NEAREST;
const sampler_t SAMPLER_NEAREST_CLAMP = CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP | CLK_FILTER_NEAREST;
-__constant const int zero = {0,0};
+__constant const int2 zero = {0,0};
// KERNEL --- BOKEH BLUR ---
__kernel void bokehBlurKernel(__read_only image2d_t boundingBox, __read_only image2d_t inputImage,
__read_only image2d_t bokehImage, __write_only image2d_t output,
- int offsetInput, int offsetOutput, int radius, int step, int dimension, int offset)
+ int2 offsetInput, int2 offsetOutput, int radius, int step, int2 dimension, int2 offset)
{
- int coords = {get_global_id(0), get_global_id(1)};
+ int2 coords = {get_global_id(0), get_global_id(1)};
coords += offset;
float tempBoundingBox;
- float color = {0.0f,0.0f,0.0f,0.0f};
- float multiplyer = {0.0f,0.0f,0.0f,0.0f};
- float bokeh;
+ float4 color = {0.0f,0.0f,0.0f,0.0f};
+ float4 multiplyer = {0.0f,0.0f,0.0f,0.0f};
+ float4 bokeh;
const float radius2 = radius*2.0f;
- const int realCoordinate = coords + offsetOutput;
- int imageCoordinates = realCoordinate - offsetInput;
+ const int2 realCoordinate = coords + offsetOutput;
+ int2 imageCoordinates = realCoordinate - offsetInput;
tempBoundingBox = read_imagef(boundingBox, SAMPLER_NEAREST, coords).s0;
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
index 1ea3fc13acd..2669bce52bc 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
@@ -122,31 +122,72 @@ namespace DEG {
/* ***************** */
/* Relations Builder */
+namespace {
+
/* TODO(sergey): This is somewhat weak, but we don't want neither false-positive
- * time dependencies nor special exceptions in the depsgraph evaluation.
- */
-static bool python_driver_depends_on_time(ChannelDriver *driver)
+ * time dependencies nor special exceptions in the depsgraph evaluation. */
+
+bool python_driver_exression_depends_on_time(const char *expression)
{
- if (driver->expression[0] == '\0') {
+ if (expression[0] == '\0') {
/* Empty expression depends on nothing. */
return false;
}
- if (strchr(driver->expression, '(') != NULL) {
+ if (strchr(expression, '(') != NULL) {
/* Function calls are considered dependent on a time. */
return true;
}
- if (strstr(driver->expression, "frame") != NULL) {
+ if (strstr(expression, "frame") != NULL) {
/* Variable `frame` depends on time. */
- /* TODO(sergey): This is a bit weak, but not sure about better way of
- * handling this. */
+ /* TODO(sergey): This is a bit weak, but not sure about better way of handling this. */
+ return true;
+ }
+ /* Possible indirect time relation s should be handled via variable targets. */
+ return false;
+}
+
+bool driver_target_depends_on_time(const DriverTarget *target)
+{
+ if (target->idtype == ID_SCE && STREQ(target->rna_path, "frame_current")) {
return true;
}
- /* Possible indirect time relation s should be handled via variable
- * targets. */
return false;
}
-static bool particle_system_depends_on_time(ParticleSystem *psys)
+bool driver_variable_depends_on_time(const DriverVar *variable)
+{
+ for (int i = 0; i < variable->num_targets; ++i) {
+ if (driver_target_depends_on_time(&variable->targets[i])) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool driver_variables_depends_on_time(const ListBase *variables)
+{
+ LISTBASE_FOREACH (const DriverVar *, variable, variables) {
+ if (driver_variable_depends_on_time(variable)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool driver_depends_on_time(ChannelDriver *driver)
+{
+ if (driver->type == DRIVER_TYPE_PYTHON) {
+ if (python_driver_exression_depends_on_time(driver->expression)) {
+ return true;
+ }
+ }
+ if (driver_variables_depends_on_time(&driver->variables)) {
+ return true;
+ }
+ return false;
+}
+
+bool particle_system_depends_on_time(ParticleSystem *psys)
{
ParticleSettings *part = psys->part;
/* Non-hair particles we always consider dependent on time. */
@@ -161,7 +202,7 @@ static bool particle_system_depends_on_time(ParticleSystem *psys)
return false;
}
-static bool object_particles_depends_on_time(Object *object)
+bool object_particles_depends_on_time(Object *object)
{
if (object->type != OB_MESH) {
return false;
@@ -174,7 +215,7 @@ static bool object_particles_depends_on_time(Object *object)
return false;
}
-static bool check_id_has_anim_component(ID *id)
+bool check_id_has_anim_component(ID *id)
{
AnimData *adt = BKE_animdata_from_id(id);
if (adt == NULL) {
@@ -183,11 +224,11 @@ static bool check_id_has_anim_component(ID *id)
return (adt->action != NULL) || (!BLI_listbase_is_empty(&adt->nla_tracks));
}
-static OperationCode bone_target_opcode(ID *target,
- const char *subtarget,
- ID *id,
- const char *component_subdata,
- RootPChanMap *root_map)
+OperationCode bone_target_opcode(ID *target,
+ const char *subtarget,
+ ID *id,
+ const char *component_subdata,
+ RootPChanMap *root_map)
{
/* Same armature. */
if (target == id) {
@@ -202,11 +243,13 @@ static OperationCode bone_target_opcode(ID *target,
return OperationCode::BONE_DONE;
}
-static bool object_have_geometry_component(const Object *object)
+bool object_have_geometry_component(const Object *object)
{
return ELEM(object->type, OB_MESH, OB_CURVE, OB_FONT, OB_SURF, OB_MBALL, OB_LATTICE, OB_GPENCIL);
}
+} // namespace
+
/* **** General purpose functions **** */
DepsgraphRelationBuilder::DepsgraphRelationBuilder(Main *bmain,
@@ -1382,7 +1425,7 @@ void DepsgraphRelationBuilder::build_driver(ID *id, FCurve *fcu)
/* It's quite tricky to detect if the driver actually depends on time or
* not, so for now we'll be quite conservative here about optimization and
* consider all python drivers to be depending on time. */
- if ((driver->type == DRIVER_TYPE_PYTHON) && python_driver_depends_on_time(driver)) {
+ if (driver_depends_on_time(driver)) {
TimeSourceKey time_src_key;
add_relation(time_src_key, driver_key, "TimeSrc -> Driver");
}
diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c
index 701d73461fc..d0fe7c6637e 100644
--- a/source/blender/draw/engines/eevee/eevee_materials.c
+++ b/source/blender/draw/engines/eevee/eevee_materials.c
@@ -68,8 +68,6 @@ static struct {
uint sss_count;
- float alpha_hash_offset;
- float alpha_hash_scale;
float noise_offsets[3];
} e_data = {NULL}; /* Engine data */
@@ -311,6 +309,9 @@ static char *eevee_get_defines(int options)
if ((options & VAR_MAT_LOOKDEV) != 0) {
BLI_dynstr_append(ds, "#define LOOKDEV\n");
}
+ if ((options & VAR_MAT_HOLDOUT) != 0) {
+ BLI_dynstr_append(ds, "#define HOLDOUT\n");
+ }
str = BLI_dynstr_get_cstring(ds);
BLI_dynstr_free(ds);
@@ -609,14 +610,14 @@ void EEVEE_materials_init(EEVEE_ViewLayerData *sldata,
}
if (!DRW_state_is_image_render() && ((stl->effects->enabled_effects & EFFECT_TAA) == 0)) {
- e_data.alpha_hash_offset = 0.0f;
- e_data.alpha_hash_scale = 1.0f;
+ sldata->common_data.alpha_hash_offset = 0.0f;
+ sldata->common_data.alpha_hash_scale = 1.0f;
}
else {
double r;
BLI_halton_1d(5, 0.0, stl->effects->taa_current_sample - 1, &r);
- e_data.alpha_hash_offset = (float)r;
- e_data.alpha_hash_scale = 0.01f;
+ sldata->common_data.alpha_hash_offset = (float)r;
+ sldata->common_data.alpha_hash_scale = 0.01f;
}
{
@@ -865,6 +866,7 @@ static struct DRWShadingGroup *EEVEE_default_shading_group_get(EEVEE_ViewLayerDa
ParticleSystem *psys,
ModifierData *md,
bool is_hair,
+ bool holdout,
bool use_ssr)
{
static int ssr_id;
@@ -876,6 +878,7 @@ static struct DRWShadingGroup *EEVEE_default_shading_group_get(EEVEE_ViewLayerDa
BLI_assert(!is_hair || (ob && psys && md));
SET_FLAG_FROM_TEST(options, is_hair, VAR_MAT_HAIR);
+ SET_FLAG_FROM_TEST(options, holdout, VAR_MAT_HOLDOUT);
if (e_data.default_lit[options] == NULL) {
create_default_shader(options);
@@ -1116,7 +1119,8 @@ static void material_opaque(Material *ma,
struct GPUMaterial **gpumat_depth,
struct DRWShadingGroup **shgrp,
struct DRWShadingGroup **shgrp_depth,
- struct DRWShadingGroup **shgrp_depth_clip)
+ struct DRWShadingGroup **shgrp_depth_clip,
+ bool holdout)
{
EEVEE_EffectsInfo *effects = vedata->stl->effects;
const DRWContextState *draw_ctx = DRW_context_state_get();
@@ -1131,7 +1135,7 @@ static void material_opaque(Material *ma,
float *rough_p = &ma->roughness;
const bool do_cull = (ma->blend_flag & MA_BL_CULL_BACKFACE) != 0;
- const bool use_gpumat = (ma->use_nodes && ma->nodetree);
+ const bool use_gpumat = (ma->use_nodes && ma->nodetree && !holdout);
const bool use_ssrefract = ((ma->blend_flag & MA_BL_SS_REFRACTION) != 0) &&
((effects->enabled_effects & EFFECT_REFRACT) != 0);
const bool use_translucency = ((ma->blend_flag & MA_BL_TRANSLUCENCY) != 0);
@@ -1218,14 +1222,6 @@ static void material_opaque(Material *ma,
DRW_shgroup_uniform_float(*shgrp_depth, "alphaThreshold", &ma->alpha_threshold, 1);
DRW_shgroup_uniform_float(*shgrp_depth_clip, "alphaThreshold", &ma->alpha_threshold, 1);
}
- else if (ma->blend_method == MA_BM_HASHED) {
- DRW_shgroup_uniform_float(*shgrp_depth, "hashAlphaOffset", &e_data.alpha_hash_offset, 1);
- DRW_shgroup_uniform_float(
- *shgrp_depth_clip, "hashAlphaOffset", &e_data.alpha_hash_offset, 1);
- DRW_shgroup_uniform_float_copy(*shgrp_depth, "hashAlphaScale", e_data.alpha_hash_scale);
- DRW_shgroup_uniform_float_copy(
- *shgrp_depth_clip, "hashAlphaScale", e_data.alpha_hash_scale);
- }
}
}
@@ -1301,7 +1297,8 @@ static void material_opaque(Material *ma,
/* Fallback to default shader */
if (*shgrp == NULL) {
bool use_ssr = ((effects->enabled_effects & EFFECT_SSR) != 0);
- *shgrp = EEVEE_default_shading_group_get(sldata, vedata, NULL, NULL, NULL, false, use_ssr);
+ *shgrp = EEVEE_default_shading_group_get(
+ sldata, vedata, NULL, NULL, NULL, false, holdout, use_ssr);
DRW_shgroup_uniform_vec3(*shgrp, "basecol", color_p, 1);
DRW_shgroup_uniform_float(*shgrp, "metallic", metal_p, 1);
DRW_shgroup_uniform_float(*shgrp, "specular", spec_p, 1);
@@ -1453,6 +1450,7 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata,
const DRWContextState *draw_ctx = DRW_context_state_get();
Scene *scene = draw_ctx->scene;
GHash *material_hash = stl->g_data->material_hash;
+ const bool holdout = (ob->base_flag & BASE_HOLDOUT) != 0;
bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) &&
!DRW_state_is_image_render();
@@ -1479,6 +1477,20 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata,
shgrp_depth_array[i] = NULL;
shgrp_depth_clip_array[i] = NULL;
+ if (holdout) {
+ material_opaque(ma_array[i],
+ material_hash,
+ sldata,
+ vedata,
+ &gpumat_array[i],
+ &gpumat_depth_array[i],
+ &shgrp_array[i],
+ &shgrp_depth_array[i],
+ &shgrp_depth_clip_array[i],
+ true);
+ continue;
+ }
+
switch (ma_array[i]->blend_method) {
case MA_BM_SOLID:
case MA_BM_CLIP:
@@ -1491,7 +1503,8 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata,
&gpumat_depth_array[i],
&shgrp_array[i],
&shgrp_depth_array[i],
- &shgrp_depth_clip_array[i]);
+ &shgrp_depth_clip_array[i],
+ false);
break;
case MA_BM_BLEND:
material_transparent(ma_array[i],
@@ -1632,6 +1645,7 @@ void EEVEE_hair_cache_populate(EEVEE_Data *vedata,
Scene *scene = draw_ctx->scene;
bool use_ssr = ((stl->effects->enabled_effects & EFFECT_SSR) != 0);
+ const bool holdout = (ob->base_flag & BASE_HOLDOUT) != 0;
if (ob->type == OB_MESH) {
if (ob != draw_ctx->object_edit) {
@@ -1664,7 +1678,8 @@ void EEVEE_hair_cache_populate(EEVEE_Data *vedata,
ob, psys, md, psl->depth_pass_clip, e_data.default_hair_prepass_clip_sh);
shgrp = NULL;
- if (ma->use_nodes && ma->nodetree) {
+
+ if (ma->use_nodes && ma->nodetree && !holdout) {
static int ssr_id;
ssr_id = (use_ssr) ? 1 : -1;
static float half = 0.5f;
@@ -1715,7 +1730,8 @@ void EEVEE_hair_cache_populate(EEVEE_Data *vedata,
/* Fallback to default shader */
if (shgrp == NULL) {
- shgrp = EEVEE_default_shading_group_get(sldata, vedata, ob, psys, md, true, use_ssr);
+ shgrp = EEVEE_default_shading_group_get(
+ sldata, vedata, ob, psys, md, true, holdout, use_ssr);
DRW_shgroup_uniform_vec3(shgrp, "basecol", color_p, 1);
DRW_shgroup_uniform_float(shgrp, "metallic", metal_p, 1);
DRW_shgroup_uniform_float(shgrp, "specular", spec_p, 1);
diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h
index f4f40d40de6..7d02aacfac7 100644
--- a/source/blender/draw/engines/eevee/eevee_private.h
+++ b/source/blender/draw/engines/eevee/eevee_private.h
@@ -157,10 +157,11 @@ enum {
VAR_MAT_BLEND = (1 << 3),
VAR_MAT_VOLUME = (1 << 4),
VAR_MAT_LOOKDEV = (1 << 5),
+ VAR_MAT_HOLDOUT = (1 << 6),
/* Max number of variation */
/* IMPORTANT : Leave it last and set
* it's value accordingly. */
- VAR_MAT_MAX = (1 << 6),
+ VAR_MAT_MAX = (1 << 7),
/* These are options that are not counted in VAR_MAT_MAX
* because they are not cumulative with the others above. */
VAR_MAT_CLIP = (1 << 9),
@@ -665,9 +666,13 @@ typedef struct EEVEE_CommonUniformBuffer {
float prb_lod_cube_max; /* float */
float prb_lod_planar_max; /* float */
/* Misc */
- int hiz_mip_offset; /* int */
- int ray_type; /* int */
- float ray_depth; /* float */
+ int hiz_mip_offset; /* int */
+ int ray_type; /* int */
+ float ray_depth; /* float */
+ float alpha_hash_offset; /* float */
+ float alpha_hash_scale; /* float */
+ float pad7; /* float */
+ float pad8; /* float */
} EEVEE_CommonUniformBuffer;
BLI_STATIC_ASSERT_ALIGN(EEVEE_CommonUniformBuffer, 16)
diff --git a/source/blender/draw/engines/eevee/eevee_shadows.c b/source/blender/draw/engines/eevee/eevee_shadows.c
index 46fc6e07c1c..1776f535237 100644
--- a/source/blender/draw/engines/eevee/eevee_shadows.c
+++ b/source/blender/draw/engines/eevee/eevee_shadows.c
@@ -365,7 +365,7 @@ void EEVEE_shadows_draw(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, DRWView
/* Precompute all shadow/view test before rendering and trashing the culling cache. */
BLI_bitmap *cube_visible = BLI_BITMAP_NEW_ALLOCA(MAX_SHADOW_CUBE);
- bool any_visible = false;
+ bool any_visible = linfo->cascade_len > 0;
for (int cube = 0; cube < linfo->cube_len; cube++) {
if (DRW_culling_sphere_test(view, linfo->shadow_bounds + cube)) {
BLI_BITMAP_ENABLE(cube_visible, cube);
@@ -373,7 +373,7 @@ void EEVEE_shadows_draw(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, DRWView
}
}
- if (!any_visible && linfo->cascade_len == 0) {
+ if (any_visible) {
sldata->common_data.ray_type = EEVEE_RAY_SHADOW;
DRW_uniformbuffer_update(sldata->common_ubo, &sldata->common_data);
}
@@ -400,7 +400,7 @@ void EEVEE_shadows_draw(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, DRWView
DRW_uniformbuffer_update(sldata->shadow_ubo, &linfo->shadow_data); /* Update all data at once */
- if (!any_visible && linfo->cascade_len == 0) {
+ if (any_visible) {
sldata->common_data.ray_type = saved_ray_type;
DRW_uniformbuffer_update(sldata->common_ubo, &sldata->common_data);
}
diff --git a/source/blender/draw/engines/eevee/eevee_volumes.c b/source/blender/draw/engines/eevee/eevee_volumes.c
index aaa351a1922..67fd441a0b1 100644
--- a/source/blender/draw/engines/eevee/eevee_volumes.c
+++ b/source/blender/draw/engines/eevee/eevee_volumes.c
@@ -41,6 +41,7 @@
#include "eevee_private.h"
#include "GPU_draw.h"
+#include "GPU_extensions.h"
#include "GPU_texture.h"
#include "GPU_material.h"
@@ -81,7 +82,9 @@ extern char datatoc_volumetric_integration_frag_glsl[];
extern char datatoc_volumetric_lib_glsl[];
extern char datatoc_common_fullscreen_vert_glsl[];
-#define USE_VOLUME_OPTI (GLEW_ARB_shader_image_load_store && GLEW_ARB_shading_language_420pack)
+#define USE_VOLUME_OPTI \
+ (GLEW_ARB_shader_image_load_store && GLEW_ARB_shading_language_420pack && \
+ !GPU_crappy_amd_driver())
static void eevee_create_shader_volumes(void)
{
diff --git a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl
index f10d98e68bd..b9a971570df 100644
--- a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl
@@ -966,7 +966,6 @@ void main()
# ifndef USE_ALPHA_BLEND
float alpha_div = 1.0 / max(1e-8, alpha);
outRadiance.rgb *= alpha_div;
- outRadiance.a = 1.0;
ssrData.rgb *= alpha_div;
# ifdef USE_SSS
sssAlbedo.rgb *= alpha_div;
diff --git a/source/blender/draw/engines/eevee/shaders/common_uniforms_lib.glsl b/source/blender/draw/engines/eevee/shaders/common_uniforms_lib.glsl
index c7ae2417904..7f255b0859d 100644
--- a/source/blender/draw/engines/eevee/shaders/common_uniforms_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/common_uniforms_lib.glsl
@@ -43,6 +43,10 @@ layout(std140) uniform common_block
int hizMipOffset;
int rayType;
float rayDepth;
+ float alphaHashOffset;
+ float alphaHashScale;
+ float pad7;
+ float pad8;
};
/* rayType (keep in sync with ray_type) */
diff --git a/source/blender/draw/engines/eevee/shaders/default_frag.glsl b/source/blender/draw/engines/eevee/shaders/default_frag.glsl
index ca06d458f6e..a031ed193b6 100644
--- a/source/blender/draw/engines/eevee/shaders/default_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/default_frag.glsl
@@ -41,5 +41,10 @@ Closure nodetree_exec(void)
gl_FragDepth = 0.0;
#endif
+#ifdef HOLDOUT
+ cl = CLOSURE_DEFAULT;
+ cl.holdout = 1.0;
+#endif
+
return cl;
}
diff --git a/source/blender/draw/engines/eevee/shaders/prepass_frag.glsl b/source/blender/draw/engines/eevee/shaders/prepass_frag.glsl
index dea6bc020ec..b49dbfceba2 100644
--- a/source/blender/draw/engines/eevee/shaders/prepass_frag.glsl
+++ b/source/blender/draw/engines/eevee/shaders/prepass_frag.glsl
@@ -12,14 +12,11 @@ float hash3d(vec3 a)
return hash(vec2(hash(a.xy), a.z));
}
-uniform float hashAlphaOffset;
-uniform float hashAlphaScale = 1.0; /* Roughly in pixel */
-
float hashed_alpha_threshold(vec3 co)
{
/* Find the discretized derivatives of our coordinates. */
float max_deriv = max(length(dFdx(co)), length(dFdy(co)));
- float pix_scale = 1.0 / (hashAlphaScale * max_deriv);
+ float pix_scale = 1.0 / (alphaHashScale * max_deriv);
/* Find two nearest log-discretized noise scales. */
float pix_scale_log = log2(pix_scale);
@@ -52,7 +49,7 @@ float hashed_alpha_threshold(vec3 co)
threshold = clamp(threshold, 1.0e-6, 1.0);
/* Jitter the threshold for TAA accumulation. */
- return fract(threshold + hashAlphaOffset);
+ return fract(threshold + alphaHashOffset);
}
#endif
diff --git a/source/blender/draw/engines/gpencil/gpencil_draw_utils.c b/source/blender/draw/engines/gpencil/gpencil_draw_utils.c
index af315597e68..efc73fd1056 100644
--- a/source/blender/draw/engines/gpencil/gpencil_draw_utils.c
+++ b/source/blender/draw/engines/gpencil/gpencil_draw_utils.c
@@ -1128,11 +1128,12 @@ static void gpencil_add_editpoints_vertexdata(GpencilBatchCache *cache,
*/
const bool show_points = (show_sculpt_points) || (is_weight_paint) ||
(GPENCIL_EDIT_MODE(gpd) &&
- (ts->gpencil_selectmode_edit != GP_SELECTMODE_STROKE));
+ ((ts->gpencil_selectmode_edit != GP_SELECTMODE_STROKE) ||
+ (gps->totpoints == 1)));
if (cache->is_dirty) {
if ((obact == ob) && ((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0) &&
- (v3d->gp_flag & V3D_GP_SHOW_EDIT_LINES)) {
+ (v3d->gp_flag & V3D_GP_SHOW_EDIT_LINES) && (gps->totpoints > 1)) {
/* line of the original stroke */
gpencil_get_edlin_geom(&cache->b_edlin, gps, edit_alpha, hide_select);
@@ -1259,9 +1260,11 @@ static void gpencil_draw_strokes(GpencilBatchCache *cache,
gpencil_add_fill_vertexdata(
cache, ob, gpl, gpf, gps, opacity, tintcolor, false, custonion);
}
- /* stroke */
- /* No fill strokes, must show stroke always */
- if (((gp_style->flag & GP_STYLE_STROKE_SHOW) || (gps->flag & GP_STROKE_NOFILL)) &&
+ /* stroke
+ * No fill strokes, must show stroke always or if the total points is lower than 3,
+ * because the stroke cannot be filled and it would be invisible. */
+ if (((gp_style->flag & GP_STYLE_STROKE_SHOW) || (gps->flag & GP_STROKE_NOFILL) ||
+ (gps->totpoints < 3)) &&
((gp_style->stroke_rgba[3] > GPENCIL_ALPHA_OPACITY_THRESH) ||
(gpl->blend_mode == eGplBlendMode_Regular))) {
/* recalc strokes uv (geometry can be changed by modifiers) */
diff --git a/source/blender/draw/intern/draw_armature.c b/source/blender/draw/intern/draw_armature.c
index 5cd6a4a1286..e16dfb5004b 100644
--- a/source/blender/draw/intern/draw_armature.c
+++ b/source/blender/draw/intern/draw_armature.c
@@ -1350,7 +1350,8 @@ static void draw_points(const EditBone *eBone,
bone_hint_color_shade(col_hint_tail, (g_theme.const_color) ? col_solid_tail : col_wire_tail);
/* Draw root point if we are not connected to our parent */
- if ((BONE_FLAG(eBone, pchan) & BONE_CONNECTED) == 0) {
+ if (!(eBone ? (eBone->parent && (eBone->flag & BONE_CONNECTED)) :
+ (pchan->bone->parent && (pchan->bone->flag & BONE_CONNECTED)))) {
if (select_id != -1) {
DRW_select_load_id(select_id | BONESEL_ROOT);
}
@@ -1518,29 +1519,32 @@ static void draw_bone_line(EditBone *eBone,
const float *col_head = no_display;
const float *col_tail = col_bone;
- if (eBone) {
- if (eBone->flag & BONE_TIPSEL) {
- col_tail = g_theme.vertex_select_color;
- }
- if (boneflag & BONE_SELECTED) {
- col_bone = g_theme.edge_select_color;
- }
- col_wire = g_theme.wire_color;
+ if (g_theme.const_color != NULL) {
+ col_wire = no_display; /* actually shrink the display. */
+ col_bone = col_head = col_tail = g_theme.const_color;
}
-
- /* Draw root point if we are not connected to our parent */
- if ((BONE_FLAG(eBone, pchan) & BONE_CONNECTED) == 0) {
+ else {
if (eBone) {
- col_head = (eBone->flag & BONE_ROOTSEL) ? g_theme.vertex_select_color : col_bone;
- }
- else if (pchan) {
- col_head = col_bone;
+ if (eBone->flag & BONE_TIPSEL) {
+ col_tail = g_theme.vertex_select_color;
+ }
+ if (boneflag & BONE_SELECTED) {
+ col_bone = g_theme.edge_select_color;
+ }
+ col_wire = g_theme.wire_color;
}
- }
- if (g_theme.const_color != NULL) {
- col_wire = no_display; /* actually shrink the display. */
- col_bone = col_head = col_tail = g_theme.const_color;
+ /* Draw root point if we are not connected to our parent. */
+ if (!(eBone ? (eBone->parent && (eBone->flag & BONE_CONNECTED)) :
+ (pchan->bone->parent && (pchan->bone->flag & BONE_CONNECTED)))) {
+
+ if (eBone) {
+ col_head = (eBone->flag & BONE_ROOTSEL) ? g_theme.vertex_select_color : col_bone;
+ }
+ else {
+ col_head = col_bone;
+ }
+ }
}
if (select_id == -1) {
diff --git a/source/blender/draw/modes/object_mode.c b/source/blender/draw/modes/object_mode.c
index 70bccb4849c..fe17019a5b5 100644
--- a/source/blender/draw/modes/object_mode.c
+++ b/source/blender/draw/modes/object_mode.c
@@ -1235,22 +1235,42 @@ static void DRW_shgroup_camera_background_images(OBJECT_Shaders *sh_data,
uv2img_space[1][1] = image_height;
const float fit_scale = image_aspect / camera_aspect;
- img2cam_space[0][0] = 1.0 / image_width;
- img2cam_space[1][1] = 1.0 / fit_scale / image_height;
+ if (camera_aspect < image_aspect) {
+ img2cam_space[0][0] = 1.0 / (1.0 / fit_scale) / image_width;
+ img2cam_space[1][1] = 1.0 / image_height;
+ }
+ else {
+ img2cam_space[0][0] = 1.0 / image_width;
+ img2cam_space[1][1] = 1.0 / fit_scale / image_height;
+ }
/* Update scaling based on image and camera framing */
float scale_x = bgpic->scale;
float scale_y = bgpic->scale;
+ float scale_x_offset = image_width;
+ float scale_y_offset = image_height;
+ if (image_aspect > 1.0f) {
+ scale_x_offset /= image_aspect;
+ if (camera_aspect > 1.0f) {
+ scale_x_offset *= min_ff(image_aspect, camera_aspect);
+ scale_y_offset *= min_ff(image_aspect, camera_aspect);
+ }
+ }
+ else {
+ scale_y_offset *= image_aspect;
+ if (camera_aspect < 1.0f) {
+ scale_x_offset /= max_ff(image_aspect, camera_aspect);
+ scale_y_offset /= max_ff(image_aspect, camera_aspect);
+ }
+ }
+
if (bgpic->flag & CAM_BGIMG_FLAG_CAMERA_ASPECT) {
if (bgpic->flag & CAM_BGIMG_FLAG_CAMERA_CROP) {
- if (image_aspect > camera_aspect) {
- scale_x *= fit_scale;
- scale_y *= fit_scale;
- }
+ /* pass */
}
else {
- if (image_aspect > camera_aspect) {
+ if (camera_aspect < image_aspect) {
scale_x /= fit_scale;
scale_y /= fit_scale;
}
@@ -1262,7 +1282,12 @@ static void DRW_shgroup_camera_background_images(OBJECT_Shaders *sh_data,
}
else {
/* Stretch image to camera aspect */
- scale_y /= 1.0 / fit_scale;
+ if (camera_aspect < image_aspect) {
+ scale_x /= fit_scale;
+ }
+ else {
+ scale_y *= fit_scale;
+ }
}
// scale image to match the desired aspect ratio
@@ -1270,8 +1295,8 @@ static void DRW_shgroup_camera_background_images(OBJECT_Shaders *sh_data,
scale_m4[1][1] = scale_y;
/* Translate */
- translate_m4[3][0] = image_width * bgpic->offset[0] * 2.0f;
- translate_m4[3][1] = image_height * bgpic->offset[1] * 2.0f;
+ translate_m4[3][0] = bgpic->offset[0] * 2.0f * scale_x_offset;
+ translate_m4[3][1] = bgpic->offset[1] * 2.0f * scale_y_offset;
mul_m4_series(bg_data->transform_mat,
win_m4_translate,
diff --git a/source/blender/draw/modes/sculpt_mode.c b/source/blender/draw/modes/sculpt_mode.c
index 9749619cffe..f32eb3b73ba 100644
--- a/source/blender/draw/modes/sculpt_mode.c
+++ b/source/blender/draw/modes/sculpt_mode.c
@@ -157,7 +157,7 @@ static void SCULPT_cache_populate(void *vedata, Object *ob)
if ((ob == draw_ctx->obact) &&
(BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) ||
- ob->sculpt->deform_modifiers_active || ob->sculpt->shapekey_active)) {
+ !ob->sculpt->deform_modifiers_active || ob->sculpt->shapekey_active)) {
PBVH *pbvh = ob->sculpt->pbvh;
if (pbvh && pbvh_has_mask(pbvh)) {
DRW_shgroup_call_sculpt(stl->g_data->mask_overlay_grp, ob, false, true, false);
diff --git a/source/blender/editors/datafiles/CMakeLists.txt b/source/blender/editors/datafiles/CMakeLists.txt
index 1c7edb6c46a..680fe3a00e5 100644
--- a/source/blender/editors/datafiles/CMakeLists.txt
+++ b/source/blender/editors/datafiles/CMakeLists.txt
@@ -693,6 +693,7 @@ set_property(GLOBAL PROPERTY ICON_GEOM_NAMES
ops.gpencil.primitive_circle
ops.gpencil.primitive_curve
ops.gpencil.primitive_line
+ ops.gpencil.primitive_polyline
ops.gpencil.radius
ops.gpencil.sculpt_clone
ops.gpencil.sculpt_grab
@@ -728,6 +729,7 @@ set_property(GLOBAL PROPERTY ICON_GEOM_NAMES
ops.mesh.spin.duplicate
ops.mesh.vertices_smooth
ops.node.links_cut
+ ops.paint.eyedropper_add
ops.paint.vertex_color_fill
ops.paint.weight_fill
ops.paint.weight_gradient
diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c
index c4f18c60f4d..3ab11f8f3f7 100644
--- a/source/blender/editors/gpencil/gpencil_edit.c
+++ b/source/blender/editors/gpencil/gpencil_edit.c
@@ -1538,6 +1538,7 @@ void GPENCIL_OT_move_to_layer(wmOperatorType *ot)
/* GPencil layer to use. */
ot->prop = RNA_def_int(ot->srna, "layer", 0, 0, INT_MAX, "Grease Pencil Layer", "", 0, INT_MAX);
+ RNA_def_property_flag(ot->prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
/* ********************* Add Blank Frame *************************** */
diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c
index f29e782c618..c34e670c872 100644
--- a/source/blender/editors/gpencil/gpencil_paint.c
+++ b/source/blender/editors/gpencil/gpencil_paint.c
@@ -837,6 +837,11 @@ static short gp_stroke_addpoint(
gpd->runtime.sbuffer = ED_gpencil_sbuffer_ensure(
gpd->runtime.sbuffer, &gpd->runtime.sbuffer_size, &gpd->runtime.sbuffer_used, false);
+ /* Check the buffer was created. */
+ if (gpd->runtime.sbuffer == NULL) {
+ return GP_STROKEADD_INVALID;
+ }
+
/* get pointer to destination point */
pt = ((tGPspoint *)(gpd->runtime.sbuffer) + gpd->runtime.sbuffer_used);
@@ -3660,7 +3665,6 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
tGPsdata *p = op->customdata;
ToolSettings *ts = CTX_data_tool_settings(C);
GP_Sculpt_Guide *guide = &p->scene->toolsettings->gp_sculpt.guide;
- tGPspoint *points = (tGPspoint *)p->gpd->runtime.sbuffer;
/* default exit state - pass through to support MMB view nav, etc. */
int estate = OPERATOR_PASS_THROUGH;
@@ -3969,6 +3973,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event)
int size_after = p->gpd->runtime.sbuffer_used;
/* Last point of the event is always real (not fake). */
+ tGPspoint *points = (tGPspoint *)p->gpd->runtime.sbuffer;
tGPspoint *pt = &points[size_after - 1];
pt->tflag &= ~GP_TPOINT_FAKE;
diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c
index b194d28a8b8..91af444c28a 100644
--- a/source/blender/editors/gpencil/gpencil_utils.c
+++ b/source/blender/editors/gpencil/gpencil_utils.c
@@ -2530,8 +2530,8 @@ void ED_gpencil_select_toggle_all(bContext *C, int action)
/* Ensure the SBuffer (while drawing stroke) size is enough to save all points of the stroke */
tGPspoint *ED_gpencil_sbuffer_ensure(tGPspoint *buffer_array,
- short *buffer_size,
- short *buffer_used,
+ int *buffer_size,
+ int *buffer_used,
const bool clear)
{
tGPspoint *p = NULL;
@@ -2548,6 +2548,11 @@ tGPspoint *ED_gpencil_sbuffer_ensure(tGPspoint *buffer_array,
*buffer_size += GP_STROKE_BUFFER_CHUNK;
p = MEM_recallocN(buffer_array, sizeof(struct tGPspoint) * *buffer_size);
}
+
+ if (p == NULL) {
+ *buffer_size = *buffer_used = 0;
+ }
+
buffer_array = p;
}
diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h
index 0ff1b8bb40b..dce0e3931be 100644
--- a/source/blender/editors/include/ED_gpencil.h
+++ b/source/blender/editors/include/ED_gpencil.h
@@ -292,8 +292,8 @@ void ED_gpencil_select_toggle_all(struct bContext *C, int action);
/* Ensure stroke sbuffer size is enough */
struct tGPspoint *ED_gpencil_sbuffer_ensure(struct tGPspoint *buffer_array,
- short *buffer_size,
- short *buffer_used,
+ int *buffer_size,
+ int *buffer_used,
const bool clear);
/* Tag all scene grease pencil object to update. */
void ED_gpencil_tag_scene_gpencil(struct Scene *scene);
diff --git a/source/blender/editors/include/ED_mask.h b/source/blender/editors/include/ED_mask.h
index df4349a9063..f4725fea039 100644
--- a/source/blender/editors/include/ED_mask.h
+++ b/source/blender/editors/include/ED_mask.h
@@ -77,41 +77,41 @@ void ED_mask_draw_frames(
struct Mask *mask, struct ARegion *ar, const int cfra, const int sfra, const int efra);
/* mask_shapekey.c */
-void ED_mask_layer_shape_auto_key(struct MaskLayer *masklay, const int frame);
+void ED_mask_layer_shape_auto_key(struct MaskLayer *mask_layer, const int frame);
bool ED_mask_layer_shape_auto_key_all(struct Mask *mask, const int frame);
bool ED_mask_layer_shape_auto_key_select(struct Mask *mask, const int frame);
/* ----------- Mask AnimEdit API ------------------ */
-bool ED_masklayer_frames_looper(struct MaskLayer *masklay,
+bool ED_masklayer_frames_looper(struct MaskLayer *mask_layer,
struct Scene *scene,
- short (*masklay_shape_cb)(struct MaskLayerShape *,
- struct Scene *));
-void ED_masklayer_make_cfra_list(struct MaskLayer *masklay, ListBase *elems, bool onlysel);
+ short (*mask_layer_shape_cb)(struct MaskLayerShape *,
+ struct Scene *));
+void ED_masklayer_make_cfra_list(struct MaskLayer *mask_layer, ListBase *elems, bool onlysel);
-bool ED_masklayer_frame_select_check(struct MaskLayer *masklay);
-void ED_masklayer_frame_select_set(struct MaskLayer *masklay, short mode);
-void ED_masklayer_frames_select_box(struct MaskLayer *masklay,
+bool ED_masklayer_frame_select_check(struct MaskLayer *mask_layer);
+void ED_masklayer_frame_select_set(struct MaskLayer *mask_layer, short mode);
+void ED_masklayer_frames_select_box(struct MaskLayer *mask_layer,
float min,
float max,
short select_mode);
void ED_masklayer_frames_select_region(struct KeyframeEditData *ked,
- struct MaskLayer *masklay,
+ struct MaskLayer *mask_layer,
short tool,
short select_mode);
-void ED_mask_select_frames(struct MaskLayer *masklay, short select_mode);
-void ED_mask_select_frame(struct MaskLayer *masklay, int selx, short select_mode);
+void ED_mask_select_frames(struct MaskLayer *mask_layer, short select_mode);
+void ED_mask_select_frame(struct MaskLayer *mask_layer, int selx, short select_mode);
-bool ED_masklayer_frames_delete(struct MaskLayer *masklay);
-void ED_masklayer_frames_duplicate(struct MaskLayer *masklay);
+bool ED_masklayer_frames_delete(struct MaskLayer *mask_layer);
+void ED_masklayer_frames_duplicate(struct MaskLayer *mask_layer);
-void ED_masklayer_snap_frames(struct MaskLayer *masklay, struct Scene *scene, short mode);
+void ED_masklayer_snap_frames(struct MaskLayer *mask_layer, struct Scene *scene, short mode);
#if 0
void free_gpcopybuf(void);
void copy_gpdata(void);
void paste_gpdata(void);
-void mirror_masklayer_frames(struct MaskLayer *masklay, short mode);
+void mirror_masklayer_frames(struct MaskLayer *mask_layer, short mode);
#endif
#endif /* __ED_MASK_H__ */
diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h
index c3e61f5f2b2..4ca7c8f96ad 100644
--- a/source/blender/editors/include/ED_screen.h
+++ b/source/blender/editors/include/ED_screen.h
@@ -404,13 +404,10 @@ void ED_screen_user_menu_register(void);
/* Cache display helpers */
-void ED_region_cache_draw_background(const struct ARegion *ar);
+void ED_region_cache_draw_background(struct ARegion *ar);
void ED_region_cache_draw_curfra_label(const int framenr, const float x, const float y);
-void ED_region_cache_draw_cached_segments(const struct ARegion *ar,
- const int num_segments,
- const int *points,
- const int sfra,
- const int efra);
+void ED_region_cache_draw_cached_segments(
+ struct ARegion *ar, const int num_segments, const int *points, const int sfra, const int efra);
/* area_utils.c */
void ED_region_generic_tools_region_message_subscribe(const struct bContext *C,
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 40e0005b487..0e20abe4221 100644
--- a/source/blender/editors/include/ED_transform_snap_object_context.h
+++ b/source/blender/editors/include/ED_transform_snap_object_context.h
@@ -68,6 +68,8 @@ struct SnapObjectParams {
unsigned int use_object_edit_cage : 1;
/* snap to the closest element, use when using more than one snap type */
unsigned int use_occlusion_test : 1;
+ /* exclude back facing geometry from snapping */
+ unsigned int use_backface_culling : 1;
};
typedef struct SnapObjectContext SnapObjectContext;
diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h
index 1c2bc54d821..c15f299bca8 100644
--- a/source/blender/editors/include/UI_icons.h
+++ b/source/blender/editors/include/UI_icons.h
@@ -76,7 +76,7 @@ DEF_ICON(X)
DEF_ICON(DUPLICATE)
DEF_ICON(TRASH)
DEF_ICON(COLLECTION_NEW)
-DEF_ICON_BLANK(77)
+DEF_ICON(OPTIONS)
DEF_ICON(NODE)
DEF_ICON(NODE_SEL)
@@ -104,8 +104,8 @@ DEF_ICON(RIGHTARROW)
DEF_ICON(DOWNARROW_HLT)
DEF_ICON(FCURVE_SNAPSHOT)
DEF_ICON(OBJECT_HIDDEN)
-DEF_ICON_BLANK(105)
-DEF_ICON_BLANK(106)
+DEF_ICON(TOPBAR)
+DEF_ICON(STATUSBAR)
DEF_ICON(PLUGIN)
/* various ui */
@@ -283,7 +283,7 @@ DEF_ICON(MOUSE_MOVE)
DEF_ICON(MOUSE_LMB_DRAG)
DEF_ICON(MOUSE_MMB_DRAG)
DEF_ICON(MOUSE_RMB_DRAG)
-DEF_ICON_BLANK(284)
+DEF_ICON(MEMORY)
DEF_ICON(PRESET_NEW)
DEF_ICON_BLANK(286)
DEF_ICON(DECORATE)
@@ -774,9 +774,9 @@ DEF_ICON_BLANK(277)
DEF_ICON_BLANK(772)
DEF_ICON_BLANK(773)
DEF_ICON_BLANK(774)
-DEF_ICON_BLANK(775)
-DEF_ICON_BLANK(776)
-DEF_ICON_BLANK(777)
+DEF_ICON(HOME)
+DEF_ICON(DOCUMENTS)
+DEF_ICON(TEMP)
/* FILE SELECT */
DEF_ICON(SORTALPHA)
@@ -857,7 +857,7 @@ DEF_ICON(SCRIPTPLUGINS)
DEF_ICON_BLANK(855)
DEF_ICON_BLANK(856)
DEF_ICON_BLANK(857)
-DEF_ICON_BLANK(858)
+DEF_ICON(DISC)
DEF_ICON(DESKTOP)
DEF_ICON(EXTERNAL_DRIVE)
DEF_ICON(NETWORK_DRIVE)
diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c
index b3e039292e1..4cef9ace66e 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -184,6 +184,18 @@ static void color_ensure_contrast_v3(uchar cp[3], const uchar cp_other[3], int c
}
}
+static void color_mul_hsl_v3(uchar ch[3], float h_factor, float s_factor, float l_factor)
+{
+ float rgb[3], hsl[3];
+ rgb_uchar_to_float(rgb, ch);
+ rgb_to_hsl_v(rgb, hsl);
+ hsl[0] *= h_factor;
+ hsl[1] *= s_factor;
+ hsl[2] *= l_factor;
+ hsl_to_rgb_v(hsl, rgb);
+ rgb_float_to_uchar(ch, rgb);
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -2573,11 +2585,12 @@ static void ui_widget_color_disabled(uiWidgetType *wt)
wt->wcol_theme = &wcol_theme_s;
}
-static void widget_active_color(uchar cp[3])
+static void widget_active_color(uiWidgetColors *wcol)
{
- cp[0] = cp[0] >= 240 ? 255 : cp[0] + 15;
- cp[1] = cp[1] >= 240 ? 255 : cp[1] + 15;
- cp[2] = cp[2] >= 240 ? 255 : cp[2] + 15;
+ bool dark = (rgb_to_grayscale_byte(wcol->text) > rgb_to_grayscale_byte(wcol->inner));
+ color_mul_hsl_v3(wcol->inner, 1.0f, 1.15f, dark ? 1.2f : 1.1f);
+ color_mul_hsl_v3(wcol->outline, 1.0f, 1.15f, 1.15f);
+ color_mul_hsl_v3(wcol->text, 1.0f, 1.15f, dark ? 1.25f : 0.8f);
}
static const uchar *widget_color_blend_from_flags(const uiWidgetStateColors *wcol_state,
@@ -2641,10 +2654,10 @@ static void widget_state(uiWidgetType *wt, int state, int drawflag)
if (color_blend != NULL) {
color_blend_v3_v3(wt->wcol.inner, color_blend, wcol_state->blend);
}
+ }
- if (state & UI_ACTIVE) { /* mouse over? */
- widget_active_color(wt->wcol.inner);
- }
+ if (state & UI_ACTIVE) {
+ widget_active_color(&wt->wcol);
}
if (state & UI_BUT_REDALERT) {
@@ -3403,7 +3416,7 @@ static void widget_numbut_draw(
wcol_zone = *wcol;
copy_v3_v3_uchar(wcol_zone.item, wcol->text);
if (state & UI_STATE_ACTIVE_LEFT) {
- widget_active_color(wcol_zone.inner);
+ widget_active_color(&wcol_zone);
}
rect_zone = *rect;
@@ -3423,7 +3436,7 @@ static void widget_numbut_draw(
wcol_zone = *wcol;
copy_v3_v3_uchar(wcol_zone.item, wcol->text);
if (state & UI_STATE_ACTIVE_RIGHT) {
- widget_active_color(wcol_zone.inner);
+ widget_active_color(&wcol_zone);
}
rect_zone = *rect;
@@ -3442,7 +3455,7 @@ static void widget_numbut_draw(
wcol_zone = *wcol;
copy_v3_v3_uchar(wcol_zone.item, wcol->text);
if (!(state & (UI_STATE_ACTIVE_LEFT | UI_STATE_ACTIVE_RIGHT))) {
- widget_active_color(wcol_zone.inner);
+ widget_active_color(&wcol_zone);
}
rect_zone = *rect;
diff --git a/source/blender/editors/mask/mask_add.c b/source/blender/editors/mask/mask_add.c
index 4624611419e..5c730c74df7 100644
--- a/source/blender/editors/mask/mask_add.c
+++ b/source/blender/editors/mask/mask_add.c
@@ -55,7 +55,7 @@ bool ED_mask_find_nearest_diff_point(const bContext *C,
float tangent[2],
const bool use_deform,
const bool use_project,
- MaskLayer **masklay_r,
+ MaskLayer **mask_layer_r,
MaskSpline **spline_r,
MaskSplinePoint **point_r,
float *u_r,
@@ -64,7 +64,7 @@ bool ED_mask_find_nearest_diff_point(const bContext *C,
ScrArea *sa = CTX_wm_area(C);
ARegion *ar = CTX_wm_region(C);
- MaskLayer *point_masklay;
+ MaskLayer *point_mask_layer;
MaskSpline *point_spline;
MaskSplinePoint *point = NULL;
float dist_best_sq = FLT_MAX, co[2];
@@ -81,16 +81,16 @@ bool ED_mask_find_nearest_diff_point(const bContext *C,
co[0] = normal_co[0] * scalex;
co[1] = normal_co[1] * scaley;
- for (MaskLayer *masklay_orig = mask_orig->masklayers.first,
- *masklay_eval = mask_eval->masklayers.first;
- masklay_orig != NULL;
- masklay_orig = masklay_orig->next, masklay_eval = masklay_eval->next) {
- if (masklay_orig->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
+ for (MaskLayer *mask_layer_orig = mask_orig->masklayers.first,
+ *mask_layer_eval = mask_eval->masklayers.first;
+ mask_layer_orig != NULL;
+ mask_layer_orig = mask_layer_orig->next, mask_layer_eval = mask_layer_eval->next) {
+ if (mask_layer_orig->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
continue;
}
- for (MaskSpline *spline_orig = masklay_orig->splines.first,
- *spline_eval = masklay_eval->splines.first;
+ for (MaskSpline *spline_orig = mask_layer_orig->splines.first,
+ *spline_eval = mask_layer_eval->splines.first;
spline_orig != NULL;
spline_orig = spline_orig->next, spline_eval = spline_eval->next) {
int i;
@@ -136,7 +136,7 @@ bool ED_mask_find_nearest_diff_point(const bContext *C,
sub_v2_v2v2(tangent, &diff_points[2 * j + 2], &diff_points[2 * j]);
}
- point_masklay = masklay_orig;
+ point_mask_layer = mask_layer_orig;
point_spline = spline_orig;
point = use_deform ?
&spline_orig->points[(cur_point_eval - spline_eval->points_deform)] :
@@ -156,8 +156,8 @@ bool ED_mask_find_nearest_diff_point(const bContext *C,
}
if (point && dist_best_sq < threshold) {
- if (masklay_r) {
- *masklay_r = point_masklay;
+ if (mask_layer_r) {
+ *mask_layer_r = point_mask_layer;
}
if (spline_r) {
@@ -184,8 +184,8 @@ bool ED_mask_find_nearest_diff_point(const bContext *C,
return true;
}
- if (masklay_r) {
- *masklay_r = NULL;
+ if (mask_layer_r) {
+ *mask_layer_r = NULL;
}
if (spline_r) {
@@ -331,21 +331,22 @@ static void setup_vertex_point(Mask *mask,
/* **** add extrude vertex **** */
-static void finSelectedSplinePoint(MaskLayer *masklay,
+static void finSelectedSplinePoint(MaskLayer *mask_layer,
MaskSpline **spline,
MaskSplinePoint **point,
bool check_active)
{
- MaskSpline *cur_spline = masklay->splines.first;
+ MaskSpline *cur_spline = mask_layer->splines.first;
*spline = NULL;
*point = NULL;
if (check_active) {
/* TODO, having an active point but no active spline is possible, why? */
- if (masklay->act_spline && masklay->act_point && MASKPOINT_ISSEL_ANY(masklay->act_point)) {
- *spline = masklay->act_spline;
- *point = masklay->act_point;
+ if (mask_layer->act_spline && mask_layer->act_point &&
+ MASKPOINT_ISSEL_ANY(mask_layer->act_point)) {
+ *spline = mask_layer->act_spline;
+ *point = mask_layer->act_point;
return;
}
}
@@ -397,7 +398,7 @@ static void mask_spline_add_point_at_index(MaskSpline *spline, int point_index)
static bool add_vertex_subdivide(const bContext *C, Mask *mask, const float co[2])
{
- MaskLayer *masklay;
+ MaskLayer *mask_layer;
MaskSpline *spline;
MaskSplinePoint *point = NULL;
const float threshold = 9;
@@ -412,7 +413,7 @@ static bool add_vertex_subdivide(const bContext *C, Mask *mask, const float co[2
tangent,
true,
true,
- &masklay,
+ &mask_layer,
&spline,
&point,
&u,
@@ -432,14 +433,14 @@ static bool add_vertex_subdivide(const bContext *C, Mask *mask, const float co[2
setup_vertex_point(mask, spline, new_point, co, u, ctime, NULL, true);
/* TODO - we could pass the spline! */
- BKE_mask_layer_shape_changed_add(masklay,
- BKE_mask_layer_shape_spline_to_index(masklay, spline) +
+ BKE_mask_layer_shape_changed_add(mask_layer,
+ BKE_mask_layer_shape_spline_to_index(mask_layer, spline) +
point_index + 1,
true,
true);
- masklay->act_spline = spline;
- masklay->act_point = new_point;
+ mask_layer->act_spline = spline;
+ mask_layer->act_point = new_point;
WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask);
@@ -451,7 +452,7 @@ static bool add_vertex_subdivide(const bContext *C, Mask *mask, const float co[2
static bool add_vertex_extrude(const bContext *C,
Mask *mask,
- MaskLayer *masklay,
+ MaskLayer *mask_layer,
const float co[2])
{
Scene *scene = CTX_data_scene(C);
@@ -468,11 +469,11 @@ static bool add_vertex_extrude(const bContext *C,
bool do_cyclic_correct = false;
bool do_prev; /* use prev point rather then next?? */
- if (!masklay) {
+ if (!mask_layer) {
return false;
}
else {
- finSelectedSplinePoint(masklay, &spline, &point, true);
+ finSelectedSplinePoint(mask_layer, &spline, &point, true);
}
ED_mask_select_toggle_all(mask, SEL_DESELECT);
@@ -533,14 +534,17 @@ static bool add_vertex_extrude(const bContext *C,
new_point = &spline->points[point_index + 1];
}
- masklay->act_point = new_point;
+ mask_layer->act_point = new_point;
setup_vertex_point(mask, spline, new_point, co, 0.5f, ctime, ref_point, false);
- if (masklay->splines_shapes.first) {
+ if (mask_layer->splines_shapes.first) {
point_index = (((int)(new_point - spline->points) + 0) % spline->tot_point);
- BKE_mask_layer_shape_changed_add(
- masklay, BKE_mask_layer_shape_spline_to_index(masklay, spline) + point_index, true, true);
+ BKE_mask_layer_shape_changed_add(mask_layer,
+ BKE_mask_layer_shape_spline_to_index(mask_layer, spline) +
+ point_index,
+ true,
+ true);
}
WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask);
@@ -548,7 +552,7 @@ static bool add_vertex_extrude(const bContext *C,
return true;
}
-static bool add_vertex_new(const bContext *C, Mask *mask, MaskLayer *masklay, const float co[2])
+static bool add_vertex_new(const bContext *C, Mask *mask, MaskLayer *mask_layer, const float co[2])
{
Scene *scene = CTX_data_scene(C);
const float ctime = CFRA;
@@ -556,27 +560,30 @@ static bool add_vertex_new(const bContext *C, Mask *mask, MaskLayer *masklay, co
MaskSpline *spline;
MaskSplinePoint *new_point = NULL, *ref_point = NULL;
- if (!masklay) {
- /* if there's no masklay currently operationg on, create new one */
- masklay = BKE_mask_layer_new(mask, "");
+ if (!mask_layer) {
+ /* if there's no mask layer currently operationg on, create new one */
+ mask_layer = BKE_mask_layer_new(mask, "");
mask->masklay_act = mask->masklay_tot - 1;
}
ED_mask_select_toggle_all(mask, SEL_DESELECT);
- spline = BKE_mask_spline_add(masklay);
+ spline = BKE_mask_spline_add(mask_layer);
- masklay->act_spline = spline;
+ mask_layer->act_spline = spline;
new_point = spline->points;
- masklay->act_point = new_point;
+ mask_layer->act_point = new_point;
setup_vertex_point(mask, spline, new_point, co, 0.5f, ctime, ref_point, false);
{
int point_index = (((int)(new_point - spline->points) + 0) % spline->tot_point);
- BKE_mask_layer_shape_changed_add(
- masklay, BKE_mask_layer_shape_spline_to_index(masklay, spline) + point_index, true, true);
+ BKE_mask_layer_shape_changed_add(mask_layer,
+ BKE_mask_layer_shape_spline_to_index(mask_layer, spline) +
+ point_index,
+ true,
+ true);
}
WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask);
@@ -584,69 +591,112 @@ static bool add_vertex_new(const bContext *C, Mask *mask, MaskLayer *masklay, co
return true;
}
-static int add_vertex_exec(bContext *C, wmOperator *op)
+/* Convert coordinate from normalized space to pixel one.
+ * TODO(sergey): Make the function more generally available. */
+static void mask_point_make_pixel_space(bContext *C,
+ float point_normalized[2],
+ float point_pixel[2])
{
- Mask *mask = CTX_data_edit_mask(C);
- MaskLayer *masklay;
+ ScrArea *sa = CTX_wm_area(C);
+ ARegion *ar = CTX_wm_region(C);
- float co[2];
+ float scalex, scaley;
+ ED_mask_pixelspace_factor(sa, ar, &scalex, &scaley);
- if (mask == NULL) {
- /* if there's no active mask, create one */
- mask = ED_mask_new(C, NULL);
+ point_pixel[0] = point_normalized[0] * scalex;
+ point_pixel[1] = point_normalized[1] * scaley;
+}
+
+static int add_vertex_handle_cyclic_at_point(bContext *C,
+ Mask *mask,
+ MaskSpline *spline,
+ MaskSplinePoint *active_point,
+ MaskSplinePoint *other_point,
+ float co[2])
+{
+ const float tolerance_in_pixels_squared = 4 * 4;
+
+ if (spline->flag & MASK_SPLINE_CYCLIC) {
+ /* No cycling toggle needed, we've got nothing meaningful to do in this operator. */
+ return OPERATOR_CANCELLED;
}
- masklay = BKE_mask_layer_active(mask);
+ float co_pixel[2];
+ mask_point_make_pixel_space(C, co, co_pixel);
+
+ float point_pixel[2];
+ mask_point_make_pixel_space(C, other_point->bezt.vec[1], point_pixel);
- if (masklay && masklay->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
- masklay = NULL;
+ const float dist_squared = len_squared_v2v2(co_pixel, point_pixel);
+ if (dist_squared > tolerance_in_pixels_squared) {
+ return OPERATOR_PASS_THROUGH;
}
- RNA_float_get_array(op->ptr, "location", co);
+ spline->flag |= MASK_SPLINE_CYCLIC;
- /* TODO, having an active point but no active spline is possible, why? */
- if (masklay && masklay->act_spline && masklay->act_point &&
- MASKPOINT_ISSEL_ANY(masklay->act_point)) {
+ /* TODO, update keyframes in time. */
+ BKE_mask_calc_handle_point_auto(spline, active_point, false);
+ BKE_mask_calc_handle_point_auto(spline, other_point, false);
- /* cheap trick - double click for cyclic */
- MaskSpline *spline = masklay->act_spline;
- MaskSplinePoint *point = masklay->act_point;
+ DEG_id_tag_update(&mask->id, ID_RECALC_GEOMETRY);
- const bool is_sta = (point == spline->points);
- const bool is_end = (point == &spline->points[spline->tot_point - 1]);
+ WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask);
- /* then check are we overlapping the mouse */
- if ((is_sta || is_end) && equals_v2v2(co, point->bezt.vec[1])) {
- if (spline->flag & MASK_SPLINE_CYCLIC) {
- /* nothing to do */
- return OPERATOR_CANCELLED;
- }
- else {
- /* recalc the connecting point as well to make a nice even curve */
- MaskSplinePoint *point_other = is_end ? spline->points :
- &spline->points[spline->tot_point - 1];
- spline->flag |= MASK_SPLINE_CYCLIC;
+ return OPERATOR_FINISHED;
+}
- /* TODO, update keyframes in time */
- BKE_mask_calc_handle_point_auto(spline, point, false);
- BKE_mask_calc_handle_point_auto(spline, point_other, false);
+static int add_vertex_handle_cyclic(
+ bContext *C, Mask *mask, MaskSpline *spline, MaskSplinePoint *active_point, float co[2])
+{
+ MaskSplinePoint *first_point = &spline->points[0];
+ MaskSplinePoint *last_point = &spline->points[spline->tot_point - 1];
+ const bool is_first_point_active = (active_point == first_point);
+ const bool is_last_point_active = (active_point == last_point);
+ if (is_last_point_active) {
+ return add_vertex_handle_cyclic_at_point(C, mask, spline, active_point, first_point, co);
+ }
+ else if (is_first_point_active) {
+ return add_vertex_handle_cyclic_at_point(C, mask, spline, active_point, last_point, co);
+ }
+ return OPERATOR_PASS_THROUGH;
+}
- DEG_id_tag_update(&mask->id, ID_RECALC_GEOMETRY);
+static int add_vertex_exec(bContext *C, wmOperator *op)
+{
+ Mask *mask = CTX_data_edit_mask(C);
+ if (mask == NULL) {
+ /* if there's no active mask, create one */
+ mask = ED_mask_new(C, NULL);
+ }
- WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask);
- return OPERATOR_FINISHED;
- }
+ MaskLayer *mask_layer = BKE_mask_layer_active(mask);
+
+ if (mask_layer && mask_layer->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
+ mask_layer = NULL;
+ }
+
+ float co[2];
+ RNA_float_get_array(op->ptr, "location", co);
+
+ /* TODO, having an active point but no active spline is possible, why? */
+ if (mask_layer && mask_layer->act_spline && mask_layer->act_point &&
+ MASKPOINT_ISSEL_ANY(mask_layer->act_point)) {
+ MaskSpline *spline = mask_layer->act_spline;
+ MaskSplinePoint *active_point = mask_layer->act_point;
+ const int cyclic_result = add_vertex_handle_cyclic(C, mask, spline, active_point, co);
+ if (cyclic_result != OPERATOR_PASS_THROUGH) {
+ return cyclic_result;
}
if (!add_vertex_subdivide(C, mask, co)) {
- if (!add_vertex_extrude(C, mask, masklay, co)) {
+ if (!add_vertex_extrude(C, mask, mask_layer, co)) {
return OPERATOR_CANCELLED;
}
}
}
else {
if (!add_vertex_subdivide(C, mask, co)) {
- if (!add_vertex_new(C, mask, masklay, co)) {
+ if (!add_vertex_new(C, mask, mask_layer, co)) {
return OPERATOR_CANCELLED;
}
}
@@ -704,7 +754,7 @@ void MASK_OT_add_vertex(wmOperatorType *ot)
static int add_feather_vertex_exec(bContext *C, wmOperator *op)
{
Mask *mask = CTX_data_edit_mask(C);
- MaskLayer *masklay;
+ MaskLayer *mask_layer;
MaskSpline *spline;
MaskSplinePoint *point = NULL;
const float threshold = 9;
@@ -717,8 +767,19 @@ static int add_feather_vertex_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
- if (ED_mask_find_nearest_diff_point(
- C, mask, co, threshold, true, NULL, true, true, &masklay, &spline, &point, &u, NULL)) {
+ if (ED_mask_find_nearest_diff_point(C,
+ mask,
+ co,
+ threshold,
+ true,
+ NULL,
+ true,
+ true,
+ &mask_layer,
+ &spline,
+ &point,
+ &u,
+ NULL)) {
float w = BKE_mask_point_weight(spline, point, u);
float weight_scalar = BKE_mask_point_weight_scalar(spline, point, u);
diff --git a/source/blender/editors/mask/mask_draw.c b/source/blender/editors/mask/mask_draw.c
index 7247697dcb7..71aa860d703 100644
--- a/source/blender/editors/mask/mask_draw.c
+++ b/source/blender/editors/mask/mask_draw.c
@@ -38,6 +38,7 @@
#include "ED_clip.h"
#include "ED_mask.h" /* own include */
+#include "ED_screen.h"
#include "ED_space_api.h"
#include "BIF_glutil.h"
@@ -55,13 +56,13 @@
#include "mask_intern.h" /* own include */
-static void mask_spline_color_get(MaskLayer *masklay,
+static void mask_spline_color_get(MaskLayer *mask_layer,
MaskSpline *spline,
const bool is_sel,
unsigned char r_rgb[4])
{
if (is_sel) {
- if (masklay->act_spline == spline) {
+ if (mask_layer->act_spline == spline) {
r_rgb[0] = r_rgb[1] = r_rgb[2] = 255;
}
else {
@@ -77,7 +78,7 @@ static void mask_spline_color_get(MaskLayer *masklay,
r_rgb[3] = 255;
}
-static void mask_spline_feather_color_get(MaskLayer *UNUSED(masklay),
+static void mask_spline_feather_color_get(MaskLayer *UNUSED(mask_layer),
MaskSpline *UNUSED(spline),
const bool is_sel,
unsigned char r_rgb[4])
@@ -186,13 +187,13 @@ static void draw_single_handle(const MaskLayer *mask_layer,
/* return non-zero if spline is selected */
static void draw_spline_points(const bContext *C,
- MaskLayer *masklay,
+ MaskLayer *mask_layer,
MaskSpline *spline,
const char draw_flag,
const char draw_type)
{
const bool is_spline_sel = (spline->flag & SELECT) &&
- (masklay->restrictflag & MASK_RESTRICT_SELECT) == 0;
+ (mask_layer->restrictflag & MASK_RESTRICT_SELECT) == 0;
const bool is_smooth = (draw_flag & MASK_DRAWFLAG_SMOOTH) != 0;
unsigned char rgb_spline[4];
@@ -215,7 +216,7 @@ static void draw_spline_points(const bContext *C,
/* TODO, add this to sequence editor */
float handle_size = 2.0f * UI_GetThemeValuef(TH_HANDLE_VERTEX_SIZE) * U.pixelsize;
- mask_spline_color_get(masklay, spline, is_spline_sel, rgb_spline);
+ mask_spline_color_get(mask_layer, spline, is_spline_sel, rgb_spline);
GPUVertFormat *format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
@@ -248,7 +249,7 @@ static void draw_spline_points(const bContext *C,
}
if (sel) {
- if (point == masklay->act_point) {
+ if (point == mask_layer->act_point) {
immUniformColor3f(1.0f, 1.0f, 1.0f);
}
else {
@@ -299,7 +300,7 @@ static void draw_spline_points(const bContext *C,
mask_point_undistort_pos(sc, handle, handle);
}
draw_single_handle(
- masklay, point, MASK_WHICH_HANDLE_STICK, draw_type, handle_size, vert, handle);
+ mask_layer, point, MASK_WHICH_HANDLE_STICK, draw_type, handle_size, vert, handle);
}
else {
float handle_left[2], handle_right[2];
@@ -310,9 +311,9 @@ static void draw_spline_points(const bContext *C,
mask_point_undistort_pos(sc, handle_left, handle_left);
}
draw_single_handle(
- masklay, point, MASK_WHICH_HANDLE_LEFT, draw_type, handle_size, vert, handle_left);
+ mask_layer, point, MASK_WHICH_HANDLE_LEFT, draw_type, handle_size, vert, handle_left);
draw_single_handle(
- masklay, point, MASK_WHICH_HANDLE_RIGHT, draw_type, handle_size, vert, handle_right);
+ mask_layer, point, MASK_WHICH_HANDLE_RIGHT, draw_type, handle_size, vert, handle_right);
}
/* bind program in loop so it does not interfere with draw_single_handle */
@@ -320,7 +321,7 @@ static void draw_spline_points(const bContext *C,
/* draw CV point */
if (MASKPOINT_ISSEL_KNOT(point)) {
- if (point == masklay->act_point) {
+ if (point == mask_layer->act_point) {
immUniformColor3f(1.0f, 1.0f, 1.0f);
}
else {
@@ -351,7 +352,7 @@ static void draw_spline_points(const bContext *C,
immBindBuiltinProgram(GPU_SHADER_2D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_OUTLINE_AA);
immUniform1f("outlineWidth", 1.5f);
- if (masklay->act_spline == spline) {
+ if (mask_layer->act_spline == spline) {
immUniformColor3f(1.0f, 1.0f, 1.0f);
}
else {
@@ -518,7 +519,7 @@ static void mask_draw_curve_type(const bContext *C,
}
static void draw_spline_curve(const bContext *C,
- MaskLayer *masklay,
+ MaskLayer *mask_layer,
MaskSpline *spline,
const char draw_flag,
const char draw_type,
@@ -532,7 +533,7 @@ static void draw_spline_curve(const bContext *C,
unsigned char rgb_tmp[4];
const bool is_spline_sel = (spline->flag & SELECT) &&
- (masklay->restrictflag & MASK_RESTRICT_SELECT) == 0;
+ (mask_layer->restrictflag & MASK_RESTRICT_SELECT) == 0;
const bool is_smooth = (draw_flag & MASK_DRAWFLAG_SMOOTH) != 0;
const bool is_fill = (spline->flag & MASK_SPLINE_NOFILL) == 0;
@@ -556,7 +557,7 @@ static void draw_spline_curve(const bContext *C,
spline, &tot_feather_point, resol, (is_fill != false));
/* draw feather */
- mask_spline_feather_color_get(masklay, spline, is_spline_sel, rgb_tmp);
+ mask_spline_feather_color_get(mask_layer, spline, is_spline_sel, rgb_tmp);
mask_draw_curve_type(
C, spline, feather_points, tot_feather_point, true, is_active, rgb_tmp, draw_type);
@@ -580,7 +581,7 @@ static void draw_spline_curve(const bContext *C,
MEM_freeN(feather_points);
/* draw main curve */
- mask_spline_color_get(masklay, spline, is_spline_sel, rgb_tmp);
+ mask_spline_color_get(mask_layer, spline, is_spline_sel, rgb_tmp);
mask_draw_curve_type(
C, spline, diff_points, tot_diff_point, false, is_active, rgb_tmp, draw_type);
MEM_freeN(diff_points);
@@ -590,37 +591,37 @@ static void draw_spline_curve(const bContext *C,
}
}
-static void draw_masklays(const bContext *C,
- Mask *mask,
- const char draw_flag,
- const char draw_type,
- const int width,
- const int height)
+static void draw_mask_layers(const bContext *C,
+ Mask *mask,
+ const char draw_flag,
+ const char draw_type,
+ const int width,
+ const int height)
{
GPU_blend(true);
GPU_blend_set_func_separate(
GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
GPU_program_point_size(true);
- MaskLayer *masklay;
+ MaskLayer *mask_layer;
int i;
- for (masklay = mask->masklayers.first, i = 0; masklay; masklay = masklay->next, i++) {
- MaskSpline *spline;
+ for (mask_layer = mask->masklayers.first, i = 0; mask_layer != NULL;
+ mask_layer = mask_layer->next, i++) {
const bool is_active = (i == mask->masklay_act);
- if (masklay->restrictflag & MASK_RESTRICT_VIEW) {
+ if (mask_layer->restrictflag & MASK_RESTRICT_VIEW) {
continue;
}
- for (spline = masklay->splines.first; spline; spline = spline->next) {
+ for (MaskSpline *spline = mask_layer->splines.first; spline; spline = spline->next) {
/* draw curve itself first... */
- draw_spline_curve(C, masklay, spline, draw_flag, draw_type, is_active, width, height);
+ draw_spline_curve(C, mask_layer, spline, draw_flag, draw_type, is_active, width, height);
- if (!(masklay->restrictflag & MASK_RESTRICT_SELECT)) {
+ if (!(mask_layer->restrictflag & MASK_RESTRICT_SELECT)) {
/* ...and then handles over the curve so they're nicely visible */
- draw_spline_points(C, masklay, spline, draw_flag, draw_type);
+ draw_spline_points(C, mask_layer, spline, draw_flag, draw_type);
}
/* show undeform for testing */
@@ -628,8 +629,8 @@ static void draw_masklays(const bContext *C,
void *back = spline->points_deform;
spline->points_deform = NULL;
- draw_spline_curve(C, masklay, spline, draw_flag, draw_type, is_active, width, height);
- draw_spline_points(C, masklay, spline, draw_flag, draw_type);
+ draw_spline_curve(C, mask_layer, spline, draw_flag, draw_type, is_active, width, height);
+ draw_spline_points(C, mask_layer, spline, draw_flag, draw_type);
spline->points_deform = back;
}
}
@@ -651,7 +652,7 @@ void ED_mask_draw(const bContext *C, const char draw_flag, const char draw_type)
ED_mask_get_size(sa, &width, &height);
- draw_masklays(C, mask, draw_flag, draw_type, width, height);
+ draw_mask_layers(C, mask, draw_flag, draw_type, width, height);
}
static float *mask_rasterize(Mask *mask, const int width, const int height)
@@ -783,7 +784,7 @@ void ED_mask_draw_region(
}
/* draw! */
- draw_masklays(C, mask_eval, draw_flag, draw_type, width, height);
+ draw_mask_layers(C, mask_eval, draw_flag, draw_type, width, height);
if (do_draw_cb) {
ED_region_draw_cb_draw(C, ar, REGION_DRAW_POST_VIEW);
@@ -796,32 +797,39 @@ void ED_mask_draw_frames(Mask *mask, ARegion *ar, const int cfra, const int sfra
{
const float framelen = ar->winx / (float)(efra - sfra + 1);
- MaskLayer *masklay = BKE_mask_layer_active(mask);
+ MaskLayer *mask_layer = BKE_mask_layer_active(mask);
+ if (mask_layer == NULL) {
+ return;
+ }
- if (masklay) {
- unsigned int num_lines = BLI_listbase_count(&masklay->splines_shapes);
+ unsigned int num_lines = BLI_listbase_count(&mask_layer->splines_shapes);
+ if (num_lines == 0) {
+ return;
+ }
- if (num_lines > 0) {
- uint pos = GPU_vertformat_attr_add(
- immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
+ /* Local coordinate visible rect inside region, to accommodate overlapping ui. */
+ const rcti *rect_visible = ED_region_visible_rect(ar);
+ const int region_bottom = rect_visible->ymin;
- immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
- immUniformColor4ub(255, 175, 0, 255);
+ uint pos = GPU_vertformat_attr_add(
+ immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
- immBegin(GPU_PRIM_LINES, 2 * num_lines);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor4ub(255, 175, 0, 255);
- for (MaskLayerShape *masklay_shape = masklay->splines_shapes.first; masklay_shape;
- masklay_shape = masklay_shape->next) {
- int frame = masklay_shape->frame;
+ immBegin(GPU_PRIM_LINES, 2 * num_lines);
- /* draw_keyframe(i, CFRA, sfra, framelen, 1); */
- int height = (frame == cfra) ? 22 : 10;
- int x = (frame - sfra) * framelen;
- immVertex2i(pos, x, 0);
- immVertex2i(pos, x, height);
- }
- immEnd();
- immUnbindProgram();
- }
+ for (MaskLayerShape *mask_layer_shape = mask_layer->splines_shapes.first;
+ mask_layer_shape != NULL;
+ mask_layer_shape = mask_layer_shape->next) {
+ int frame = mask_layer_shape->frame;
+
+ /* draw_keyframe(i, CFRA, sfra, framelen, 1); */
+ int height = (frame == cfra) ? 22 : 10;
+ int x = (frame - sfra) * framelen;
+ immVertex2i(pos, x, region_bottom);
+ immVertex2i(pos, x, region_bottom + height * UI_DPI_FAC);
}
+ immEnd();
+ immUnbindProgram();
}
diff --git a/source/blender/editors/mask/mask_edit.c b/source/blender/editors/mask/mask_edit.c
index 0c5591ed89b..56d8ef56160 100644
--- a/source/blender/editors/mask/mask_edit.c
+++ b/source/blender/editors/mask/mask_edit.c
@@ -371,7 +371,6 @@ void ED_mask_cursor_location_get(ScrArea *sa, float cursor[2])
bool ED_mask_selected_minmax(const bContext *C, float min[2], float max[2])
{
Mask *mask = CTX_data_edit_mask(C);
- MaskLayer *mask_layer;
bool ok = false;
if (mask == NULL) {
@@ -379,15 +378,14 @@ bool ED_mask_selected_minmax(const bContext *C, float min[2], float max[2])
}
INIT_MINMAX2(min, max);
- for (mask_layer = mask->masklayers.first; mask_layer != NULL; mask_layer = mask_layer->next) {
- MaskSpline *spline;
+ for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer != NULL;
+ mask_layer = mask_layer->next) {
if (mask_layer->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
continue;
}
- for (spline = mask_layer->splines.first; spline != NULL; spline = spline->next) {
+ for (MaskSpline *spline = mask_layer->splines.first; spline != NULL; spline = spline->next) {
MaskSplinePoint *points_array = BKE_mask_spline_point_array(spline);
- int i;
- for (i = 0; i < spline->tot_point; i++) {
+ for (int i = 0; i < spline->tot_point; i++) {
MaskSplinePoint *point = &spline->points[i];
MaskSplinePoint *deform_point = &points_array[i];
BezTriple *bezt = &point->bezt;
diff --git a/source/blender/editors/mask/mask_editaction.c b/source/blender/editors/mask/mask_editaction.c
index 985fa58cace..33f4bab14ec 100644
--- a/source/blender/editors/mask/mask_editaction.c
+++ b/source/blender/editors/mask/mask_editaction.c
@@ -53,22 +53,22 @@
/* Generics - Loopers */
/* Loops over the mask-frames for a mask-layer, and applies the given callback */
-bool ED_masklayer_frames_looper(MaskLayer *masklay,
+bool ED_masklayer_frames_looper(MaskLayer *mask_layer,
Scene *scene,
- short (*masklay_shape_cb)(MaskLayerShape *, Scene *))
+ short (*mask_layer_shape_cb)(MaskLayerShape *, Scene *))
{
- MaskLayerShape *masklay_shape;
+ MaskLayerShape *mask_layer_shape;
/* error checker */
- if (masklay == NULL) {
+ if (mask_layer == NULL) {
return false;
}
/* do loop */
- for (masklay_shape = masklay->splines_shapes.first; masklay_shape;
- masklay_shape = masklay_shape->next) {
+ for (mask_layer_shape = mask_layer->splines_shapes.first; mask_layer_shape;
+ mask_layer_shape = mask_layer_shape->next) {
/* execute callback */
- if (masklay_shape_cb(masklay_shape, scene)) {
+ if (mask_layer_shape_cb(mask_layer_shape, scene)) {
return true;
}
}
@@ -81,24 +81,24 @@ bool ED_masklayer_frames_looper(MaskLayer *masklay,
/* Data Conversion Tools */
/* make a listing all the mask-frames in a layer as cfraelems */
-void ED_masklayer_make_cfra_list(MaskLayer *masklay, ListBase *elems, bool onlysel)
+void ED_masklayer_make_cfra_list(MaskLayer *mask_layer, ListBase *elems, bool onlysel)
{
- MaskLayerShape *masklay_shape;
+ MaskLayerShape *mask_layer_shape;
CfraElem *ce;
/* error checking */
- if (ELEM(NULL, masklay, elems)) {
+ if (ELEM(NULL, mask_layer, elems)) {
return;
}
/* loop through mask-frames, adding */
- for (masklay_shape = masklay->splines_shapes.first; masklay_shape;
- masklay_shape = masklay_shape->next) {
- if ((onlysel == false) || (masklay_shape->flag & MASK_SHAPE_SELECT)) {
+ for (mask_layer_shape = mask_layer->splines_shapes.first; mask_layer_shape;
+ mask_layer_shape = mask_layer_shape->next) {
+ if ((onlysel == false) || (mask_layer_shape->flag & MASK_SHAPE_SELECT)) {
ce = MEM_callocN(sizeof(CfraElem), "CfraElem");
- ce->cfra = (float)masklay_shape->frame;
- ce->sel = (masklay_shape->flag & MASK_SHAPE_SELECT) ? 1 : 0;
+ ce->cfra = (float)mask_layer_shape->frame;
+ ce->sel = (mask_layer_shape->flag & MASK_SHAPE_SELECT) ? 1 : 0;
BLI_addtail(elems, ce);
}
@@ -109,19 +109,19 @@ void ED_masklayer_make_cfra_list(MaskLayer *masklay, ListBase *elems, bool onlys
/* Selection Tools */
/* check if one of the frames in this layer is selected */
-bool ED_masklayer_frame_select_check(MaskLayer *masklay)
+bool ED_masklayer_frame_select_check(MaskLayer *mask_layer)
{
- MaskLayerShape *masklay_shape;
+ MaskLayerShape *mask_layer_shape;
/* error checking */
- if (masklay == NULL) {
+ if (mask_layer == NULL) {
return 0;
}
/* stop at the first one found */
- for (masklay_shape = masklay->splines_shapes.first; masklay_shape;
- masklay_shape = masklay_shape->next) {
- if (masklay_shape->flag & MASK_SHAPE_SELECT) {
+ for (mask_layer_shape = mask_layer->splines_shapes.first; mask_layer_shape;
+ mask_layer_shape = mask_layer_shape->next) {
+ if (mask_layer_shape->flag & MASK_SHAPE_SELECT) {
return 1;
}
}
@@ -131,120 +131,120 @@ bool ED_masklayer_frame_select_check(MaskLayer *masklay)
}
/* helper function - select mask-frame based on SELECT_* mode */
-static void masklayshape_select(MaskLayerShape *masklay_shape, short select_mode)
+static void mask_layer_shape_select(MaskLayerShape *mask_layer_shape, short select_mode)
{
- if (masklay_shape == NULL) {
+ if (mask_layer_shape == NULL) {
return;
}
switch (select_mode) {
case SELECT_ADD:
- masklay_shape->flag |= MASK_SHAPE_SELECT;
+ mask_layer_shape->flag |= MASK_SHAPE_SELECT;
break;
case SELECT_SUBTRACT:
- masklay_shape->flag &= ~MASK_SHAPE_SELECT;
+ mask_layer_shape->flag &= ~MASK_SHAPE_SELECT;
break;
case SELECT_INVERT:
- masklay_shape->flag ^= MASK_SHAPE_SELECT;
+ mask_layer_shape->flag ^= MASK_SHAPE_SELECT;
break;
}
}
/* set all/none/invert select (like above, but with SELECT_* modes) */
-void ED_mask_select_frames(MaskLayer *masklay, short select_mode)
+void ED_mask_select_frames(MaskLayer *mask_layer, short select_mode)
{
- MaskLayerShape *masklay_shape;
+ MaskLayerShape *mask_layer_shape;
/* error checking */
- if (masklay == NULL) {
+ if (mask_layer == NULL) {
return;
}
/* handle according to mode */
- for (masklay_shape = masklay->splines_shapes.first; masklay_shape;
- masklay_shape = masklay_shape->next) {
- masklayshape_select(masklay_shape, select_mode);
+ for (mask_layer_shape = mask_layer->splines_shapes.first; mask_layer_shape;
+ mask_layer_shape = mask_layer_shape->next) {
+ mask_layer_shape_select(mask_layer_shape, select_mode);
}
}
/* set all/none/invert select */
-void ED_masklayer_frame_select_set(MaskLayer *masklay, short mode)
+void ED_masklayer_frame_select_set(MaskLayer *mask_layer, short mode)
{
/* error checking */
- if (masklay == NULL) {
+ if (mask_layer == NULL) {
return;
}
/* now call the standard function */
- ED_mask_select_frames(masklay, mode);
+ ED_mask_select_frames(mask_layer, mode);
}
/* select the frame in this layer that occurs on this frame (there should only be one at most) */
-void ED_mask_select_frame(MaskLayer *masklay, int selx, short select_mode)
+void ED_mask_select_frame(MaskLayer *mask_layer, int selx, short select_mode)
{
- MaskLayerShape *masklay_shape;
+ MaskLayerShape *mask_layer_shape;
- if (masklay == NULL) {
+ if (mask_layer == NULL) {
return;
}
- masklay_shape = BKE_mask_layer_shape_find_frame(masklay, selx);
+ mask_layer_shape = BKE_mask_layer_shape_find_frame(mask_layer, selx);
- if (masklay_shape) {
- masklayshape_select(masklay_shape, select_mode);
+ if (mask_layer_shape) {
+ mask_layer_shape_select(mask_layer_shape, select_mode);
}
}
/* select the frames in this layer that occur within the bounds specified */
-void ED_masklayer_frames_select_box(MaskLayer *masklay, float min, float max, short select_mode)
+void ED_masklayer_frames_select_box(MaskLayer *mask_layer, float min, float max, short select_mode)
{
- MaskLayerShape *masklay_shape;
+ MaskLayerShape *mask_layer_shape;
- if (masklay == NULL) {
+ if (mask_layer == NULL) {
return;
}
/* only select those frames which are in bounds */
- for (masklay_shape = masklay->splines_shapes.first; masklay_shape;
- masklay_shape = masklay_shape->next) {
- if (IN_RANGE(masklay_shape->frame, min, max)) {
- masklayshape_select(masklay_shape, select_mode);
+ for (mask_layer_shape = mask_layer->splines_shapes.first; mask_layer_shape;
+ mask_layer_shape = mask_layer_shape->next) {
+ if (IN_RANGE(mask_layer_shape->frame, min, max)) {
+ mask_layer_shape_select(mask_layer_shape, select_mode);
}
}
}
/* select the frames in this layer that occur within the lasso/circle region specified */
void ED_masklayer_frames_select_region(KeyframeEditData *ked,
- MaskLayer *masklay,
+ MaskLayer *mask_layer,
short tool,
short select_mode)
{
- MaskLayerShape *masklay_shape;
+ MaskLayerShape *mask_layer_shape;
- if (masklay == NULL) {
+ if (mask_layer == NULL) {
return;
}
/* only select frames which are within the region */
- for (masklay_shape = masklay->splines_shapes.first; masklay_shape;
- masklay_shape = masklay_shape->next) {
+ for (mask_layer_shape = mask_layer->splines_shapes.first; mask_layer_shape;
+ mask_layer_shape = mask_layer_shape->next) {
/* construct a dummy point coordinate to do this testing with */
float pt[2] = {0};
- pt[0] = masklay_shape->frame;
+ pt[0] = mask_layer_shape->frame;
pt[1] = ked->channel_y;
/* check the necessary regions */
if (tool == BEZT_OK_CHANNEL_LASSO) {
/* Lasso */
if (keyframe_region_lasso_test(ked->data, pt)) {
- masklayshape_select(masklay_shape, select_mode);
+ mask_layer_shape_select(mask_layer_shape, select_mode);
}
}
else if (tool == BEZT_OK_CHANNEL_CIRCLE) {
/* Circle */
if (keyframe_region_circle_test(ked->data, pt)) {
- masklayshape_select(masklay_shape, select_mode);
+ mask_layer_shape_select(mask_layer_shape, select_mode);
}
}
}
@@ -254,23 +254,23 @@ void ED_masklayer_frames_select_region(KeyframeEditData *ked,
/* Frame Editing Tools */
/* Delete selected frames */
-bool ED_masklayer_frames_delete(MaskLayer *masklay)
+bool ED_masklayer_frames_delete(MaskLayer *mask_layer)
{
- MaskLayerShape *masklay_shape, *masklay_shape_next;
+ MaskLayerShape *mask_layer_shape, *mask_layer_shape_next;
bool changed = false;
/* error checking */
- if (masklay == NULL) {
+ if (mask_layer == NULL) {
return false;
}
/* check for frames to delete */
- for (masklay_shape = masklay->splines_shapes.first; masklay_shape;
- masklay_shape = masklay_shape_next) {
- masklay_shape_next = masklay_shape->next;
+ for (mask_layer_shape = mask_layer->splines_shapes.first; mask_layer_shape;
+ mask_layer_shape = mask_layer_shape_next) {
+ mask_layer_shape_next = mask_layer_shape->next;
- if (masklay_shape->flag & MASK_SHAPE_SELECT) {
- BKE_mask_layer_shape_unlink(masklay, masklay_shape);
+ if (mask_layer_shape->flag & MASK_SHAPE_SELECT) {
+ BKE_mask_layer_shape_unlink(mask_layer, mask_layer_shape);
changed = true;
}
}
@@ -279,29 +279,30 @@ bool ED_masklayer_frames_delete(MaskLayer *masklay)
}
/* Duplicate selected frames from given mask-layer */
-void ED_masklayer_frames_duplicate(MaskLayer *masklay)
+void ED_masklayer_frames_duplicate(MaskLayer *mask_layer)
{
- MaskLayerShape *masklay_shape, *gpfn;
+ MaskLayerShape *mask_layer_shape, *gpfn;
/* error checking */
- if (masklay == NULL) {
+ if (mask_layer == NULL) {
return;
}
/* duplicate selected frames */
- for (masklay_shape = masklay->splines_shapes.first; masklay_shape; masklay_shape = gpfn) {
- gpfn = masklay_shape->next;
+ for (mask_layer_shape = mask_layer->splines_shapes.first; mask_layer_shape;
+ mask_layer_shape = gpfn) {
+ gpfn = mask_layer_shape->next;
/* duplicate this frame */
- if (masklay_shape->flag & MASK_SHAPE_SELECT) {
+ if (mask_layer_shape->flag & MASK_SHAPE_SELECT) {
MaskLayerShape *mask_shape_dupe;
/* duplicate frame, and deselect self */
- mask_shape_dupe = BKE_mask_layer_shape_duplicate(masklay_shape);
- masklay_shape->flag &= ~MASK_SHAPE_SELECT;
+ mask_shape_dupe = BKE_mask_layer_shape_duplicate(mask_layer_shape);
+ mask_layer_shape->flag &= ~MASK_SHAPE_SELECT;
/* XXX - how to handle duplicate frames? */
- BLI_insertlinkafter(&masklay->splines_shapes, masklay_shape, mask_shape_dupe);
+ BLI_insertlinkafter(&mask_layer->splines_shapes, mask_layer_shape, mask_shape_dupe);
}
}
}
@@ -309,55 +310,55 @@ void ED_masklayer_frames_duplicate(MaskLayer *masklay)
/* -------------------------------------- */
/* Snap Tools */
-static short snap_masklayer_nearest(MaskLayerShape *masklay_shape, Scene *UNUSED(scene))
+static short snap_mask_layer_nearest(MaskLayerShape *mask_layer_shape, Scene *UNUSED(scene))
{
- if (masklay_shape->flag & MASK_SHAPE_SELECT) {
- masklay_shape->frame = (int)(floor(masklay_shape->frame + 0.5));
+ if (mask_layer_shape->flag & MASK_SHAPE_SELECT) {
+ mask_layer_shape->frame = (int)(floor(mask_layer_shape->frame + 0.5));
}
return 0;
}
-static short snap_masklayer_nearestsec(MaskLayerShape *masklay_shape, Scene *scene)
+static short snap_mask_layer_nearestsec(MaskLayerShape *mask_layer_shape, Scene *scene)
{
float secf = (float)FPS;
- if (masklay_shape->flag & MASK_SHAPE_SELECT) {
- masklay_shape->frame = (int)(floorf(masklay_shape->frame / secf + 0.5f) * secf);
+ if (mask_layer_shape->flag & MASK_SHAPE_SELECT) {
+ mask_layer_shape->frame = (int)(floorf(mask_layer_shape->frame / secf + 0.5f) * secf);
}
return 0;
}
-static short snap_masklayer_cframe(MaskLayerShape *masklay_shape, Scene *scene)
+static short snap_mask_layer_cframe(MaskLayerShape *mask_layer_shape, Scene *scene)
{
- if (masklay_shape->flag & MASK_SHAPE_SELECT) {
- masklay_shape->frame = (int)CFRA;
+ if (mask_layer_shape->flag & MASK_SHAPE_SELECT) {
+ mask_layer_shape->frame = (int)CFRA;
}
return 0;
}
-static short snap_masklayer_nearmarker(MaskLayerShape *masklay_shape, Scene *scene)
+static short snap_mask_layer_nearmarker(MaskLayerShape *mask_layer_shape, Scene *scene)
{
- if (masklay_shape->flag & MASK_SHAPE_SELECT) {
- masklay_shape->frame = (int)ED_markers_find_nearest_marker_time(&scene->markers,
- (float)masklay_shape->frame);
+ if (mask_layer_shape->flag & MASK_SHAPE_SELECT) {
+ mask_layer_shape->frame = (int)ED_markers_find_nearest_marker_time(
+ &scene->markers, (float)mask_layer_shape->frame);
}
return 0;
}
/* snap selected frames to ... */
-void ED_masklayer_snap_frames(MaskLayer *masklay, Scene *scene, short mode)
+void ED_masklayer_snap_frames(MaskLayer *mask_layer, Scene *scene, short mode)
{
switch (mode) {
case SNAP_KEYS_NEARFRAME: /* snap to nearest frame */
- ED_masklayer_frames_looper(masklay, scene, snap_masklayer_nearest);
+ ED_masklayer_frames_looper(mask_layer, scene, snap_mask_layer_nearest);
break;
case SNAP_KEYS_CURFRAME: /* snap to current frame */
- ED_masklayer_frames_looper(masklay, scene, snap_masklayer_cframe);
+ ED_masklayer_frames_looper(mask_layer, scene, snap_mask_layer_cframe);
break;
case SNAP_KEYS_NEARMARKER: /* snap to nearest marker */
- ED_masklayer_frames_looper(masklay, scene, snap_masklayer_nearmarker);
+ ED_masklayer_frames_looper(mask_layer, scene, snap_mask_layer_nearmarker);
break;
case SNAP_KEYS_NEARSEC: /* snap to nearest second */
- ED_masklayer_frames_looper(masklay, scene, snap_masklayer_nearestsec);
+ ED_masklayer_frames_looper(mask_layer, scene, snap_mask_layer_nearestsec);
break;
default: /* just in case */
break;
diff --git a/source/blender/editors/mask/mask_intern.h b/source/blender/editors/mask/mask_intern.h
index 67785f1ae46..7cf92a9051a 100644
--- a/source/blender/editors/mask/mask_intern.h
+++ b/source/blender/editors/mask/mask_intern.h
@@ -39,7 +39,7 @@ bool ED_mask_find_nearest_diff_point(const struct bContext *C,
float tangent[2],
const bool use_deform,
const bool use_project,
- struct MaskLayer **masklay_r,
+ struct MaskLayer **mask_layer_r,
struct MaskSpline **spline_r,
struct MaskSplinePoint **point_r,
float *u_r,
@@ -76,7 +76,7 @@ bool ED_mask_feather_find_nearest(const struct bContext *C,
struct Mask *mask,
const float normal_co[2],
const float threshold,
- struct MaskLayer **masklay_r,
+ struct MaskLayer **mask_layer_r,
struct MaskSpline **spline_r,
struct MaskSplinePoint **point_r,
struct MaskSplinePointUW **uw_r,
@@ -86,7 +86,7 @@ struct MaskSplinePoint *ED_mask_point_find_nearest(const struct bContext *C,
struct Mask *mask,
const float normal_co[2],
const float threshold,
- struct MaskLayer **masklay_r,
+ struct MaskLayer **mask_layer_r,
struct MaskSpline **spline_r,
eMaskWhichHandle *which_handle_r,
float *score);
@@ -114,11 +114,11 @@ void MASK_OT_select_more(struct wmOperatorType *ot);
void MASK_OT_select_less(struct wmOperatorType *ot);
bool ED_mask_spline_select_check(struct MaskSpline *spline);
-bool ED_mask_layer_select_check(struct MaskLayer *masklay);
+bool ED_mask_layer_select_check(struct MaskLayer *mask_layer);
bool ED_mask_select_check(struct Mask *mask);
void ED_mask_spline_select_set(struct MaskSpline *spline, const bool do_select);
-void ED_mask_layer_select_set(struct MaskLayer *masklay, const bool do_select);
+void ED_mask_layer_select_set(struct MaskLayer *mask_layer, const bool do_select);
void ED_mask_select_toggle_all(struct Mask *mask, int action);
void ED_mask_select_flush_all(struct Mask *mask);
diff --git a/source/blender/editors/mask/mask_ops.c b/source/blender/editors/mask/mask_ops.c
index c91f431ad20..3a982b255f0 100644
--- a/source/blender/editors/mask/mask_ops.c
+++ b/source/blender/editors/mask/mask_ops.c
@@ -69,7 +69,7 @@ MaskSplinePoint *ED_mask_point_find_nearest(const bContext *C,
Mask *mask_orig,
const float normal_co[2],
const float threshold,
- MaskLayer **masklay_r,
+ MaskLayer **mask_layer_r,
MaskSpline **spline_r,
eMaskWhichHandle *which_handle_r,
float *score)
@@ -77,7 +77,7 @@ MaskSplinePoint *ED_mask_point_find_nearest(const bContext *C,
ScrArea *sa = CTX_wm_area(C);
ARegion *ar = CTX_wm_region(C);
- MaskLayer *point_masklay = NULL;
+ MaskLayer *point_mask_layer = NULL;
MaskSpline *point_spline = NULL;
MaskSplinePoint *point = NULL;
float co[2];
@@ -95,17 +95,17 @@ MaskSplinePoint *ED_mask_point_find_nearest(const bContext *C,
co[0] = normal_co[0] * scalex;
co[1] = normal_co[1] * scaley;
- for (MaskLayer *masklay_orig = mask_orig->masklayers.first,
- *masklay_eval = mask_eval->masklayers.first;
- masklay_orig != NULL;
- masklay_orig = masklay_orig->next, masklay_eval = masklay_eval->next) {
+ for (MaskLayer *mask_layer_orig = mask_orig->masklayers.first,
+ *mask_layer_eval = mask_eval->masklayers.first;
+ mask_layer_orig != NULL;
+ mask_layer_orig = mask_layer_orig->next, mask_layer_eval = mask_layer_eval->next) {
- if (masklay_orig->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
+ if (mask_layer_orig->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
continue;
}
- for (MaskSpline *spline_orig = masklay_orig->splines.first,
- *spline_eval = masklay_eval->splines.first;
+ for (MaskSpline *spline_orig = mask_layer_orig->splines.first,
+ *spline_eval = mask_layer_eval->splines.first;
spline_orig != NULL;
spline_orig = spline_orig->next, spline_eval = spline_eval->next) {
MaskSplinePoint *points_array = BKE_mask_spline_point_array(spline_eval);
@@ -124,7 +124,7 @@ MaskSplinePoint *ED_mask_point_find_nearest(const bContext *C,
if (cur_len_sq < len_sq) {
point_spline = spline_orig;
- point_masklay = masklay_orig;
+ point_mask_layer = mask_layer_orig;
point = cur_point_orig;
len_sq = cur_len_sq;
which_handle = MASK_WHICH_HANDLE_NONE;
@@ -174,7 +174,7 @@ MaskSplinePoint *ED_mask_point_find_nearest(const bContext *C,
}
if (cur_len_sq <= len_sq && cur_which_handle != MASK_WHICH_HANDLE_NONE) {
- point_masklay = masklay_orig;
+ point_mask_layer = mask_layer_orig;
point_spline = spline_orig;
point = cur_point_orig;
len_sq = cur_len_sq;
@@ -185,8 +185,8 @@ MaskSplinePoint *ED_mask_point_find_nearest(const bContext *C,
}
if (len_sq < threshold_sq) {
- if (masklay_r) {
- *masklay_r = point_masklay;
+ if (mask_layer_r) {
+ *mask_layer_r = point_mask_layer;
}
if (spline_r) {
@@ -204,8 +204,8 @@ MaskSplinePoint *ED_mask_point_find_nearest(const bContext *C,
return point;
}
- if (masklay_r) {
- *masklay_r = NULL;
+ if (mask_layer_r) {
+ *mask_layer_r = NULL;
}
if (spline_r) {
@@ -223,7 +223,7 @@ bool ED_mask_feather_find_nearest(const bContext *C,
Mask *mask_orig,
const float normal_co[2],
const float threshold,
- MaskLayer **masklay_r,
+ MaskLayer **mask_layer_r,
MaskSpline **spline_r,
MaskSplinePoint **point_r,
MaskSplinePointUW **uw_r,
@@ -232,7 +232,7 @@ bool ED_mask_feather_find_nearest(const bContext *C,
ScrArea *sa = CTX_wm_area(C);
ARegion *ar = CTX_wm_region(C);
- MaskLayer *point_masklay = NULL;
+ MaskLayer *point_mask_layer = NULL;
MaskSpline *point_spline = NULL;
MaskSplinePoint *point = NULL;
MaskSplinePointUW *uw = NULL;
@@ -250,13 +250,13 @@ bool ED_mask_feather_find_nearest(const bContext *C,
co[0] = normal_co[0] * scalex;
co[1] = normal_co[1] * scaley;
- for (MaskLayer *masklay_orig = mask_orig->masklayers.first,
- *masklay_eval = mask_eval->masklayers.first;
- masklay_orig != NULL;
- masklay_orig = masklay_orig->next, masklay_eval = masklay_eval->next) {
+ for (MaskLayer *mask_layer_orig = mask_orig->masklayers.first,
+ *mask_layer_eval = mask_eval->masklayers.first;
+ mask_layer_orig != NULL;
+ mask_layer_orig = mask_layer_orig->next, mask_layer_eval = mask_layer_eval->next) {
- for (MaskSpline *spline_orig = masklay_orig->splines.first,
- *spline_eval = masklay_eval->splines.first;
+ for (MaskSpline *spline_orig = mask_layer_orig->splines.first,
+ *spline_eval = mask_layer_eval->splines.first;
spline_orig != NULL;
spline_orig = spline_orig->next, spline_eval = spline_eval->next) {
// MaskSplinePoint *points_array = BKE_mask_spline_point_array(spline);
@@ -264,7 +264,7 @@ bool ED_mask_feather_find_nearest(const bContext *C,
int i, tot_feather_point;
float(*feather_points)[2], (*fp)[2];
- if (masklay_orig->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
+ if (mask_layer_orig->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
continue;
}
@@ -291,7 +291,7 @@ bool ED_mask_feather_find_nearest(const bContext *C,
uw = &cur_point_orig->uw[j - 1];
}
- point_masklay = masklay_orig;
+ point_mask_layer = mask_layer_orig;
point_spline = spline_orig;
point = cur_point_orig;
len = cur_len_sq;
@@ -306,8 +306,8 @@ bool ED_mask_feather_find_nearest(const bContext *C,
}
if (len < threshold_sq) {
- if (masklay_r) {
- *masklay_r = point_masklay;
+ if (mask_layer_r) {
+ *mask_layer_r = point_mask_layer;
}
if (spline_r) {
@@ -329,8 +329,8 @@ bool ED_mask_feather_find_nearest(const bContext *C,
return true;
}
- if (masklay_r) {
- *masklay_r = NULL;
+ if (mask_layer_r) {
+ *mask_layer_r = NULL;
}
if (spline_r) {
@@ -428,9 +428,9 @@ void MASK_OT_new(wmOperatorType *ot)
RNA_def_string(ot->srna, "name", NULL, MAX_ID_NAME - 2, "Name", "Name of new mask");
}
-/******************** create new masklay *********************/
+/******************** create new mask layer *********************/
-static int masklay_new_exec(bContext *C, wmOperator *op)
+static int mask_layer_new_exec(bContext *C, wmOperator *op)
{
Mask *mask = CTX_data_edit_mask(C);
char name[MAX_ID_NAME - 2];
@@ -454,7 +454,7 @@ void MASK_OT_layer_new(wmOperatorType *ot)
ot->idname = "MASK_OT_layer_new";
/* api callbacks */
- ot->exec = masklay_new_exec;
+ ot->exec = mask_layer_new_exec;
ot->poll = ED_maskedit_poll;
/* flags */
@@ -466,13 +466,13 @@ void MASK_OT_layer_new(wmOperatorType *ot)
/******************** remove mask layer *********************/
-static int masklay_remove_exec(bContext *C, wmOperator *UNUSED(op))
+static int mask_layer_remove_exec(bContext *C, wmOperator *UNUSED(op))
{
Mask *mask = CTX_data_edit_mask(C);
- MaskLayer *masklay = BKE_mask_layer_active(mask);
+ MaskLayer *mask_layer = BKE_mask_layer_active(mask);
- if (masklay) {
- BKE_mask_layer_remove(mask, masklay);
+ if (mask_layer) {
+ BKE_mask_layer_remove(mask, mask_layer);
WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask);
DEG_id_tag_update(&mask->id, ID_RECALC_COPY_ON_WRITE);
@@ -489,7 +489,7 @@ void MASK_OT_layer_remove(wmOperatorType *ot)
ot->idname = "MASK_OT_layer_remove";
/* api callbacks */
- ot->exec = masklay_remove_exec;
+ ot->exec = mask_layer_remove_exec;
ot->poll = ED_maskedit_poll;
/* flags */
@@ -511,7 +511,7 @@ typedef struct SlidePointData {
short event_invoke_type;
int action;
Mask *mask;
- MaskLayer *masklay;
+ MaskLayer *mask_layer;
MaskSpline *spline, *orig_spline;
MaskSplinePoint *point;
MaskSplinePointUW *uw;
@@ -555,7 +555,6 @@ static bool spline_under_mouse_get(const bContext *C,
const float threshold = 19.0f;
ScrArea *sa = CTX_wm_area(C);
SpaceClip *sc = CTX_wm_space_clip(C);
- MaskLayer *mask_layer;
int width, height;
float pixel_co[2];
float closest_dist_squared = 0.0f;
@@ -570,13 +569,13 @@ static bool spline_under_mouse_get(const bContext *C,
if (sc != NULL) {
undistort = (sc->clip != NULL) && (sc->user.render_flag & MCLIP_PROXY_RENDER_UNDISTORT) != 0;
}
- for (mask_layer = mask->masklayers.first; mask_layer != NULL; mask_layer = mask_layer->next) {
- MaskSpline *spline;
+ for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer != NULL;
+ mask_layer = mask_layer->next) {
if (mask_layer->restrictflag & MASK_RESTRICT_SELECT) {
continue;
}
- for (spline = mask_layer->splines.first; spline != NULL; spline = spline->next) {
+ for (MaskSpline *spline = mask_layer->splines.first; spline != NULL; spline = spline->next) {
MaskSplinePoint *points_array;
float min[2], max[2], center[2];
float dist_squared;
@@ -719,7 +718,7 @@ static void *slide_point_customdata(bContext *C, wmOperator *op, const wmEvent *
Mask *mask = CTX_data_edit_mask(C);
SlidePointData *customdata = NULL;
- MaskLayer *masklay, *cv_masklay, *feather_masklay;
+ MaskLayer *mask_layer, *cv_mask_layer, *feather_mask_layer;
MaskSpline *spline, *cv_spline, *feather_spline;
MaskSplinePoint *point, *cv_point, *feather_point;
MaskSplinePointUW *uw = NULL;
@@ -733,13 +732,13 @@ static void *slide_point_customdata(bContext *C, wmOperator *op, const wmEvent *
ED_mask_get_size(sa, &width, &height);
cv_point = ED_mask_point_find_nearest(
- C, mask, co, threshold, &cv_masklay, &cv_spline, &which_handle, &cv_score);
+ C, mask, co, threshold, &cv_mask_layer, &cv_spline, &which_handle, &cv_score);
if (ED_mask_feather_find_nearest(C,
mask,
co,
threshold,
- &feather_masklay,
+ &feather_mask_layer,
&feather_spline,
&feather_point,
&uw,
@@ -747,7 +746,7 @@ static void *slide_point_customdata(bContext *C, wmOperator *op, const wmEvent *
if (slide_feather || !cv_point || feather_score < cv_score) {
action = SLIDE_ACTION_FEATHER;
- masklay = feather_masklay;
+ mask_layer = feather_mask_layer;
spline = feather_spline;
point = feather_point;
}
@@ -761,13 +760,13 @@ static void *slide_point_customdata(bContext *C, wmOperator *op, const wmEvent *
action = SLIDE_ACTION_POINT;
}
- masklay = cv_masklay;
+ mask_layer = cv_mask_layer;
spline = cv_spline;
point = cv_point;
}
if (action == SLIDE_ACTION_NONE) {
- if (spline_under_mouse_get(C, mask, co, &masklay, &spline)) {
+ if (spline_under_mouse_get(C, mask, co, &mask_layer, &spline)) {
action = SLIDE_ACTION_SPLINE;
point = NULL;
}
@@ -777,7 +776,7 @@ static void *slide_point_customdata(bContext *C, wmOperator *op, const wmEvent *
customdata = MEM_callocN(sizeof(SlidePointData), "mask slide point data");
customdata->event_invoke_type = event->type;
customdata->mask = mask;
- customdata->masklay = masklay;
+ customdata->mask_layer = mask_layer;
customdata->spline = spline;
customdata->point = point;
customdata->width = width;
@@ -790,7 +789,7 @@ static void *slide_point_customdata(bContext *C, wmOperator *op, const wmEvent *
if (customdata->action != SLIDE_ACTION_SPLINE) {
customdata->old_h1 = point->bezt.h1;
customdata->old_h2 = point->bezt.h2;
- select_sliding_point(mask, masklay, spline, point, which_handle);
+ select_sliding_point(mask, mask_layer, spline, point, which_handle);
check_sliding_handle_type(point, which_handle);
}
@@ -850,8 +849,8 @@ static int slide_point_invoke(bContext *C, wmOperator *op, const wmEvent *event)
WM_event_add_modal_handler(C, op);
- slidedata->masklay->act_spline = slidedata->spline;
- slidedata->masklay->act_point = slidedata->point;
+ slidedata->mask_layer->act_spline = slidedata->spline;
+ slidedata->mask_layer->act_point = slidedata->point;
WM_event_add_notifier(C, NC_MASK | ND_SELECT, mask);
@@ -1140,7 +1139,7 @@ static int slide_point_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* dont key sliding feather uw's */
if ((data->action == SLIDE_ACTION_FEATHER && data->uw) == false) {
if (IS_AUTOKEY_ON(scene)) {
- ED_mask_layer_shape_auto_key(data->masklay, CFRA);
+ ED_mask_layer_shape_auto_key(data->mask_layer, CFRA);
}
}
@@ -1586,16 +1585,13 @@ void MASK_OT_slide_spline_curvature(wmOperatorType *ot)
static int cyclic_toggle_exec(bContext *C, wmOperator *UNUSED(op))
{
Mask *mask = CTX_data_edit_mask(C);
- MaskLayer *masklay;
-
- for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
- MaskSpline *spline;
- if (masklay->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
+ for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
+ if (mask_layer->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
continue;
}
- for (spline = masklay->splines.first; spline; spline = spline->next) {
+ for (MaskSpline *spline = mask_layer->splines.first; spline; spline = spline->next) {
if (ED_mask_spline_select_check(spline)) {
spline->flag ^= MASK_SPLINE_CYCLIC;
}
@@ -1666,18 +1662,17 @@ static void delete_feather_points(MaskSplinePoint *point)
static int delete_exec(bContext *C, wmOperator *UNUSED(op))
{
Mask *mask = CTX_data_edit_mask(C);
- MaskLayer *masklay;
bool changed = false;
- for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
+ for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
MaskSpline *spline;
int mask_layer_shape_ofs = 0;
- if (masklay->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
+ if (mask_layer->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
continue;
}
- spline = masklay->splines.first;
+ spline = mask_layer->splines.first;
while (spline) {
const int tot_point_orig = spline->tot_point;
@@ -1695,15 +1690,15 @@ static int delete_exec(bContext *C, wmOperator *UNUSED(op))
if (count == 0) {
/* delete the whole spline */
- BLI_remlink(&masklay->splines, spline);
+ BLI_remlink(&mask_layer->splines, spline);
BKE_mask_spline_free(spline);
- if (spline == masklay->act_spline) {
- masklay->act_spline = NULL;
- masklay->act_point = NULL;
+ if (spline == mask_layer->act_spline) {
+ mask_layer->act_spline = NULL;
+ mask_layer->act_point = NULL;
}
- BKE_mask_layer_shape_changed_remove(masklay, mask_layer_shape_ofs, tot_point_orig);
+ BKE_mask_layer_shape_changed_remove(mask_layer, mask_layer_shape_ofs, tot_point_orig);
}
else {
MaskSplinePoint *new_points;
@@ -1715,8 +1710,8 @@ static int delete_exec(bContext *C, wmOperator *UNUSED(op))
MaskSplinePoint *point = &spline->points[i];
if (!MASKPOINT_ISSEL_ANY(point)) {
- if (point == masklay->act_point) {
- masklay->act_point = &new_points[j];
+ if (point == mask_layer->act_point) {
+ mask_layer->act_point = &new_points[j];
}
delete_feather_points(point);
@@ -1725,14 +1720,14 @@ static int delete_exec(bContext *C, wmOperator *UNUSED(op))
j++;
}
else {
- if (point == masklay->act_point) {
- masklay->act_point = NULL;
+ if (point == mask_layer->act_point) {
+ mask_layer->act_point = NULL;
}
BKE_mask_point_free(point);
spline->tot_point--;
- BKE_mask_layer_shape_changed_remove(masklay, mask_layer_shape_ofs + j, 1);
+ BKE_mask_layer_shape_changed_remove(mask_layer, mask_layer_shape_ofs + j, 1);
}
}
@@ -1750,8 +1745,8 @@ static int delete_exec(bContext *C, wmOperator *UNUSED(op))
/* not essential but confuses users when there are keys with no data!
* assume if they delete all data from the layer they also dont care about keys */
- if (BLI_listbase_is_empty(&masklay->splines)) {
- BKE_mask_layer_free_shapes(masklay);
+ if (BLI_listbase_is_empty(&mask_layer->splines)) {
+ BKE_mask_layer_free_shapes(mask_layer);
}
}
@@ -1787,22 +1782,20 @@ static int mask_switch_direction_exec(bContext *C, wmOperator *UNUSED(op))
{
Scene *scene = CTX_data_scene(C);
Mask *mask = CTX_data_edit_mask(C);
- MaskLayer *masklay;
bool changed = false;
/* do actual selection */
- for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
- MaskSpline *spline;
+ for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
bool changed_layer = false;
- if (masklay->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
+ if (mask_layer->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
continue;
}
- for (spline = masklay->splines.first; spline; spline = spline->next) {
+ for (MaskSpline *spline = mask_layer->splines.first; spline; spline = spline->next) {
if (ED_mask_spline_select_check(spline)) {
- BKE_mask_spline_direction_switch(masklay, spline);
+ BKE_mask_spline_direction_switch(mask_layer, spline);
changed = true;
changed_layer = true;
}
@@ -1810,7 +1803,7 @@ static int mask_switch_direction_exec(bContext *C, wmOperator *UNUSED(op))
if (changed_layer) {
if (IS_AUTOKEY_ON(scene)) {
- ED_mask_layer_shape_auto_key(masklay, CFRA);
+ ED_mask_layer_shape_auto_key(mask_layer, CFRA);
}
}
}
@@ -1847,22 +1840,19 @@ static int mask_normals_make_consistent_exec(bContext *C, wmOperator *UNUSED(op)
{
Scene *scene = CTX_data_scene(C);
Mask *mask = CTX_data_edit_mask(C);
- MaskLayer *masklay;
- int i;
bool changed = false;
/* do actual selection */
- for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
- MaskSpline *spline;
+ for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
bool changed_layer = false;
- if (masklay->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
+ if (mask_layer->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
continue;
}
- for (spline = masklay->splines.first; spline; spline = spline->next) {
- for (i = 0; i < spline->tot_point; i++) {
+ for (MaskSpline *spline = mask_layer->splines.first; spline; spline = spline->next) {
+ for (int i = 0; i < spline->tot_point; i++) {
MaskSplinePoint *point = &spline->points[i];
if (MASKPOINT_ISSEL_ANY(point)) {
@@ -1875,7 +1865,7 @@ static int mask_normals_make_consistent_exec(bContext *C, wmOperator *UNUSED(op)
if (changed_layer) {
if (IS_AUTOKEY_ON(scene)) {
- ED_mask_layer_shape_auto_key(masklay, CFRA);
+ ED_mask_layer_shape_auto_key(mask_layer, CFRA);
}
}
}
@@ -1913,21 +1903,17 @@ void MASK_OT_normals_make_consistent(wmOperatorType *ot)
static int set_handle_type_exec(bContext *C, wmOperator *op)
{
Mask *mask = CTX_data_edit_mask(C);
- MaskLayer *masklay;
int handle_type = RNA_enum_get(op->ptr, "type");
bool changed = false;
- for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
- MaskSpline *spline;
- int i;
-
- if (masklay->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
+ for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
+ if (mask_layer->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
continue;
}
- for (spline = masklay->splines.first; spline; spline = spline->next) {
- for (i = 0; i < spline->tot_point; i++) {
+ for (MaskSpline *spline = mask_layer->splines.first; spline; spline = spline->next) {
+ for (int i = 0; i < spline->tot_point; i++) {
MaskSplinePoint *point = &spline->points[i];
if (MASKPOINT_ISSEL_ANY(point)) {
@@ -1999,15 +1985,14 @@ void MASK_OT_handle_type_set(wmOperatorType *ot)
static int mask_hide_view_clear_exec(bContext *C, wmOperator *op)
{
Mask *mask = CTX_data_edit_mask(C);
- MaskLayer *masklay;
bool changed = false;
const bool select = RNA_boolean_get(op->ptr, "select");
- for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
+ for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
- if (masklay->restrictflag & OB_RESTRICT_VIEWPORT) {
- ED_mask_layer_select_set(masklay, select);
- masklay->restrictflag &= ~OB_RESTRICT_VIEWPORT;
+ if (mask_layer->restrictflag & OB_RESTRICT_VIEWPORT) {
+ ED_mask_layer_select_set(mask_layer, select);
+ mask_layer->restrictflag &= ~OB_RESTRICT_VIEWPORT;
changed = true;
}
}
@@ -2044,32 +2029,31 @@ void MASK_OT_hide_view_clear(wmOperatorType *ot)
static int mask_hide_view_set_exec(bContext *C, wmOperator *op)
{
Mask *mask = CTX_data_edit_mask(C);
- MaskLayer *masklay;
const bool unselected = RNA_boolean_get(op->ptr, "unselected");
bool changed = false;
- for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
+ for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
- if (masklay->restrictflag & MASK_RESTRICT_SELECT) {
+ if (mask_layer->restrictflag & MASK_RESTRICT_SELECT) {
continue;
}
if (!unselected) {
- if (ED_mask_layer_select_check(masklay)) {
- ED_mask_layer_select_set(masklay, false);
+ if (ED_mask_layer_select_check(mask_layer)) {
+ ED_mask_layer_select_set(mask_layer, false);
- masklay->restrictflag |= OB_RESTRICT_VIEWPORT;
+ mask_layer->restrictflag |= OB_RESTRICT_VIEWPORT;
changed = true;
- if (masklay == BKE_mask_layer_active(mask)) {
+ if (mask_layer == BKE_mask_layer_active(mask)) {
BKE_mask_layer_active_set(mask, NULL);
}
}
}
else {
- if (!ED_mask_layer_select_check(masklay)) {
- masklay->restrictflag |= OB_RESTRICT_VIEWPORT;
+ if (!ED_mask_layer_select_check(mask_layer)) {
+ mask_layer->restrictflag |= OB_RESTRICT_VIEWPORT;
changed = true;
- if (masklay == BKE_mask_layer_active(mask)) {
+ if (mask_layer == BKE_mask_layer_active(mask)) {
BKE_mask_layer_active_set(mask, NULL);
}
}
@@ -2108,19 +2092,15 @@ void MASK_OT_hide_view_set(wmOperatorType *ot)
static int mask_feather_weight_clear_exec(bContext *C, wmOperator *UNUSED(op))
{
Mask *mask = CTX_data_edit_mask(C);
- MaskLayer *masklay;
bool changed = false;
- int i;
-
- for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
- MaskSpline *spline;
- if (masklay->restrictflag & (MASK_RESTRICT_SELECT | MASK_RESTRICT_VIEW)) {
+ for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
+ if (mask_layer->restrictflag & (MASK_RESTRICT_SELECT | MASK_RESTRICT_VIEW)) {
continue;
}
- for (spline = masklay->splines.first; spline; spline = spline->next) {
- for (i = 0; i < spline->tot_point; i++) {
+ for (MaskSpline *spline = mask_layer->splines.first; spline; spline = spline->next) {
+ for (int i = 0; i < spline->tot_point; i++) {
MaskSplinePoint *point = &spline->points[i];
if (MASKPOINT_ISSEL_ANY(point)) {
@@ -2247,12 +2227,9 @@ void MASK_OT_layer_move(wmOperatorType *ot)
static int mask_duplicate_exec(bContext *C, wmOperator *UNUSED(op))
{
Mask *mask = CTX_data_edit_mask(C);
- MaskLayer *mask_layer;
-
- for (mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
- MaskSpline *spline;
- for (spline = mask_layer->splines.last; spline; spline = spline->prev) {
+ for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
+ for (MaskSpline *spline = mask_layer->splines.last; spline; spline = spline->prev) {
MaskSplinePoint *point = spline->points;
int i = 0;
while (i < spline->tot_point) {
diff --git a/source/blender/editors/mask/mask_relationships.c b/source/blender/editors/mask/mask_relationships.c
index 75b2aee3570..130ebb61a90 100644
--- a/source/blender/editors/mask/mask_relationships.c
+++ b/source/blender/editors/mask/mask_relationships.c
@@ -43,18 +43,14 @@
static int mask_parent_clear_exec(bContext *C, wmOperator *UNUSED(op))
{
Mask *mask = CTX_data_edit_mask(C);
- MaskLayer *masklay;
- for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
- MaskSpline *spline;
- int i;
-
- if (masklay->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
+ for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
+ if (mask_layer->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
continue;
}
- for (spline = masklay->splines.first; spline; spline = spline->next) {
- for (i = 0; i < spline->tot_point; i++) {
+ for (MaskSpline *spline = mask_layer->splines.first; spline; spline = spline->next) {
+ for (int i = 0; i < spline->tot_point; i++) {
MaskSplinePoint *point = &spline->points[i];
if (MASKPOINT_ISSEL_ANY(point)) {
@@ -89,7 +85,6 @@ void MASK_OT_parent_clear(wmOperatorType *ot)
static int mask_parent_set_exec(bContext *C, wmOperator *UNUSED(op))
{
Mask *mask = CTX_data_edit_mask(C);
- MaskLayer *masklay;
/* parent info */
SpaceClip *sc = CTX_wm_space_clip(C);
@@ -141,16 +136,13 @@ static int mask_parent_set_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_CANCELLED;
}
- for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
- MaskSpline *spline;
- int i;
-
- if (masklay->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
+ for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
+ if (mask_layer->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
continue;
}
- for (spline = masklay->splines.first; spline; spline = spline->next) {
- for (i = 0; i < spline->tot_point; i++) {
+ for (MaskSpline *spline = mask_layer->splines.first; spline; spline = spline->next) {
+ for (int i = 0; i < spline->tot_point; i++) {
MaskSplinePoint *point = &spline->points[i];
if (MASKPOINT_ISSEL_ANY(point)) {
diff --git a/source/blender/editors/mask/mask_select.c b/source/blender/editors/mask/mask_select.c
index 2b3bd1b72c9..656c055a7d9 100644
--- a/source/blender/editors/mask/mask_select.c
+++ b/source/blender/editors/mask/mask_select.c
@@ -68,15 +68,13 @@ bool ED_mask_spline_select_check(MaskSpline *spline)
return false;
}
-bool ED_mask_layer_select_check(MaskLayer *masklay)
+bool ED_mask_layer_select_check(MaskLayer *mask_layer)
{
- MaskSpline *spline;
-
- if (masklay->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
+ if (mask_layer->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
return false;
}
- for (spline = masklay->splines.first; spline; spline = spline->next) {
+ for (MaskSpline *spline = mask_layer->splines.first; spline; spline = spline->next) {
if (ED_mask_spline_select_check(spline)) {
return true;
}
@@ -87,10 +85,8 @@ bool ED_mask_layer_select_check(MaskLayer *masklay)
bool ED_mask_select_check(Mask *mask)
{
- MaskLayer *masklay;
-
- for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
- if (ED_mask_layer_select_check(masklay)) {
+ for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
+ if (ED_mask_layer_select_check(mask_layer)) {
return true;
}
}
@@ -117,25 +113,21 @@ void ED_mask_spline_select_set(MaskSpline *spline, const bool do_select)
}
}
-void ED_mask_layer_select_set(MaskLayer *masklay, const bool do_select)
+void ED_mask_layer_select_set(MaskLayer *mask_layer, const bool do_select)
{
- MaskSpline *spline;
-
- if (masklay->restrictflag & MASK_RESTRICT_SELECT) {
+ if (mask_layer->restrictflag & MASK_RESTRICT_SELECT) {
if (do_select == true) {
return;
}
}
- for (spline = masklay->splines.first; spline; spline = spline->next) {
+ for (MaskSpline *spline = mask_layer->splines.first; spline; spline = spline->next) {
ED_mask_spline_select_set(spline, do_select);
}
}
void ED_mask_select_toggle_all(Mask *mask, int action)
{
- MaskLayer *masklay;
-
if (action == SEL_TOGGLE) {
if (ED_mask_select_check(mask)) {
action = SEL_DESELECT;
@@ -145,9 +137,9 @@ void ED_mask_select_toggle_all(Mask *mask, int action)
}
}
- for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
+ for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
- if (masklay->restrictflag & MASK_RESTRICT_VIEW) {
+ if (mask_layer->restrictflag & MASK_RESTRICT_VIEW) {
continue;
}
@@ -155,11 +147,10 @@ void ED_mask_select_toggle_all(Mask *mask, int action)
/* we don't have generic functions for this, its restricted to this operator
* if one day we need to re-use such functionality, they can be split out */
- MaskSpline *spline;
- if (masklay->restrictflag & MASK_RESTRICT_SELECT) {
+ if (mask_layer->restrictflag & MASK_RESTRICT_SELECT) {
continue;
}
- for (spline = masklay->splines.first; spline; spline = spline->next) {
+ for (MaskSpline *spline = mask_layer->splines.first; spline; spline = spline->next) {
int i;
for (i = 0; i < spline->tot_point; i++) {
MaskSplinePoint *point = &spline->points[i];
@@ -168,30 +159,24 @@ void ED_mask_select_toggle_all(Mask *mask, int action)
}
}
else {
- ED_mask_layer_select_set(masklay, (action == SEL_SELECT) ? true : false);
+ ED_mask_layer_select_set(mask_layer, (action == SEL_SELECT) ? true : false);
}
}
}
void ED_mask_select_flush_all(Mask *mask)
{
- MaskLayer *masklay;
-
- for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
- MaskSpline *spline;
-
- for (spline = masklay->splines.first; spline; spline = spline->next) {
- int i;
-
+ for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
+ for (MaskSpline *spline = mask_layer->splines.first; spline; spline = spline->next) {
spline->flag &= ~SELECT;
- /* intentionally _dont_ do this in the masklay loop
+ /* intentionally _dont_ do this in the mask layer loop
* so we clear flags on all splines */
- if (masklay->restrictflag & MASK_RESTRICT_VIEW) {
+ if (mask_layer->restrictflag & MASK_RESTRICT_VIEW) {
continue;
}
- for (i = 0; i < spline->tot_point; i++) {
+ for (int i = 0; i < spline->tot_point; i++) {
MaskSplinePoint *cur_point = &spline->points[i];
if (MASKPOINT_ISSEL_ANY(cur_point)) {
@@ -270,7 +255,7 @@ void MASK_OT_select_all(wmOperatorType *ot)
static int select_exec(bContext *C, wmOperator *op)
{
Mask *mask = CTX_data_edit_mask(C);
- MaskLayer *masklay;
+ MaskLayer *mask_layer;
MaskSpline *spline;
MaskSplinePoint *point = NULL;
float co[2];
@@ -284,7 +269,7 @@ static int select_exec(bContext *C, wmOperator *op)
RNA_float_get_array(op->ptr, "location", co);
point = ED_mask_point_find_nearest(
- C, mask, co, threshold, &masklay, &spline, &which_handle, NULL);
+ C, mask, co, threshold, &mask_layer, &spline, &which_handle, NULL);
if (extend == false && deselect == false && toggle == false) {
ED_mask_select_toggle_all(mask, SEL_DESELECT);
@@ -293,8 +278,8 @@ static int select_exec(bContext *C, wmOperator *op)
if (point) {
if (which_handle != MASK_WHICH_HANDLE_NONE) {
if (extend) {
- masklay->act_spline = spline;
- masklay->act_point = point;
+ mask_layer->act_spline = spline;
+ mask_layer->act_point = point;
BKE_mask_point_select_set_handle(point, which_handle, true);
}
@@ -302,8 +287,8 @@ static int select_exec(bContext *C, wmOperator *op)
BKE_mask_point_select_set_handle(point, which_handle, false);
}
else {
- masklay->act_spline = spline;
- masklay->act_point = point;
+ mask_layer->act_spline = spline;
+ mask_layer->act_point = point;
if (!MASKPOINT_ISSEL_HANDLE(point, which_handle)) {
BKE_mask_point_select_set_handle(point, which_handle, true);
@@ -315,8 +300,8 @@ static int select_exec(bContext *C, wmOperator *op)
}
else {
if (extend) {
- masklay->act_spline = spline;
- masklay->act_point = point;
+ mask_layer->act_spline = spline;
+ mask_layer->act_point = point;
BKE_mask_point_select_set(point, true);
}
@@ -324,8 +309,8 @@ static int select_exec(bContext *C, wmOperator *op)
BKE_mask_point_select_set(point, false);
}
else {
- masklay->act_spline = spline;
- masklay->act_point = point;
+ mask_layer->act_spline = spline;
+ mask_layer->act_point = point;
if (!MASKPOINT_ISSEL_ANY(point)) {
BKE_mask_point_select_set(point, true);
@@ -336,8 +321,8 @@ static int select_exec(bContext *C, wmOperator *op)
}
}
- masklay->act_spline = spline;
- masklay->act_point = point;
+ mask_layer->act_spline = spline;
+ mask_layer->act_point = point;
ED_mask_select_flush_all(mask);
@@ -350,11 +335,11 @@ static int select_exec(bContext *C, wmOperator *op)
MaskSplinePointUW *uw;
if (ED_mask_feather_find_nearest(
- C, mask, co, threshold, &masklay, &spline, &point, &uw, NULL)) {
+ C, mask, co, threshold, &mask_layer, &spline, &point, &uw, NULL)) {
if (extend) {
- masklay->act_spline = spline;
- masklay->act_point = point;
+ mask_layer->act_spline = spline;
+ mask_layer->act_point = point;
if (uw) {
uw->flag |= SELECT;
@@ -366,8 +351,8 @@ static int select_exec(bContext *C, wmOperator *op)
}
}
else {
- masklay->act_spline = spline;
- masklay->act_point = point;
+ mask_layer->act_spline = spline;
+ mask_layer->act_point = point;
if (uw) {
if (!(uw->flag & SELECT)) {
@@ -454,8 +439,6 @@ static int box_select_exec(bContext *C, wmOperator *op)
ARegion *ar = CTX_wm_region(C);
Mask *mask = CTX_data_edit_mask(C);
- MaskLayer *masklay;
- int i;
rcti rect;
rctf rectf;
@@ -475,17 +458,15 @@ static int box_select_exec(bContext *C, wmOperator *op)
ED_mask_point_pos(sa, ar, rect.xmax, rect.ymax, &rectf.xmax, &rectf.ymax);
/* do actual selection */
- for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
- MaskSpline *spline;
-
- if (masklay->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
+ for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
+ if (mask_layer->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
continue;
}
- for (spline = masklay->splines.first; spline; spline = spline->next) {
+ for (MaskSpline *spline = mask_layer->splines.first; spline; spline = spline->next) {
MaskSplinePoint *points_array = BKE_mask_spline_point_array(spline);
- for (i = 0; i < spline->tot_point; i++) {
+ for (int i = 0; i < spline->tot_point; i++) {
MaskSplinePoint *point = &spline->points[i];
MaskSplinePoint *point_deform = &points_array[i];
@@ -548,8 +529,6 @@ static bool do_lasso_select_mask(bContext *C,
ARegion *ar = CTX_wm_region(C);
Mask *mask = CTX_data_edit_mask(C);
- MaskLayer *masklay;
- int i;
rcti rect;
bool changed = false;
@@ -564,17 +543,15 @@ static bool do_lasso_select_mask(bContext *C,
BLI_lasso_boundbox(&rect, mcords, moves);
/* do actual selection */
- for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
- MaskSpline *spline;
-
- if (masklay->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
+ for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
+ if (mask_layer->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
continue;
}
- for (spline = masklay->splines.first; spline; spline = spline->next) {
+ for (MaskSpline *spline = mask_layer->splines.first; spline; spline = spline->next) {
MaskSplinePoint *points_array = BKE_mask_spline_point_array(spline);
- for (i = 0; i < spline->tot_point; i++) {
+ for (int i = 0; i < spline->tot_point; i++) {
MaskSplinePoint *point = &spline->points[i];
MaskSplinePoint *point_deform = &points_array[i];
@@ -678,7 +655,6 @@ static int circle_select_exec(bContext *C, wmOperator *op)
ARegion *ar = CTX_wm_region(C);
Mask *mask = CTX_data_edit_mask(C);
- MaskLayer *masklay;
int i;
float zoomx, zoomy, offset[2], ellipse[2];
@@ -709,14 +685,12 @@ static int circle_select_exec(bContext *C, wmOperator *op)
}
/* do actual selection */
- for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
- MaskSpline *spline;
-
- if (masklay->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
+ for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
+ if (mask_layer->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
continue;
}
- for (spline = masklay->splines.first; spline; spline = spline->next) {
+ for (MaskSpline *spline = mask_layer->splines.first; spline; spline = spline->next) {
MaskSplinePoint *points_array = BKE_mask_spline_point_array(spline);
for (i = 0; i < spline->tot_point; i++) {
@@ -778,7 +752,7 @@ static int mask_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmE
ARegion *ar = CTX_wm_region(C);
Mask *mask = CTX_data_edit_mask(C);
- MaskLayer *masklay;
+ MaskLayer *mask_layer;
MaskSpline *spline;
MaskSplinePoint *point = NULL;
float co[2];
@@ -788,12 +762,12 @@ static int mask_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmE
ED_mask_mouse_pos(sa, ar, event->mval, co);
- point = ED_mask_point_find_nearest(C, mask, co, threshold, &masklay, &spline, NULL, NULL);
+ point = ED_mask_point_find_nearest(C, mask, co, threshold, &mask_layer, &spline, NULL, NULL);
if (point) {
ED_mask_spline_select_set(spline, do_select);
- masklay->act_spline = spline;
- masklay->act_point = point;
+ mask_layer->act_spline = spline;
+ mask_layer->act_point = point;
changed = true;
}
@@ -836,19 +810,16 @@ void MASK_OT_select_linked_pick(wmOperatorType *ot)
static int mask_select_linked_exec(bContext *C, wmOperator *UNUSED(op))
{
Mask *mask = CTX_data_edit_mask(C);
- MaskLayer *masklay;
bool changed = false;
/* do actual selection */
- for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
- MaskSpline *spline;
-
- if (masklay->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
+ for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
+ if (mask_layer->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
continue;
}
- for (spline = masklay->splines.first; spline; spline = spline->next) {
+ for (MaskSpline *spline = mask_layer->splines.first; spline; spline = spline->next) {
if (ED_mask_spline_select_check(spline)) {
ED_mask_spline_select_set(spline, true);
changed = true;
@@ -892,16 +863,13 @@ void MASK_OT_select_linked(wmOperatorType *ot)
static int mask_select_more_less(bContext *C, bool more)
{
Mask *mask = CTX_data_edit_mask(C);
- MaskLayer *masklay;
-
- for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
- MaskSpline *spline;
- if (masklay->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
+ for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
+ if (mask_layer->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
continue;
}
- for (spline = masklay->splines.first; spline; spline = spline->next) {
+ for (MaskSpline *spline = mask_layer->splines.first; spline; spline = spline->next) {
const bool cyclic = (spline->flag & MASK_SPLINE_CYCLIC) != 0;
bool start_sel, end_sel, prev_sel, cur_sel;
int i;
diff --git a/source/blender/editors/mask/mask_shapekey.c b/source/blender/editors/mask/mask_shapekey.c
index 1abe805192d..2300289fd3b 100644
--- a/source/blender/editors/mask/mask_shapekey.c
+++ b/source/blender/editors/mask/mask_shapekey.c
@@ -51,18 +51,17 @@ static int mask_shape_key_insert_exec(bContext *C, wmOperator *UNUSED(op))
Scene *scene = CTX_data_scene(C);
const int frame = CFRA;
Mask *mask = CTX_data_edit_mask(C);
- MaskLayer *masklay;
bool changed = false;
- for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
- MaskLayerShape *masklay_shape;
+ for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
+ MaskLayerShape *mask_layer_shape;
- if (!ED_mask_layer_select_check(masklay)) {
+ if (!ED_mask_layer_select_check(mask_layer)) {
continue;
}
- masklay_shape = BKE_mask_layer_shape_verify_frame(masklay, frame);
- BKE_mask_layer_shape_from_mask(masklay, masklay_shape);
+ mask_layer_shape = BKE_mask_layer_shape_verify_frame(mask_layer, frame);
+ BKE_mask_layer_shape_from_mask(mask_layer, mask_layer_shape);
changed = true;
}
@@ -97,20 +96,19 @@ static int mask_shape_key_clear_exec(bContext *C, wmOperator *UNUSED(op))
Scene *scene = CTX_data_scene(C);
const int frame = CFRA;
Mask *mask = CTX_data_edit_mask(C);
- MaskLayer *masklay;
bool changed = false;
- for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
- MaskLayerShape *masklay_shape;
+ for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
+ MaskLayerShape *mask_layer_shape;
- if (!ED_mask_layer_select_check(masklay)) {
+ if (!ED_mask_layer_select_check(mask_layer)) {
continue;
}
- masklay_shape = BKE_mask_layer_shape_find_frame(masklay, frame);
+ mask_layer_shape = BKE_mask_layer_shape_find_frame(mask_layer, frame);
- if (masklay_shape) {
- BKE_mask_layer_shape_unlink(masklay, masklay_shape);
+ if (mask_layer_shape) {
+ BKE_mask_layer_shape_unlink(mask_layer, mask_layer_shape);
changed = true;
}
}
@@ -146,39 +144,36 @@ static int mask_shape_key_feather_reset_exec(bContext *C, wmOperator *UNUSED(op)
Scene *scene = CTX_data_scene(C);
const int frame = CFRA;
Mask *mask = CTX_data_edit_mask(C);
- MaskLayer *masklay;
bool changed = false;
- for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
+ for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
- if (masklay->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
+ if (mask_layer->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
continue;
}
- if (masklay->splines_shapes.first) {
- MaskLayerShape *masklay_shape_reset;
- MaskLayerShape *masklay_shape;
+ if (mask_layer->splines_shapes.first) {
+ MaskLayerShape *mask_layer_shape_reset;
+ MaskLayerShape *mask_layer_shape;
/* get the shapekey of the current state */
- masklay_shape_reset = BKE_mask_layer_shape_alloc(masklay, frame);
+ mask_layer_shape_reset = BKE_mask_layer_shape_alloc(mask_layer, frame);
/* initialize from mask - as if inseting a keyframe */
- BKE_mask_layer_shape_from_mask(masklay, masklay_shape_reset);
+ BKE_mask_layer_shape_from_mask(mask_layer, mask_layer_shape_reset);
- for (masklay_shape = masklay->splines_shapes.first; masklay_shape;
- masklay_shape = masklay_shape->next) {
+ for (mask_layer_shape = mask_layer->splines_shapes.first; mask_layer_shape;
+ mask_layer_shape = mask_layer_shape->next) {
- if (masklay_shape_reset->tot_vert == masklay_shape->tot_vert) {
+ if (mask_layer_shape_reset->tot_vert == mask_layer_shape->tot_vert) {
int i_abs = 0;
- int i;
- MaskSpline *spline;
MaskLayerShapeElem *shape_ele_src;
MaskLayerShapeElem *shape_ele_dst;
- shape_ele_src = (MaskLayerShapeElem *)masklay_shape_reset->data;
- shape_ele_dst = (MaskLayerShapeElem *)masklay_shape->data;
+ shape_ele_src = (MaskLayerShapeElem *)mask_layer_shape_reset->data;
+ shape_ele_dst = (MaskLayerShapeElem *)mask_layer_shape->data;
- for (spline = masklay->splines.first; spline; spline = spline->next) {
- for (i = 0; i < spline->tot_point; i++) {
+ for (MaskSpline *spline = mask_layer->splines.first; spline; spline = spline->next) {
+ for (int i = 0; i < spline->tot_point; i++) {
MaskSplinePoint *point = &spline->points[i];
if (MASKPOINT_ISSEL_ANY(point)) {
@@ -200,7 +195,7 @@ static int mask_shape_key_feather_reset_exec(bContext *C, wmOperator *UNUSED(op)
changed = true;
}
- BKE_mask_layer_shape_free(masklay_shape_reset);
+ BKE_mask_layer_shape_free(mask_layer_shape_reset);
}
}
@@ -243,98 +238,94 @@ static int mask_shape_key_rekey_exec(bContext *C, wmOperator *op)
Scene *scene = CTX_data_scene(C);
const int frame = CFRA;
Mask *mask = CTX_data_edit_mask(C);
- MaskLayer *masklay;
bool changed = false;
const bool do_feather = RNA_boolean_get(op->ptr, "feather");
const bool do_location = RNA_boolean_get(op->ptr, "location");
- for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
-
- if (masklay->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
+ for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
+ if (mask_layer->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
continue;
}
/* we need at least one point selected here to bother re-interpolating */
- if (!ED_mask_layer_select_check(masklay)) {
+ if (!ED_mask_layer_select_check(mask_layer)) {
continue;
}
- if (masklay->splines_shapes.first) {
- MaskLayerShape *masklay_shape, *masklay_shape_next;
- MaskLayerShape *masklay_shape_lastsel = NULL;
+ if (mask_layer->splines_shapes.first) {
+ MaskLayerShape *mask_layer_shape, *mask_layer_shape_next;
+ MaskLayerShape *mask_layer_shape_lastsel = NULL;
- for (masklay_shape = masklay->splines_shapes.first; masklay_shape;
- masklay_shape = masklay_shape_next) {
- MaskLayerShape *masklay_shape_a = NULL;
- MaskLayerShape *masklay_shape_b = NULL;
+ for (mask_layer_shape = mask_layer->splines_shapes.first; mask_layer_shape;
+ mask_layer_shape = mask_layer_shape_next) {
+ MaskLayerShape *mask_layer_shape_a = NULL;
+ MaskLayerShape *mask_layer_shape_b = NULL;
- masklay_shape_next = masklay_shape->next;
+ mask_layer_shape_next = mask_layer_shape->next;
/* find contiguous selections */
- if (masklay_shape->flag & MASK_SHAPE_SELECT) {
- if (masklay_shape_lastsel == NULL) {
- masklay_shape_lastsel = masklay_shape;
+ if (mask_layer_shape->flag & MASK_SHAPE_SELECT) {
+ if (mask_layer_shape_lastsel == NULL) {
+ mask_layer_shape_lastsel = mask_layer_shape;
}
- if ((masklay_shape->next == NULL) ||
- (((MaskLayerShape *)masklay_shape->next)->flag & MASK_SHAPE_SELECT) == 0) {
- masklay_shape_a = masklay_shape_lastsel;
- masklay_shape_b = masklay_shape;
- masklay_shape_lastsel = NULL;
+ if ((mask_layer_shape->next == NULL) ||
+ (((MaskLayerShape *)mask_layer_shape->next)->flag & MASK_SHAPE_SELECT) == 0) {
+ mask_layer_shape_a = mask_layer_shape_lastsel;
+ mask_layer_shape_b = mask_layer_shape;
+ mask_layer_shape_lastsel = NULL;
/* this will be freed below, step over selection */
- masklay_shape_next = masklay_shape->next;
+ mask_layer_shape_next = mask_layer_shape->next;
}
}
/* we have a from<>to? - re-interpolate! */
- if (masklay_shape_a && masklay_shape_b) {
+ if (mask_layer_shape_a && mask_layer_shape_b) {
ListBase shapes_tmp = {NULL, NULL};
- MaskLayerShape *masklay_shape_tmp;
- MaskLayerShape *masklay_shape_tmp_next;
- MaskLayerShape *masklay_shape_tmp_last = masklay_shape_b->next;
- MaskLayerShape *masklay_shape_tmp_rekey;
+ MaskLayerShape *mask_layer_shape_tmp;
+ MaskLayerShape *mask_layer_shape_tmp_next;
+ MaskLayerShape *mask_layer_shape_tmp_last = mask_layer_shape_b->next;
+ MaskLayerShape *mask_layer_shape_tmp_rekey;
/* move keys */
- for (masklay_shape_tmp = masklay_shape_a;
- masklay_shape_tmp && (masklay_shape_tmp != masklay_shape_tmp_last);
- masklay_shape_tmp = masklay_shape_tmp_next) {
- masklay_shape_tmp_next = masklay_shape_tmp->next;
- BLI_remlink(&masklay->splines_shapes, masklay_shape_tmp);
- BLI_addtail(&shapes_tmp, masklay_shape_tmp);
+ for (mask_layer_shape_tmp = mask_layer_shape_a;
+ mask_layer_shape_tmp && (mask_layer_shape_tmp != mask_layer_shape_tmp_last);
+ mask_layer_shape_tmp = mask_layer_shape_tmp_next) {
+ mask_layer_shape_tmp_next = mask_layer_shape_tmp->next;
+ BLI_remlink(&mask_layer->splines_shapes, mask_layer_shape_tmp);
+ BLI_addtail(&shapes_tmp, mask_layer_shape_tmp);
}
/* re-key, note: cant modify the keys here since it messes uop */
- for (masklay_shape_tmp = shapes_tmp.first; masklay_shape_tmp;
- masklay_shape_tmp = masklay_shape_tmp->next) {
- BKE_mask_layer_evaluate(masklay, masklay_shape_tmp->frame, true);
- masklay_shape_tmp_rekey = BKE_mask_layer_shape_verify_frame(masklay,
- masklay_shape_tmp->frame);
- BKE_mask_layer_shape_from_mask(masklay, masklay_shape_tmp_rekey);
- masklay_shape_tmp_rekey->flag = masklay_shape_tmp->flag & MASK_SHAPE_SELECT;
+ for (mask_layer_shape_tmp = shapes_tmp.first; mask_layer_shape_tmp;
+ mask_layer_shape_tmp = mask_layer_shape_tmp->next) {
+ BKE_mask_layer_evaluate(mask_layer, mask_layer_shape_tmp->frame, true);
+ mask_layer_shape_tmp_rekey = BKE_mask_layer_shape_verify_frame(
+ mask_layer, mask_layer_shape_tmp->frame);
+ BKE_mask_layer_shape_from_mask(mask_layer, mask_layer_shape_tmp_rekey);
+ mask_layer_shape_tmp_rekey->flag = mask_layer_shape_tmp->flag & MASK_SHAPE_SELECT;
}
/* restore unselected points and free copies */
- for (masklay_shape_tmp = shapes_tmp.first; masklay_shape_tmp;
- masklay_shape_tmp = masklay_shape_tmp_next) {
+ for (mask_layer_shape_tmp = shapes_tmp.first; mask_layer_shape_tmp;
+ mask_layer_shape_tmp = mask_layer_shape_tmp_next) {
/* restore */
int i_abs = 0;
- int i;
- MaskSpline *spline;
MaskLayerShapeElem *shape_ele_src;
MaskLayerShapeElem *shape_ele_dst;
- masklay_shape_tmp_next = masklay_shape_tmp->next;
+ mask_layer_shape_tmp_next = mask_layer_shape_tmp->next;
/* we know this exists, added above */
- masklay_shape_tmp_rekey = BKE_mask_layer_shape_find_frame(masklay,
- masklay_shape_tmp->frame);
+ mask_layer_shape_tmp_rekey = BKE_mask_layer_shape_find_frame(
+ mask_layer, mask_layer_shape_tmp->frame);
- shape_ele_src = (MaskLayerShapeElem *)masklay_shape_tmp->data;
- shape_ele_dst = (MaskLayerShapeElem *)masklay_shape_tmp_rekey->data;
+ shape_ele_src = (MaskLayerShapeElem *)mask_layer_shape_tmp->data;
+ shape_ele_dst = (MaskLayerShapeElem *)mask_layer_shape_tmp_rekey->data;
- for (spline = masklay->splines.first; spline; spline = spline->next) {
- for (i = 0; i < spline->tot_point; i++) {
+ for (MaskSpline *spline = mask_layer->splines.first; spline; spline = spline->next) {
+ for (int i = 0; i < spline->tot_point; i++) {
MaskSplinePoint *point = &spline->points[i];
/* not especially efficient but makes this easier to follow */
@@ -356,7 +347,7 @@ static int mask_shape_key_rekey_exec(bContext *C, wmOperator *op)
}
}
- BKE_mask_layer_shape_free(masklay_shape_tmp);
+ BKE_mask_layer_shape_free(mask_layer_shape_tmp);
}
changed = true;
@@ -364,7 +355,7 @@ static int mask_shape_key_rekey_exec(bContext *C, wmOperator *op)
}
/* re-evaluate */
- BKE_mask_layer_evaluate(masklay, frame, true);
+ BKE_mask_layer_evaluate(mask_layer, frame, true);
}
}
@@ -401,21 +392,20 @@ void MASK_OT_shape_key_rekey(wmOperatorType *ot)
/* *** Shape Key Utils *** */
-void ED_mask_layer_shape_auto_key(MaskLayer *masklay, const int frame)
+void ED_mask_layer_shape_auto_key(MaskLayer *mask_layer, const int frame)
{
- MaskLayerShape *masklay_shape;
+ MaskLayerShape *mask_layer_shape;
- masklay_shape = BKE_mask_layer_shape_verify_frame(masklay, frame);
- BKE_mask_layer_shape_from_mask(masklay, masklay_shape);
+ mask_layer_shape = BKE_mask_layer_shape_verify_frame(mask_layer, frame);
+ BKE_mask_layer_shape_from_mask(mask_layer, mask_layer_shape);
}
bool ED_mask_layer_shape_auto_key_all(Mask *mask, const int frame)
{
- MaskLayer *masklay;
bool changed = false;
- for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
- ED_mask_layer_shape_auto_key(masklay, frame);
+ for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
+ ED_mask_layer_shape_auto_key(mask_layer, frame);
changed = true;
}
@@ -424,16 +414,15 @@ bool ED_mask_layer_shape_auto_key_all(Mask *mask, const int frame)
bool ED_mask_layer_shape_auto_key_select(Mask *mask, const int frame)
{
- MaskLayer *masklay;
bool changed = false;
- for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
+ for (MaskLayer *mask_layer = mask->masklayers.first; mask_layer; mask_layer = mask_layer->next) {
- if (!ED_mask_layer_select_check(masklay)) {
+ if (!ED_mask_layer_select_check(mask_layer)) {
continue;
}
- ED_mask_layer_shape_auto_key(masklay, frame);
+ ED_mask_layer_shape_auto_key(mask_layer, frame);
changed = true;
}
diff --git a/source/blender/editors/mesh/editmesh_extrude_spin.c b/source/blender/editors/mesh/editmesh_extrude_spin.c
index bf4403e49ee..7cad7e1e062 100644
--- a/source/blender/editors/mesh/editmesh_extrude_spin.c
+++ b/source/blender/editors/mesh/editmesh_extrude_spin.c
@@ -200,7 +200,10 @@ void MESH_OT_spin(wmOperatorType *ot)
/* props */
RNA_def_int(ot->srna, "steps", 9, 0, 1000000, "Steps", "Steps", 0, 1000);
- RNA_def_boolean(ot->srna, "dupli", 0, "Duplicate", "Make Duplicates");
+
+ prop = RNA_def_boolean(ot->srna, "dupli", 0, "Use Duplicates", "");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+
prop = RNA_def_float(ot->srna,
"angle",
DEG2RADF(90.0f),
diff --git a/source/blender/editors/mesh/editmesh_mask_extract.c b/source/blender/editors/mesh/editmesh_mask_extract.c
index 8d98a3bf231..25d3118b3a9 100644
--- a/source/blender/editors/mesh/editmesh_mask_extract.c
+++ b/source/blender/editors/mesh/editmesh_mask_extract.c
@@ -30,6 +30,7 @@
#include "BKE_context.h"
#include "BKE_editmesh.h"
#include "BKE_layer.h"
+#include "BKE_library.h"
#include "BKE_mesh.h"
#include "BKE_modifier.h"
#include "BKE_paint.h"
@@ -179,7 +180,7 @@ static int paint_mask_extract_exec(bContext *C, wmOperator *op)
BM_mesh_elem_hflag_disable_all(bm, BM_VERT | BM_EDGE | BM_FACE, BM_ELEM_SELECT, false);
- BKE_mesh_free(new_mesh);
+ BKE_id_free(bmain, new_mesh);
new_mesh = BKE_mesh_from_bmesh_nomain(bm,
(&(struct BMeshToMeshParams){
.calc_object_remap = false,
@@ -190,7 +191,7 @@ static int paint_mask_extract_exec(bContext *C, wmOperator *op)
MEM_freeN(em);
if (new_mesh->totvert == 0) {
- BKE_mesh_free(new_mesh);
+ BKE_id_free(bmain, new_mesh);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/mesh/editmesh_polybuild.c b/source/blender/editors/mesh/editmesh_polybuild.c
index 21c850160dd..a91f0f9274e 100644
--- a/source/blender/editors/mesh/editmesh_polybuild.c
+++ b/source/blender/editors/mesh/editmesh_polybuild.c
@@ -216,7 +216,7 @@ static int edbm_polybuild_delete_at_cursor_invoke(bContext *C,
}
if (ele_act->head.htype == BM_VERT) {
BMVert *v_act = (BMVert *)ele_act;
- if (BM_vert_is_edge_pair(v_act)) {
+ if (BM_vert_is_edge_pair(v_act) && !BM_vert_is_wire(v_act)) {
BM_edge_collapse(bm, v_act->e, v_act, true, true);
changed = true;
}
diff --git a/source/blender/editors/render/render_view.c b/source/blender/editors/render/render_view.c
index a54701f8725..cbedb25ea64 100644
--- a/source/blender/editors/render/render_view.c
+++ b/source/blender/editors/render/render_view.c
@@ -118,7 +118,7 @@ static ScrArea *find_area_image_empty(bContext *C)
for (sa = sc->areabase.first; sa; sa = sa->next) {
if (sa->spacetype == SPACE_IMAGE) {
sima = sa->spacedata.first;
- if (!sima->image) {
+ if ((sima->mode == SI_MODE_VIEW) && !sima->image) {
break;
}
}
@@ -205,7 +205,7 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports)
/* we already had a fullscreen here -> mark new space as a stacked fullscreen */
if (sa->full) {
- sa->flag |= (AREA_FLAG_STACKED_FULLSCREEN | AREA_FLAG_TEMP_TYPE);
+ sa->flag |= AREA_FLAG_STACKED_FULLSCREEN;
}
}
else {
@@ -222,6 +222,7 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports)
}
}
sima = sa->spacedata.first;
+ sima->link_flag |= SPACE_FLAG_TYPE_TEMPORARY;
/* get the correct image, and scale it */
sima->image = BKE_image_verify_viewer(bmain, IMA_TYPE_R_RESULT, "Render Result");
diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c
index 9957fe0515c..ccee88eb0d6 100644
--- a/source/blender/editors/screen/area.c
+++ b/source/blender/editors/screen/area.c
@@ -1947,7 +1947,7 @@ void ED_area_newspace(bContext *C, ScrArea *sa, int type, const bool skip_ar_exi
if (sa->spacetype != type) {
SpaceType *st;
- SpaceLink *slold;
+ SpaceLink *slold = sa->spacedata.first;
SpaceLink *sl;
/* store sa->type->exit callback */
void *sa_exit = sa->type ? sa->type->exit : NULL;
@@ -1963,7 +1963,7 @@ void ED_area_newspace(bContext *C, ScrArea *sa, int type, const bool skip_ar_exi
*/
int header_alignment = ED_area_header_alignment_or_fallback(sa, -1);
const bool sync_header_alignment = ((header_alignment != -1) &&
- (sa->flag & AREA_FLAG_TEMP_TYPE) == 0);
+ ((slold->link_flag & SPACE_FLAG_TYPE_TEMPORARY) == 0));
/* in some cases (opening temp space) we don't want to
* call area exit callback, so we temporarily unset it */
@@ -1979,7 +1979,6 @@ void ED_area_newspace(bContext *C, ScrArea *sa, int type, const bool skip_ar_exi
}
st = BKE_spacetype_from_id(type);
- slold = sa->spacedata.first;
sa->spacetype = type;
sa->type = st;
@@ -2010,6 +2009,10 @@ void ED_area_newspace(bContext *C, ScrArea *sa, int type, const bool skip_ar_exi
slold->regionbase = sa->regionbase;
sa->regionbase = sl->regionbase;
BLI_listbase_clear(&sl->regionbase);
+ /* SPACE_FLAG_TYPE_WAS_ACTIVE is only used to go back to a previously active space that is
+ * overlapped by temporary ones. It's now properly activated, so the flag should be cleared
+ * at this point. */
+ sl->link_flag &= ~SPACE_FLAG_TYPE_WAS_ACTIVE;
/* put in front of list */
BLI_remlink(&sa->spacedata, sl);
@@ -2073,23 +2076,45 @@ void ED_area_newspace(bContext *C, ScrArea *sa, int type, const bool skip_ar_exi
ED_area_tag_redraw(sa);
}
-void ED_area_prevspace(bContext *C, ScrArea *sa)
+static SpaceLink *area_get_prevspace(ScrArea *sa)
{
SpaceLink *sl = sa->spacedata.first;
- if (sl && sl->next) {
- ED_area_newspace(C, sa, sl->next->spacetype, false);
+ /* First toggle to the next temporary space in the list. */
+ for (SpaceLink *sl_iter = sl->next; sl_iter; sl_iter = sl_iter->next) {
+ if (sl_iter->link_flag & SPACE_FLAG_TYPE_TEMPORARY) {
+ return sl_iter;
+ }
+ }
- /* keep old spacedata but move it to end, so calling
- * ED_area_prevspace once more won't open it again */
- BLI_remlink(&sa->spacedata, sl);
- BLI_addtail(&sa->spacedata, sl);
+ /* No temporary space, find the item marked as last active. */
+ for (SpaceLink *sl_iter = sl->next; sl_iter; sl_iter = sl_iter->next) {
+ if (sl_iter->link_flag & SPACE_FLAG_TYPE_WAS_ACTIVE) {
+ return sl_iter;
+ }
+ }
+
+ /* If neither is found, we can just return to the regular previous one. */
+ return sl->next;
+}
+
+void ED_area_prevspace(bContext *C, ScrArea *sa)
+{
+ SpaceLink *sl = sa->spacedata.first;
+ SpaceLink *prevspace = sl ? area_get_prevspace(sa) : NULL;
+
+ if (prevspace) {
+ ED_area_newspace(C, sa, prevspace->spacetype, false);
+ /* We've exited the space, so it can't be considered temporary anymore. */
+ sl->link_flag &= ~SPACE_FLAG_TYPE_TEMPORARY;
}
else {
/* no change */
return;
}
- sa->flag &= ~(AREA_FLAG_STACKED_FULLSCREEN | AREA_FLAG_TEMP_TYPE);
+ /* If this is a stacked fullscreen, changing to previous area exits it (meaning we're still in a
+ * fullscreen, but not in a stacked one). */
+ sa->flag &= ~AREA_FLAG_STACKED_FULLSCREEN;
ED_area_tag_redraw(sa);
@@ -3337,13 +3362,17 @@ const rcti *ED_region_visible_rect(ARegion *ar)
/* Cache display helpers */
-void ED_region_cache_draw_background(const ARegion *ar)
+void ED_region_cache_draw_background(ARegion *ar)
{
+ /* Local coordinate visible rect inside region, to accommodate overlapping ui. */
+ const rcti *rect_visible = ED_region_visible_rect(ar);
+ const int region_bottom = rect_visible->ymin;
+
uint pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
immUniformColor4ub(128, 128, 255, 64);
- immRecti(pos, 0, 0, ar->winx, 8 * UI_DPI_FAC);
+ immRecti(pos, 0, region_bottom, ar->winx, region_bottom + 8 * UI_DPI_FAC);
immUnbindProgram();
}
@@ -3373,9 +3402,13 @@ void ED_region_cache_draw_curfra_label(const int framenr, const float x, const f
}
void ED_region_cache_draw_cached_segments(
- const ARegion *ar, const int num_segments, const int *points, const int sfra, const int efra)
+ ARegion *ar, const int num_segments, const int *points, const int sfra, const int efra)
{
if (num_segments) {
+ /* Local coordinate visible rect inside region, to accommodate overlapping ui. */
+ const rcti *rect_visible = ED_region_visible_rect(ar);
+ const int region_bottom = rect_visible->ymin;
+
uint pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
@@ -3385,7 +3418,7 @@ void ED_region_cache_draw_cached_segments(
float x1 = (float)(points[a * 2] - sfra) / (efra - sfra + 1) * ar->winx;
float x2 = (float)(points[a * 2 + 1] - sfra + 1) / (efra - sfra + 1) * ar->winx;
- immRecti(pos, x1, 0, x2, 8 * UI_DPI_FAC);
+ immRecti(pos, x1, region_bottom, x2, region_bottom + 8 * UI_DPI_FAC);
/* TODO(merwin): use primitive restart to draw multiple rects more efficiently */
}
diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c
index bbdddfadc30..5b8fd33a4e9 100644
--- a/source/blender/editors/screen/screen_edit.c
+++ b/source/blender/editors/screen/screen_edit.c
@@ -1115,6 +1115,7 @@ ScrArea *ED_screen_full_newspace(bContext *C, ScrArea *sa, int type)
{
wmWindow *win = CTX_wm_window(C);
ScrArea *newsa = NULL;
+ SpaceLink *newsl;
if (!sa || sa->full == NULL) {
newsa = ED_screen_state_toggle(C, win, sa, SCREENMAXIMIZED);
@@ -1125,15 +1126,14 @@ ScrArea *ED_screen_full_newspace(bContext *C, ScrArea *sa, int type)
}
BLI_assert(newsa);
+ newsl = newsa->spacedata.first;
- if (sa && (sa->spacetype != type)) {
- newsa->flag |= AREA_FLAG_TEMP_TYPE;
- }
- else {
- newsa->flag &= ~AREA_FLAG_TEMP_TYPE;
+ /* 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) {
+ newsl->link_flag |= SPACE_FLAG_TYPE_WAS_ACTIVE;
}
- ED_area_newspace(C, newsa, type, (newsa->flag & AREA_FLAG_TEMP_TYPE));
+ ED_area_newspace(C, newsa, type, newsl->link_flag & SPACE_FLAG_TYPE_TEMPORARY);
return newsa;
}
@@ -1146,7 +1146,7 @@ void ED_screen_full_prevspace(bContext *C, ScrArea *sa)
BLI_assert(sa->full);
if (sa->flag & AREA_FLAG_STACKED_FULLSCREEN) {
- /* stacked fullscreen -> only go back to previous screen and don't toggle out of fullscreen */
+ /* stacked fullscreen -> only go back to previous area and don't toggle out of fullscreen */
ED_area_prevspace(C, sa);
}
else {
@@ -1156,13 +1156,13 @@ void ED_screen_full_prevspace(bContext *C, ScrArea *sa)
void ED_screen_restore_temp_type(bContext *C, ScrArea *sa)
{
+ SpaceLink *sl = sa->spacedata.first;
+
/* In case nether functions below run. */
ED_area_tag_redraw(sa);
- if (sa->flag & AREA_FLAG_TEMP_TYPE) {
+ if (sl->link_flag & SPACE_FLAG_TYPE_TEMPORARY) {
ED_area_prevspace(C, sa);
- /* Flag should be cleared now. */
- BLI_assert((sa->flag & AREA_FLAG_TEMP_TYPE) == 0);
}
if (sa->full) {
@@ -1182,7 +1182,7 @@ void ED_screen_full_restore(bContext *C, ScrArea *sa)
* overlaid on top of an existing setup) then return to the previous space */
if (sl->next) {
- if (sa->flag & AREA_FLAG_TEMP_TYPE) {
+ if (sl->link_flag & SPACE_FLAG_TYPE_TEMPORARY) {
ED_screen_full_prevspace(C, sa);
}
else {
@@ -1392,14 +1392,15 @@ ScrArea *ED_screen_temp_space_open(bContext *C,
if (ctx_sa->full) {
sa = ctx_sa;
ED_area_newspace(C, ctx_sa, space_type, true);
- /* we already had a fullscreen here -> mark new space as a stacked fullscreen */
- sa->flag |= (AREA_FLAG_STACKED_FULLSCREEN | AREA_FLAG_TEMP_TYPE);
+ sa->flag |= AREA_FLAG_STACKED_FULLSCREEN;
+ ((SpaceLink *)sa->spacedata.first)->link_flag |= SPACE_FLAG_TYPE_TEMPORARY;
}
else if (ctx_sa->spacetype == space_type) {
sa = ED_screen_state_toggle(C, CTX_wm_window(C), ctx_sa, SCREENMAXIMIZED);
}
else {
sa = ED_screen_full_newspace(C, ctx_sa, (int)space_type);
+ ((SpaceLink *)sa->spacedata.first)->link_flag |= SPACE_FLAG_TYPE_TEMPORARY;
}
break;
}
diff --git a/source/blender/editors/sculpt_paint/paint_image_2d.c b/source/blender/editors/sculpt_paint/paint_image_2d.c
index 9c95a3cee4d..a1e67e78a10 100644
--- a/source/blender/editors/sculpt_paint/paint_image_2d.c
+++ b/source/blender/editors/sculpt_paint/paint_image_2d.c
@@ -387,7 +387,12 @@ static unsigned short *brush_painter_curve_mask_new(BrushPainter *painter,
m = mask;
int aa_samples = 1.0f / (radius * 0.20f);
- aa_samples = clamp_i(aa_samples, 3, 16);
+ if (brush->sampling_flag & BRUSH_PAINT_ANTIALIASING) {
+ aa_samples = clamp_i(aa_samples, 3, 16);
+ }
+ else {
+ aa_samples = 1;
+ }
/* Temporal until we have the brush properties */
const float hardness = 1.0f;
diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c
index 77c95c6acb3..ac7cf310099 100644
--- a/source/blender/editors/sculpt_paint/paint_vertex.c
+++ b/source/blender/editors/sculpt_paint/paint_vertex.c
@@ -2341,7 +2341,7 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
/* calculate pivot for rotation around seletion if needed */
/* also needed for "View Selected" on last stroke */
- paint_last_stroke_update(scene, ss->cache->location);
+ paint_last_stroke_update(scene, ss->cache->true_location);
BKE_mesh_batch_cache_dirty_tag(ob->data, BKE_MESH_BATCH_DIRTY_ALL);
@@ -3316,7 +3316,7 @@ static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P
/* calculate pivot for rotation around seletion if needed */
/* also needed for "View Selected" on last stroke */
- paint_last_stroke_update(scene, ss->cache->location);
+ paint_last_stroke_update(scene, ss->cache->true_location);
ED_region_tag_redraw(vc->ar);
diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c
index 5d95cc80280..fc990c01bfb 100644
--- a/source/blender/editors/sculpt_paint/sculpt_undo.c
+++ b/source/blender/editors/sculpt_paint/sculpt_undo.c
@@ -77,6 +77,7 @@ static UndoSculpt *sculpt_undo_get_nodes(void);
static void update_cb(PBVHNode *node, void *rebuild)
{
BKE_pbvh_node_mark_update(node);
+ BKE_pbvh_node_mark_update_mask(node);
if (*((bool *)rebuild)) {
BKE_pbvh_node_mark_rebuild_draw(node);
}
@@ -497,7 +498,7 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase
SculptSession *ss = ob->sculpt;
SubdivCCG *subdiv_ccg = ss->subdiv_ccg;
SculptUndoNode *unode;
- bool update = false, rebuild = false;
+ bool update = false, rebuild = false, update_mask = false;
bool need_mask = false;
for (unode = lb->first; unode; unode = unode->next) {
@@ -579,6 +580,7 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase
case SCULPT_UNDO_MASK:
if (sculpt_undo_restore_mask(C, unode)) {
update = true;
+ update_mask = true;
}
break;
@@ -616,6 +618,9 @@ static void sculpt_undo_restore_list(bContext *C, Depsgraph *depsgraph, ListBase
};
BKE_pbvh_search_callback(ss->pbvh, NULL, NULL, update_cb_partial, &data);
BKE_pbvh_update_bounds(ss->pbvh, PBVH_UpdateBB | PBVH_UpdateOriginalBB | PBVH_UpdateRedraw);
+ if (update_mask) {
+ BKE_pbvh_update_vertex_data(ss->pbvh, PBVH_UpdateMask);
+ }
if (BKE_sculpt_multires_active(scene, ob)) {
if (rebuild) {
diff --git a/source/blender/editors/space_clip/clip_ops.c b/source/blender/editors/space_clip/clip_ops.c
index 192449a219d..4a4b85cbf8f 100644
--- a/source/blender/editors/space_clip/clip_ops.c
+++ b/source/blender/editors/space_clip/clip_ops.c
@@ -1118,7 +1118,7 @@ static int change_frame_invoke(bContext *C, wmOperator *op, const wmEvent *event
ARegion *ar = CTX_wm_region(C);
if (ar->regiontype == RGN_TYPE_WINDOW) {
- if (event->mval[1] > 16) {
+ if (event->mval[1] > 16 * UI_DPI_FAC) {
return OPERATOR_PASS_THROUGH;
}
}
diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c
index d29233618de..1ea7d81f9da 100644
--- a/source/blender/editors/space_file/filelist.c
+++ b/source/blender/editors/space_file/filelist.c
@@ -338,7 +338,7 @@ enum {
enum {
SPECIAL_IMG_DOCUMENT = 0,
- SPECIAL_IMG_UNSUPORTED = 1,
+ SPECIAL_IMG_DRIVE_DISC = 1,
SPECIAL_IMG_FOLDER = 2,
SPECIAL_IMG_PARENT = 3,
SPECIAL_IMG_DRIVE_FIXED = 4,
diff --git a/source/blender/editors/space_graph/space_graph.c b/source/blender/editors/space_graph/space_graph.c
index 91e5ab61dd9..95ad56a35e6 100644
--- a/source/blender/editors/space_graph/space_graph.c
+++ b/source/blender/editors/space_graph/space_graph.c
@@ -303,8 +303,10 @@ static void graph_main_region_draw(const bContext *C, ARegion *ar)
}
/* preview range */
- UI_view2d_view_ortho(v2d);
- ANIM_draw_previewrange(C, v2d, 0);
+ if (sipo->mode != SIPO_MODE_DRIVERS) {
+ UI_view2d_view_ortho(v2d);
+ ANIM_draw_previewrange(C, v2d, 0);
+ }
/* callback */
UI_view2d_view_ortho(v2d);
diff --git a/source/blender/editors/space_image/image_draw.c b/source/blender/editors/space_image/image_draw.c
index 9a2b0d95c20..2d4ca6dc15a 100644
--- a/source/blender/editors/space_image/image_draw.c
+++ b/source/blender/editors/space_image/image_draw.c
@@ -901,6 +901,10 @@ void draw_image_cache(const bContext *C, ARegion *ar)
mask = ED_space_image_get_mask(sima);
}
+ /* Local coordinate visible rect inside region, to accommodate overlapping ui. */
+ const rcti *rect_visible = ED_region_visible_rect(ar);
+ const int region_bottom = rect_visible->ymin;
+
GPU_blend(true);
GPU_blend_set_func_separate(
GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA);
@@ -928,10 +932,10 @@ void draw_image_cache(const bContext *C, ARegion *ar)
immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
immUniformThemeColor(TH_CFRAME);
- immRecti(pos, x, 0, x + ceilf(framelen), 8 * UI_DPI_FAC);
+ immRecti(pos, x, region_bottom, x + ceilf(framelen), region_bottom + 8 * UI_DPI_FAC);
immUnbindProgram();
- ED_region_cache_draw_curfra_label(cfra, x, 8.0f * UI_DPI_FAC);
+ ED_region_cache_draw_curfra_label(cfra, x, region_bottom + 8.0f * UI_DPI_FAC);
if (mask != NULL) {
ED_mask_draw_frames(mask, ar, cfra, sfra, efra);
diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c
index a8dfad85232..8d17b703449 100644
--- a/source/blender/editors/space_image/image_ops.c
+++ b/source/blender/editors/space_image/image_ops.c
@@ -3886,7 +3886,12 @@ static int change_frame_invoke(bContext *C, wmOperator *op, const wmEvent *event
if (ar->regiontype == RGN_TYPE_WINDOW) {
SpaceImage *sima = CTX_wm_space_image(C);
- if (event->mval[1] > 16 || !ED_space_image_show_cache(sima)) {
+
+ /* Local coordinate visible rect inside region, to accommodate overlapping ui. */
+ const rcti *rect_visible = ED_region_visible_rect(ar);
+ const int region_bottom = rect_visible->ymin;
+
+ if (event->mval[1] > (region_bottom + 16 * UI_DPI_FAC) || !ED_space_image_show_cache(sima)) {
return OPERATOR_PASS_THROUGH;
}
}
diff --git a/source/blender/editors/space_image/image_undo.c b/source/blender/editors/space_image/image_undo.c
index 577c4e24b11..b6b32293cee 100644
--- a/source/blender/editors/space_image/image_undo.c
+++ b/source/blender/editors/space_image/image_undo.c
@@ -115,7 +115,7 @@ typedef struct PaintTile {
ushort *mask;
bool valid;
bool use_float;
- int x, y;
+ int x_tile, y_tile;
} PaintTile;
static void ptile_free(PaintTile *ptile)
@@ -154,7 +154,7 @@ void *ED_image_paint_tile_find(ListBase *paint_tiles,
bool validate)
{
for (PaintTile *ptile = paint_tiles->first; ptile; ptile = ptile->next) {
- if (ptile->x == x_tile && ptile->y == y_tile) {
+ if (ptile->x_tile == x_tile && ptile->y_tile == y_tile) {
if (ptile->image == image && ptile->ibuf == ibuf) {
if (r_mask) {
/* allocate mask if requested. */
@@ -206,8 +206,8 @@ void *ED_image_paint_tile_push(ListBase *paint_tiles,
ptile->image = image;
ptile->ibuf = ibuf;
- ptile->x = x_tile;
- ptile->y = y_tile;
+ ptile->x_tile = x_tile;
+ ptile->y_tile = y_tile;
/* add mask explicitly here */
if (r_mask) {
@@ -269,8 +269,14 @@ static void ptile_restore_runtime_list(ListBase *paint_tiles)
SWAP(uint *, ptile->rect.uint, tmpibuf->rect);
}
- IMB_rectcpy(
- ibuf, tmpibuf, ptile->x, ptile->y, 0, 0, ED_IMAGE_UNDO_TILE_SIZE, ED_IMAGE_UNDO_TILE_SIZE);
+ IMB_rectcpy(ibuf,
+ tmpibuf,
+ ptile->x_tile * ED_IMAGE_UNDO_TILE_SIZE,
+ ptile->y_tile * ED_IMAGE_UNDO_TILE_SIZE,
+ 0,
+ 0,
+ ED_IMAGE_UNDO_TILE_SIZE,
+ ED_IMAGE_UNDO_TILE_SIZE);
if (has_float) {
SWAP(float *, ptile->rect.fp, tmpibuf->rect_float);
@@ -764,7 +770,7 @@ static bool image_undosys_step_encode(struct bContext *C,
utile->users = 1;
utile->rect.pt = ptile->rect.pt;
ptile->rect.pt = NULL;
- const uint tile_index = index_from_xy(ptile->x, ptile->y, ubuf_pre->tiles_dims);
+ const uint tile_index = index_from_xy(ptile->x_tile, ptile->y_tile, ubuf_pre->tiles_dims);
BLI_assert(ubuf_pre->tiles[tile_index] == NULL);
ubuf_pre->tiles[tile_index] = utile;
diff --git a/source/blender/editors/space_info/info_ops.c b/source/blender/editors/space_info/info_ops.c
index 14817e9ffa1..124e3c08165 100644
--- a/source/blender/editors/space_info/info_ops.c
+++ b/source/blender/editors/space_info/info_ops.c
@@ -211,6 +211,7 @@ static const EnumPropertyItem unpack_all_method_items[] = {
"Write files to original location (overwrite existing files)",
""},
{PF_KEEP, "KEEP", 0, "Disable Auto-pack, keep all packed files", ""},
+ {PF_REMOVE, "REMOVE", 0, "Remove Pack", ""},
/* {PF_ASK, "ASK", 0, "Ask for each file", ""}, */
{0, NULL, 0, NULL, NULL},
};
diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c
index c5271e9df06..cb6275e3f44 100644
--- a/source/blender/editors/space_outliner/outliner_draw.c
+++ b/source/blender/editors/space_outliner/outliner_draw.c
@@ -756,14 +756,15 @@ static void namebutton_cb(bContext *C, void *tsep, char *oldname)
}
case TSE_BONE: {
- ViewLayer *view_layer = CTX_data_view_layer(C);
- Scene *scene = CTX_data_scene(C);
+ TreeViewContext tvc;
+ outliner_viewcontext_init(C, &tvc);
+
bArmature *arm = (bArmature *)tselem->id;
Bone *bone = te->directdata;
char newname[sizeof(bone->name)];
/* always make current object active */
- tree_element_active(C, scene, view_layer, soops, te, OL_SETSEL_NORMAL, true);
+ tree_element_active(C, &tvc, soops, te, OL_SETSEL_NORMAL, true);
/* restore bone name */
BLI_strncpy(newname, bone->name, sizeof(bone->name));
@@ -773,14 +774,15 @@ static void namebutton_cb(bContext *C, void *tsep, char *oldname)
break;
}
case TSE_POSE_CHANNEL: {
- Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
+ TreeViewContext tvc;
+ outliner_viewcontext_init(C, &tvc);
+
Object *ob = (Object *)tselem->id;
bPoseChannel *pchan = te->directdata;
char newname[sizeof(pchan->name)];
/* always make current pose-bone active */
- tree_element_active(C, scene, view_layer, soops, te, OL_SETSEL_NORMAL, true);
+ tree_element_active(C, &tvc, soops, te, OL_SETSEL_NORMAL, true);
BLI_assert(ob->type == OB_ARMATURE);
@@ -2819,8 +2821,7 @@ typedef struct MergedIconRow {
static void outliner_draw_iconrow(bContext *C,
uiBlock *block,
const uiFontStyle *fstyle,
- Scene *scene,
- ViewLayer *view_layer,
+ const TreeViewContext *tvc,
SpaceOutliner *soops,
ListBase *lb,
int level,
@@ -2831,7 +2832,6 @@ static void outliner_draw_iconrow(bContext *C,
MergedIconRow *merged)
{
eOLDrawState active = OL_DRAWSEL_NONE;
- const Object *obact = OBACT(view_layer);
for (TreeElement *te = lb->first; te; te = te->next) {
TreeStoreElem *tselem = TREESTORE(te);
@@ -2841,14 +2841,13 @@ static void outliner_draw_iconrow(bContext *C,
/* active blocks get white circle */
if (tselem->type == 0) {
if (te->idcode == ID_OB) {
- active = (OBACT(view_layer) == (Object *)tselem->id) ? OL_DRAWSEL_NORMAL :
- OL_DRAWSEL_NONE;
+ active = (tvc->obact == (Object *)tselem->id) ? OL_DRAWSEL_NORMAL : OL_DRAWSEL_NONE;
}
- else if (is_object_data_in_editmode(tselem->id, obact)) {
+ else if (is_object_data_in_editmode(tselem->id, tvc->obact)) {
active = OL_DRAWSEL_ACTIVE;
}
else {
- active = tree_element_active(C, scene, view_layer, soops, te, OL_SETSEL_NONE, false);
+ active = tree_element_active(C, tvc, soops, te, OL_SETSEL_NONE, false);
}
}
else if (tselem->type == TSE_GP_LAYER) {
@@ -2856,8 +2855,7 @@ static void outliner_draw_iconrow(bContext *C,
active = (gpl->flag & GP_LAYER_ACTIVE) ? OL_DRAWSEL_ACTIVE : OL_DRAWSEL_NONE;
}
else {
- active = tree_element_type_active(
- C, scene, view_layer, soops, te, tselem, OL_SETSEL_NONE, false);
+ active = tree_element_type_active(C, tvc, soops, te, tselem, OL_SETSEL_NONE, false);
}
if (!ELEM(tselem->type, 0, TSE_LAYER_COLLECTION, TSE_R_LAYER, TSE_GP_LAYER)) {
@@ -2878,8 +2876,7 @@ static void outliner_draw_iconrow(bContext *C,
outliner_draw_iconrow(C,
block,
fstyle,
- scene,
- view_layer,
+ tvc,
soops,
&te->subtree,
level + 1,
@@ -2937,8 +2934,7 @@ static void outliner_set_coord_tree_element(TreeElement *te, int startx, int sta
static void outliner_draw_tree_element(bContext *C,
uiBlock *block,
const uiFontStyle *fstyle,
- Scene *scene,
- ViewLayer *view_layer,
+ const TreeViewContext *tvc,
ARegion *ar,
SpaceOutliner *soops,
TreeElement *te,
@@ -2977,9 +2973,8 @@ static void outliner_draw_tree_element(bContext *C,
/* colors for active/selected data */
if (tselem->type == 0) {
- const Object *obact = OBACT(view_layer);
if (te->idcode == ID_SCE) {
- if (tselem->id == (ID *)scene) {
+ if (tselem->id == (ID *)tvc->scene) {
/* active scene */
icon_bgcolor[3] = 0.2f;
active = OL_DRAWSEL_ACTIVE;
@@ -2988,15 +2983,15 @@ static void outliner_draw_tree_element(bContext *C,
else if (te->idcode == ID_OB) {
Object *ob = (Object *)tselem->id;
Base *base = (te->directdata) ? (Base *)te->directdata :
- BKE_view_layer_base_find(view_layer, ob);
+ BKE_view_layer_base_find(tvc->view_layer, ob);
const bool is_selected = (base != NULL) && ((base->flag & BASE_SELECTED) != 0);
- if (ob == obact) {
+ if (ob == tvc->obact) {
active = OL_DRAWSEL_ACTIVE;
}
if (is_selected) {
- if (ob == obact) {
+ if (ob == tvc->obact) {
/* active selected object */
UI_GetThemeColor3ubv(TH_ACTIVE_OBJECT, text_color);
text_color[3] = 255;
@@ -3008,14 +3003,14 @@ static void outliner_draw_tree_element(bContext *C,
}
}
}
- else if (is_object_data_in_editmode(tselem->id, obact)) {
+ else if (is_object_data_in_editmode(tselem->id, tvc->obact)) {
/* objects being edited */
UI_GetThemeColor4fv(TH_EDITED_OBJECT, icon_bgcolor);
icon_border[3] = 0.3f;
active = OL_DRAWSEL_ACTIVE;
}
else {
- if (tree_element_active(C, scene, view_layer, soops, te, OL_SETSEL_NONE, false)) {
+ if (tree_element_active(C, tvc, soops, te, OL_SETSEL_NONE, false)) {
/* active items like camera or material */
icon_bgcolor[3] = 0.2f;
active = OL_DRAWSEL_ACTIVE;
@@ -3030,8 +3025,7 @@ static void outliner_draw_tree_element(bContext *C,
}
}
else {
- active = tree_element_type_active(
- C, scene, view_layer, soops, te, tselem, OL_SETSEL_NONE, false);
+ active = tree_element_type_active(C, tvc, soops, te, tselem, OL_SETSEL_NONE, false);
/* active collection*/
icon_bgcolor[3] = 0.2f;
}
@@ -3040,7 +3034,7 @@ static void outliner_draw_tree_element(bContext *C,
if ((tselem->type == TSE_LAYER_COLLECTION) &&
(soops->show_restrict_flags & SO_RESTRICT_ENABLE)) {
tselem_draw_layer_collection_enable_icon(
- scene, block, xmax, (float)startx + offsx + UI_UNIT_X, (float)*starty, te, 0.8f);
+ tvc->scene, block, xmax, (float)startx + offsx + UI_UNIT_X, (float)*starty, te, 0.8f);
offsx += UI_UNIT_X;
}
@@ -3159,8 +3153,7 @@ static void outliner_draw_tree_element(bContext *C,
outliner_draw_iconrow(C,
block,
fstyle,
- scene,
- view_layer,
+ tvc,
soops,
&te->subtree,
0,
@@ -3190,8 +3183,7 @@ static void outliner_draw_tree_element(bContext *C,
outliner_draw_tree_element(C,
block,
fstyle,
- scene,
- view_layer,
+ tvc,
ar,
soops,
ten,
@@ -3490,8 +3482,7 @@ static void outliner_draw_highlights(ARegion *ar, SpaceOutliner *soops, int star
static void outliner_draw_tree(bContext *C,
uiBlock *block,
- Scene *scene,
- ViewLayer *view_layer,
+ const TreeViewContext *tvc,
ARegion *ar,
SpaceOutliner *soops,
const float restrict_column_width,
@@ -3537,8 +3528,7 @@ static void outliner_draw_tree(bContext *C,
outliner_draw_tree_element(C,
block,
fstyle,
- scene,
- view_layer,
+ tvc,
ar,
soops,
te,
@@ -3629,15 +3619,16 @@ static void outliner_update_viewable_area(ARegion *ar,
void draw_outliner(const bContext *C)
{
Main *mainvar = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
ARegion *ar = CTX_wm_region(C);
View2D *v2d = &ar->v2d;
SpaceOutliner *soops = CTX_wm_space_outliner(C);
uiBlock *block;
TreeElement *te_edit = NULL;
- outliner_build_tree(mainvar, scene, view_layer, soops, ar); // always
+ TreeViewContext tvc;
+ outliner_viewcontext_init(C, &tvc);
+
+ outliner_build_tree(mainvar, tvc.scene, tvc.view_layer, soops, ar); // always
/* If global sync select is dirty, flag other outliners */
if (ED_outliner_select_sync_is_dirty(C)) {
@@ -3659,8 +3650,7 @@ void draw_outliner(const bContext *C)
const float restrict_column_width = outliner_restrict_columns_width(soops);
outliner_back(ar);
block = UI_block_begin(C, ar, __func__, UI_EMBOSS);
- outliner_draw_tree(
- (bContext *)C, block, scene, view_layer, ar, soops, restrict_column_width, &te_edit);
+ outliner_draw_tree((bContext *)C, block, &tvc, ar, soops, restrict_column_width, &te_edit);
/* Compute outliner dimensions after it has been drawn. */
int tree_width, tree_height;
@@ -3686,7 +3676,8 @@ void draw_outliner(const bContext *C)
/* draw restriction columns */
RestrictPropertiesActive props_active;
memset(&props_active, 1, sizeof(RestrictPropertiesActive));
- outliner_draw_restrictbuts(block, scene, view_layer, ar, soops, &soops->tree, props_active);
+ outliner_draw_restrictbuts(
+ block, tvc.scene, tvc.view_layer, ar, soops, &soops->tree, props_active);
}
UI_block_emboss_set(block, UI_EMBOSS);
diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c
index c55140db46f..34bbf3a2a30 100644
--- a/source/blender/editors/space_outliner/outliner_edit.c
+++ b/source/blender/editors/space_outliner/outliner_edit.c
@@ -1600,7 +1600,11 @@ static void tree_element_show_hierarchy(Scene *scene, SpaceOutliner *soops, List
for (te = lb->first; te; te = te->next) {
tselem = TREESTORE(te);
- if (tselem->type == 0) {
+ if (ELEM(tselem->type,
+ 0,
+ TSE_SCENE_OBJECTS_BASE,
+ TSE_VIEW_COLLECTION_BASE,
+ TSE_LAYER_COLLECTION)) {
if (te->idcode == ID_SCE) {
if (tselem->id != (ID *)scene) {
tselem->flag |= TSE_CLOSED;
diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h
index 95e37dea249..23c883c0db3 100644
--- a/source/blender/editors/space_outliner/outliner_intern.h
+++ b/source/blender/editors/space_outliner/outliner_intern.h
@@ -200,6 +200,25 @@ typedef enum {
#define TSELEM_OPEN(telm, sv) \
((telm->flag & TSE_CLOSED) == 0 || (SEARCHING_OUTLINER(sv) && (telm->flag & TSE_CHILDSEARCH)))
+/**
+ * Container to avoid passing around these variables to many functions.
+ * Also so we can have one place to assing these variables.
+ */
+typedef struct TreeViewContext {
+ /* Scene level. */
+ struct Scene *scene;
+ struct ViewLayer *view_layer;
+
+ /* Object level. */
+ /** Avoid OBACT macro everywhere. */
+ Object *obact;
+ Object *ob_edit;
+ /**
+ * The pose object may not be the active object (when in weight paint mode).
+ * Checking this in draw loops isn't efficient, so set only once. */
+ Object *ob_pose;
+} TreeViewContext;
+
/* outliner_tree.c ----------------------------------------------- */
void outliner_free_tree(ListBase *tree);
@@ -237,16 +256,14 @@ int tree_element_id_type_to_index(TreeElement *te);
/* outliner_select.c -------------------------------------------- */
eOLDrawState tree_element_type_active(struct bContext *C,
- struct Scene *scene,
- struct ViewLayer *view_layer,
+ const TreeViewContext *tvc,
struct SpaceOutliner *soops,
TreeElement *te,
TreeStoreElem *tselem,
const eOLSetState set,
bool recursive);
eOLDrawState tree_element_active(struct bContext *C,
- struct Scene *scene,
- struct ViewLayer *view_layer,
+ const TreeViewContext *tvc,
SpaceOutliner *soops,
TreeElement *te,
const eOLSetState set,
@@ -267,7 +284,8 @@ void outliner_object_mode_toggle(struct bContext *C,
void outliner_element_activate(struct SpaceOutliner *soops, struct TreeStoreElem *tselem);
-bool outliner_item_is_co_within_close_toggle(TreeElement *te, float view_co_x);
+bool outliner_item_is_co_over_name_icons(const TreeElement *te, float view_co_x);
+bool outliner_item_is_co_within_close_toggle(const TreeElement *te, float view_co_x);
/* outliner_edit.c ---------------------------------------------- */
typedef void (*outliner_operation_cb)(struct bContext *C,
@@ -457,6 +475,8 @@ void OUTLINER_OT_unhide_all(struct wmOperatorType *ot);
/* outliner_utils.c ---------------------------------------------- */
+void outliner_viewcontext_init(const struct bContext *C, TreeViewContext *tvc);
+
TreeElement *outliner_find_item_at_y(const SpaceOutliner *soops,
const ListBase *tree,
float view_co_y);
diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c
index 19bbb115788..c96f2f9956f 100644
--- a/source/blender/editors/space_outliner/outliner_select.c
+++ b/source/blender/editors/space_outliner/outliner_select.c
@@ -595,6 +595,7 @@ static eOLDrawState tree_element_active_posegroup(bContext *C,
static eOLDrawState tree_element_active_posechannel(bContext *C,
Scene *UNUSED(scene),
ViewLayer *view_layer,
+ Object *ob_pose,
TreeElement *te,
TreeStoreElem *tselem,
const eOLSetState set,
@@ -651,7 +652,7 @@ static eOLDrawState tree_element_active_posechannel(bContext *C,
}
}
else {
- if (ob == OBACT(view_layer) && ob->pose) {
+ if (ob == ob_pose && ob->pose) {
if (pchan->bone->flag & BONE_SELECTED) {
return OL_DRAWSEL_NORMAL;
}
@@ -1007,8 +1008,7 @@ static eOLDrawState tree_element_active_layer_collection(bContext *C,
/* generic call for ID data check or make/check active in UI */
eOLDrawState tree_element_active(bContext *C,
- Scene *scene,
- ViewLayer *view_layer,
+ const TreeViewContext *tvc,
SpaceOutliner *soops,
TreeElement *te,
const eOLSetState set,
@@ -1020,17 +1020,18 @@ eOLDrawState tree_element_active(bContext *C,
* See #do_outliner_item_activate. */
case ID_OB:
if (handle_all_types) {
- return tree_element_set_active_object(C, scene, view_layer, soops, te, set, false);
+ return tree_element_set_active_object(
+ C, tvc->scene, tvc->view_layer, soops, te, set, false);
}
break;
case ID_MA:
- return tree_element_active_material(C, scene, view_layer, soops, te, set);
+ return tree_element_active_material(C, tvc->scene, tvc->view_layer, soops, te, set);
case ID_WO:
- return tree_element_active_world(C, scene, view_layer, soops, te, set);
+ return tree_element_active_world(C, tvc->scene, tvc->view_layer, soops, te, set);
case ID_TXT:
- return tree_element_active_text(C, scene, view_layer, soops, te, set);
+ return tree_element_active_text(C, tvc->scene, tvc->view_layer, soops, te, set);
case ID_CA:
- return tree_element_active_camera(C, scene, view_layer, soops, te, set);
+ return tree_element_active_camera(C, tvc->scene, tvc->view_layer, soops, te, set);
}
return OL_DRAWSEL_NONE;
}
@@ -1039,8 +1040,7 @@ eOLDrawState tree_element_active(bContext *C,
* Generic call for non-id data to make/check active in UI
*/
eOLDrawState tree_element_type_active(bContext *C,
- Scene *scene,
- ViewLayer *view_layer,
+ const TreeViewContext *tvc,
SpaceOutliner *soops,
TreeElement *te,
TreeStoreElem *tselem,
@@ -1049,41 +1049,42 @@ eOLDrawState tree_element_type_active(bContext *C,
{
switch (tselem->type) {
case TSE_DEFGROUP:
- return tree_element_active_defgroup(C, view_layer, te, tselem, set);
+ return tree_element_active_defgroup(C, tvc->view_layer, te, tselem, set);
case TSE_BONE:
- return tree_element_active_bone(C, view_layer, te, tselem, set, recursive);
+ return tree_element_active_bone(C, tvc->view_layer, te, tselem, set, recursive);
case TSE_EBONE:
- return tree_element_active_ebone(C, view_layer, te, tselem, set, recursive);
+ return tree_element_active_ebone(C, tvc->view_layer, te, tselem, set, recursive);
case TSE_MODIFIER:
- return tree_element_active_modifier(C, scene, view_layer, te, tselem, set);
+ return tree_element_active_modifier(C, tvc->scene, tvc->view_layer, te, tselem, set);
case TSE_LINKED_OB:
if (set != OL_SETSEL_NONE) {
- tree_element_set_active_object(C, scene, view_layer, soops, te, set, false);
+ tree_element_set_active_object(C, tvc->scene, tvc->view_layer, soops, te, set, false);
}
- else if (tselem->id == (ID *)OBACT(view_layer)) {
+ else if (tselem->id == (ID *)tvc->obact) {
return OL_DRAWSEL_NORMAL;
}
break;
case TSE_LINKED_PSYS:
- return tree_element_active_psys(C, scene, te, tselem, set);
+ return tree_element_active_psys(C, tvc->scene, te, tselem, set);
case TSE_POSE_BASE:
- return tree_element_active_pose(C, scene, view_layer, te, tselem, set);
+ return tree_element_active_pose(C, tvc->scene, tvc->view_layer, te, tselem, set);
case TSE_POSE_CHANNEL:
- return tree_element_active_posechannel(C, scene, view_layer, te, tselem, set, recursive);
+ return tree_element_active_posechannel(
+ C, tvc->scene, tvc->view_layer, tvc->ob_pose, te, tselem, set, recursive);
case TSE_CONSTRAINT:
- return tree_element_active_constraint(C, scene, view_layer, te, tselem, set);
+ return tree_element_active_constraint(C, tvc->scene, tvc->view_layer, te, tselem, set);
case TSE_R_LAYER:
- return active_viewlayer(C, scene, view_layer, te, set);
+ return active_viewlayer(C, tvc->scene, tvc->view_layer, te, set);
case TSE_POSEGRP:
- return tree_element_active_posegroup(C, scene, view_layer, te, tselem, set);
+ return tree_element_active_posegroup(C, tvc->scene, tvc->view_layer, te, tselem, set);
case TSE_SEQUENCE:
- return tree_element_active_sequence(C, scene, te, tselem, set);
+ return tree_element_active_sequence(C, tvc->scene, te, tselem, set);
case TSE_SEQUENCE_DUP:
- return tree_element_active_sequence_dup(scene, te, tselem, set);
+ return tree_element_active_sequence_dup(tvc->scene, te, tselem, set);
case TSE_KEYMAP_ITEM:
- return tree_element_active_keymap_item(C, scene, view_layer, te, tselem, set);
+ return tree_element_active_keymap_item(C, tvc->scene, tvc->view_layer, te, tselem, set);
case TSE_GP_LAYER:
- return tree_element_active_gplayer(C, scene, te, tselem, set);
+ return tree_element_active_gplayer(C, tvc->scene, te, tselem, set);
break;
case TSE_VIEW_COLLECTION_BASE:
return tree_element_active_master_collection(C, te, set);
@@ -1109,14 +1110,15 @@ void outliner_element_activate(SpaceOutliner *soops, TreeStoreElem *tselem)
* Needed to run from operators accessed from a menu.
*/
static void do_outliner_item_activate_tree_element(bContext *C,
- Scene *scene,
- ViewLayer *view_layer,
+ const TreeViewContext *tvc,
SpaceOutliner *soops,
TreeElement *te,
TreeStoreElem *tselem,
const bool extend,
- const bool recursive)
+ const bool recursive,
+ const bool is_over_name_icons)
{
+ bool do_activate_data = soops->flag & SO_SYNC_SELECT || is_over_name_icons;
/* Always makes active object, except for some specific types. */
if (ELEM(tselem->type,
TSE_SEQUENCE,
@@ -1133,11 +1135,11 @@ static void do_outliner_item_activate_tree_element(bContext *C,
else if (tselem->type == TSE_POSE_BASE) {
/* Support pose mode toggle, keeping the active object as is. */
}
- else if (soops->flag & SO_SYNC_SELECT) {
+ else if (do_activate_data) {
/* Only activate when synced selection is enabled */
tree_element_set_active_object(C,
- scene,
- view_layer,
+ tvc->scene,
+ tvc->view_layer,
soops,
te,
(extend && tselem->type == 0) ? OL_SETSEL_EXTEND :
@@ -1149,9 +1151,11 @@ static void do_outliner_item_activate_tree_element(bContext *C,
outliner_element_activate(soops, tselem);
if (tselem->type == 0) { // the lib blocks
- /* editmode? */
- if (te->idcode == ID_SCE) {
- if (scene != (Scene *)tselem->id) {
+ if (do_activate_data == false) {
+ /* Only select in outliner. */
+ }
+ else if (te->idcode == ID_SCE) {
+ if (tvc->scene != (Scene *)tselem->id) {
WM_window_set_active_scene(CTX_data_main(C), C, CTX_wm_window(C), (Scene *)tselem->id);
}
}
@@ -1161,7 +1165,7 @@ static void do_outliner_item_activate_tree_element(bContext *C,
if (extend) {
int sel = BA_SELECT;
FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (gr, object) {
- Base *base = BKE_view_layer_base_find(view_layer, object);
+ Base *base = BKE_view_layer_base_find(tvc->view_layer, object);
if (base && (base->flag & BASE_SELECTED)) {
sel = BA_DESELECT;
break;
@@ -1170,7 +1174,7 @@ static void do_outliner_item_activate_tree_element(bContext *C,
FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (gr, object) {
- Base *base = BKE_view_layer_base_find(view_layer, object);
+ Base *base = BKE_view_layer_base_find(tvc->view_layer, object);
if (base) {
ED_object_base_select(base, sel);
}
@@ -1178,10 +1182,10 @@ static void do_outliner_item_activate_tree_element(bContext *C,
FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
}
else {
- BKE_view_layer_base_deselect_all(view_layer);
+ BKE_view_layer_base_deselect_all(tvc->view_layer);
FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (gr, object) {
- Base *base = BKE_view_layer_base_find(view_layer, object);
+ Base *base = BKE_view_layer_base_find(tvc->view_layer, object);
/* Object may not be in this scene */
if (base != NULL) {
if ((base->flag & BASE_SELECTED) == 0) {
@@ -1192,15 +1196,15 @@ static void do_outliner_item_activate_tree_element(bContext *C,
FOREACH_COLLECTION_OBJECT_RECURSIVE_END;
}
- DEG_id_tag_update(&scene->id, ID_RECALC_SELECT);
- WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene);
+ DEG_id_tag_update(&tvc->scene->id, ID_RECALC_SELECT);
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, tvc->scene);
}
else if (OB_DATA_SUPPORT_EDITMODE(te->idcode)) {
Object *ob = (Object *)outliner_search_back(soops, te, ID_OB);
if ((ob != NULL) && (ob->data == tselem->id)) {
- Base *base = BKE_view_layer_base_find(view_layer, ob);
+ Base *base = BKE_view_layer_base_find(tvc->view_layer, ob);
if ((base != NULL) && (base->flag & BASE_VISIBLE_DEPSGRAPH)) {
- do_outliner_activate_obdata(C, scene, view_layer, base, extend);
+ do_outliner_activate_obdata(C, tvc->scene, tvc->view_layer, base, extend);
}
}
}
@@ -1209,18 +1213,12 @@ static void do_outliner_item_activate_tree_element(bContext *C,
WM_operator_name_call(C, "GPENCIL_OT_editmode_toggle", WM_OP_INVOKE_REGION_WIN, NULL);
}
else { // rest of types
- tree_element_active(C, scene, view_layer, soops, te, OL_SETSEL_NORMAL, false);
+ tree_element_active(C, tvc, soops, te, OL_SETSEL_NORMAL, false);
}
}
- else if (soops->flag & SO_SYNC_SELECT) {
- tree_element_type_active(C,
- scene,
- view_layer,
- soops,
- te,
- tselem,
- extend ? OL_SETSEL_EXTEND : OL_SETSEL_NORMAL,
- recursive);
+ else if (do_activate_data) {
+ tree_element_type_active(
+ C, tvc, soops, te, tselem, extend ? OL_SETSEL_EXTEND : OL_SETSEL_NORMAL, recursive);
}
}
@@ -1327,12 +1325,12 @@ static bool outliner_is_co_within_restrict_columns(const SpaceOutliner *soops,
void outliner_item_do_activate_from_tree_element(
bContext *C, TreeElement *te, TreeStoreElem *tselem, bool extend, bool recursive)
{
- Scene *scene = CTX_data_scene(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
SpaceOutliner *soops = CTX_wm_space_outliner(C);
- do_outliner_item_activate_tree_element(
- C, scene, view_layer, soops, te, tselem, extend, recursive);
+ TreeViewContext tvc;
+ outliner_viewcontext_init(C, &tvc);
+
+ do_outliner_item_activate_tree_element(C, &tvc, soops, te, tselem, extend, recursive, false);
}
/**
@@ -1347,7 +1345,6 @@ static int outliner_item_do_activate_from_cursor(bContext *C,
const bool deselect_all)
{
ARegion *ar = CTX_wm_region(C);
- Scene *scene = CTX_data_scene(C);
SpaceOutliner *soops = CTX_wm_space_outliner(C);
TreeElement *te;
float view_mval[2];
@@ -1371,8 +1368,6 @@ static int outliner_item_do_activate_from_cursor(bContext *C,
return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
}
else {
- ViewLayer *view_layer = CTX_data_view_layer(C);
-
/* The row may also contain children, if one is hovered we want this instead of current te */
bool merged_elements = false;
TreeElement *activate_te = outliner_find_item_at_x_in_row(
@@ -1390,9 +1385,14 @@ static int outliner_item_do_activate_from_cursor(bContext *C,
do_outliner_range_select(C, soops, activate_te, extend);
}
else {
+ TreeViewContext tvc;
+ outliner_viewcontext_init(C, &tvc);
+
+ const bool is_over_name_icons = outliner_item_is_co_over_name_icons(activate_te,
+ view_mval[0]);
outliner_item_select(soops, activate_te, extend, extend);
do_outliner_item_activate_tree_element(
- C, scene, view_layer, soops, activate_te, activate_tselem, extend, false);
+ C, &tvc, soops, activate_te, activate_tselem, extend, false, is_over_name_icons);
}
changed = true;
@@ -1505,17 +1505,6 @@ static int outliner_box_select_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-/* Find if x coordinate is over an icon or name */
-static bool outliner_item_is_co_over_name_icons(TreeElement *te, float view_co_x)
-{
- /* Special case: count area left of Scene Collection as empty space */
- bool outside_left = (TREESTORE(te)->type == TSE_VIEW_COLLECTION_BASE) ?
- (view_co_x > te->xs + UI_UNIT_X) :
- (view_co_x > te->xs);
-
- return outside_left && (view_co_x < te->xend);
-}
-
static int outliner_box_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
SpaceOutliner *soops = CTX_wm_space_outliner(C);
diff --git a/source/blender/editors/space_outliner/outliner_sync.c b/source/blender/editors/space_outliner/outliner_sync.c
index 29c820bce92..745a527cc15 100644
--- a/source/blender/editors/space_outliner/outliner_sync.c
+++ b/source/blender/editors/space_outliner/outliner_sync.c
@@ -37,6 +37,7 @@
#include "BKE_context.h"
#include "BKE_layer.h"
#include "BKE_main.h"
+#include "BKE_object.h"
#include "BKE_sequencer.h"
#include "DEG_depsgraph.h"
@@ -129,14 +130,14 @@ static void outliner_sync_select_from_outliner_set_types(bContext *C,
SpaceOutliner *soops,
SyncSelectTypes *sync_types)
{
- Object *obact = CTX_data_active_object(C);
- Object *obedit = CTX_data_edit_object(C);
+ TreeViewContext tvc;
+ outliner_viewcontext_init(C, &tvc);
const bool sequence_view = soops->outlinevis == SO_SEQUENCE;
sync_types->object = !sequence_view;
- sync_types->edit_bone = !sequence_view && (obedit && obedit->type == OB_ARMATURE);
- sync_types->pose_bone = !sequence_view && (obact && obact->mode == OB_MODE_POSE);
+ sync_types->edit_bone = !sequence_view && (tvc.ob_edit && tvc.ob_edit->type == OB_ARMATURE);
+ sync_types->pose_bone = !sequence_view && (tvc.ob_pose && tvc.ob_pose->mode == OB_MODE_POSE);
sync_types->sequence = sequence_view;
}
@@ -149,16 +150,16 @@ static bool outliner_sync_select_to_outliner_set_types(const bContext *C,
SpaceOutliner *soops,
SyncSelectTypes *sync_types)
{
- Object *obact = CTX_data_active_object(C);
- Object *obedit = CTX_data_edit_object(C);
+ TreeViewContext tvc;
+ outliner_viewcontext_init(C, &tvc);
const bool sequence_view = soops->outlinevis == SO_SEQUENCE;
sync_types->object = !sequence_view &&
(soops->sync_select_dirty & WM_OUTLINER_SYNC_SELECT_FROM_OBJECT);
- sync_types->edit_bone = !sequence_view && (obedit && obedit->type == OB_ARMATURE) &&
+ sync_types->edit_bone = !sequence_view && (tvc.ob_edit && tvc.ob_edit->type == OB_ARMATURE) &&
(soops->sync_select_dirty & WM_OUTLINER_SYNC_SELECT_FROM_EDIT_BONE);
- sync_types->pose_bone = !sequence_view && (obact && obact->mode == OB_MODE_POSE) &&
+ sync_types->pose_bone = !sequence_view && (tvc.ob_pose && tvc.ob_pose->mode == OB_MODE_POSE) &&
(soops->sync_select_dirty & WM_OUTLINER_SYNC_SELECT_FROM_POSE_BONE);
sync_types->sequence = sequence_view &&
(soops->sync_select_dirty & WM_OUTLINER_SYNC_SELECT_FROM_SEQUENCE);
diff --git a/source/blender/editors/space_outliner/outliner_utils.c b/source/blender/editors/space_outliner/outliner_utils.c
index 5dfdf6f129b..c3984ab16fa 100644
--- a/source/blender/editors/space_outliner/outliner_utils.c
+++ b/source/blender/editors/space_outliner/outliner_utils.c
@@ -21,6 +21,8 @@
* \ingroup spoutliner
*/
+#include <string.h>
+
#include "BLI_utildefines.h"
#include "DNA_action_types.h"
@@ -30,6 +32,7 @@
#include "BKE_context.h"
#include "BKE_outliner_treehash.h"
#include "BKE_layer.h"
+#include "BKE_object.h"
#include "ED_armature.h"
#include "ED_outliner.h"
@@ -39,6 +42,33 @@
#include "outliner_intern.h"
+/* -------------------------------------------------------------------- */
+/** \name Tree View Context
+ * \{ */
+
+void outliner_viewcontext_init(const bContext *C, TreeViewContext *tvc)
+{
+ memset(tvc, 0, sizeof(*tvc));
+
+ /* Scene level. */
+ tvc->scene = CTX_data_scene(C);
+ tvc->view_layer = CTX_data_view_layer(C);
+
+ /* Objects. */
+ tvc->obact = OBACT(tvc->view_layer);
+ if (tvc->obact != NULL) {
+ tvc->ob_edit = OBEDIT_FROM_OBACT(tvc->obact);
+
+ if ((tvc->obact->type == OB_ARMATURE) ||
+ /* This could be made into it's own function. */
+ ((tvc->obact->type == OB_MESH) && tvc->obact->mode & OB_MODE_WEIGHT_PAINT)) {
+ tvc->ob_pose = BKE_object_pose_armature_get(tvc->obact);
+ }
+ }
+}
+
+/** \} */
+
/**
* Try to find an item under y-coordinate \a view_co_y (view-space).
* \note Recursive
@@ -361,8 +391,19 @@ bool outliner_is_element_visible(const TreeElement *te)
return true;
}
+/* Find if x coordinate is over an icon or name */
+bool outliner_item_is_co_over_name_icons(const TreeElement *te, float view_co_x)
+{
+ /* Special case: count area left of Scene Collection as empty space */
+ bool outside_left = (TREESTORE(te)->type == TSE_VIEW_COLLECTION_BASE) ?
+ (view_co_x > te->xs + UI_UNIT_X) :
+ (view_co_x > te->xs);
+
+ return outside_left && (view_co_x < te->xend);
+}
+
/* Find if x coordinate is over element disclosure toggle */
-bool outliner_item_is_co_within_close_toggle(TreeElement *te, float view_co_x)
+bool outliner_item_is_co_within_close_toggle(const TreeElement *te, float view_co_x)
{
return (view_co_x > te->xs) && (view_co_x < te->xs + UI_UNIT_X);
}
diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c
index 1a788237e6e..5b2ea9d4793 100644
--- a/source/blender/editors/space_sequencer/sequencer_draw.c
+++ b/source/blender/editors/space_sequencer/sequencer_draw.c
@@ -1767,8 +1767,8 @@ static void draw_seq_strips(const bContext *C, Editing *ed, ARegion *ar)
static void seq_draw_sfra_efra(Scene *scene, View2D *v2d)
{
const Editing *ed = BKE_sequencer_editing_get(scene, false);
- const int frame_sta = PSFRA;
- const int frame_end = PEFRA + 1;
+ const int frame_sta = scene->r.sfra;
+ const int frame_end = scene->r.efra + 1;
GPU_blend(true);
diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c
index 865dfb45278..ed384cfc1a8 100644
--- a/source/blender/editors/space_sequencer/sequencer_edit.c
+++ b/source/blender/editors/space_sequencer/sequencer_edit.c
@@ -177,7 +177,7 @@ static void proxy_endjob(void *pjv)
WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, pj->scene);
}
-static void seq_proxy_build_job(const bContext *C)
+static void seq_proxy_build_job(const bContext *C, ReportList *reports)
{
wmJob *wm_job;
ProxyJob *pj;
@@ -216,8 +216,11 @@ static void seq_proxy_build_job(const bContext *C)
file_list = BLI_gset_new(BLI_ghashutil_strhash_p, BLI_ghashutil_strcmp, "file list");
SEQP_BEGIN (ed, seq) {
if ((seq->flag & SELECT)) {
- BKE_sequencer_proxy_rebuild_context(
+ bool success = BKE_sequencer_proxy_rebuild_context(
pj->main, pj->depsgraph, pj->scene, seq, file_list, &pj->queue);
+ if (!success) {
+ BKE_reportf(reports, RPT_ERROR, "Could not build proxy for strip %s", seq->name);
+ }
}
}
SEQ_END;
@@ -3608,10 +3611,10 @@ void SEQUENCER_OT_view_ghost_border(wmOperatorType *ot)
/* rebuild_proxy operator */
static int sequencer_rebuild_proxy_invoke(bContext *C,
- wmOperator *UNUSED(op),
+ wmOperator *op,
const wmEvent *UNUSED(event))
{
- seq_proxy_build_job(C);
+ seq_proxy_build_job(C, op->reports);
return OPERATOR_FINISHED;
}
@@ -4181,3 +4184,67 @@ void SEQUENCER_OT_export_subtitles(struct wmOperatorType *ot)
FILE_DEFAULTDISPLAY,
FILE_SORT_ALPHA);
}
+
+static int sequencer_set_range_to_strips_exec(bContext *C, wmOperator *op)
+{
+ Scene *scene = CTX_data_scene(C);
+ Editing *ed = BKE_sequencer_editing_get(scene, false);
+ Sequence *seq;
+
+ int sfra = MAXFRAME;
+ int efra = -MAXFRAME;
+ bool selected = false;
+ const bool preview = RNA_boolean_get(op->ptr, "preview");
+
+ for (seq = ed->seqbasep->first; seq; seq = seq->next) {
+ if (seq->flag & SELECT) {
+ selected = true;
+ sfra = min_ii(sfra, seq->startdisp);
+ efra = max_ii(efra, seq->enddisp - 1);
+ }
+ }
+
+ if (!selected) {
+ BKE_report(op->reports, RPT_WARNING, "Select one or more strips");
+ return OPERATOR_CANCELLED;
+ }
+ else if (efra < 0) {
+ BKE_report(op->reports, RPT_ERROR, "Can't set a negative range");
+ return OPERATOR_CANCELLED;
+ }
+
+ if (preview) {
+ scene->r.flag |= SCER_PRV_RANGE;
+ scene->r.psfra = max_ii(0, sfra);
+ scene->r.pefra = efra;
+ }
+ else {
+ scene->r.flag &= ~SCER_PRV_RANGE;
+ scene->r.sfra = max_ii(0, sfra);
+ scene->r.efra = efra;
+ }
+
+ WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
+
+ return OPERATOR_FINISHED;
+}
+
+void SEQUENCER_OT_set_range_to_strips(struct wmOperatorType *ot)
+{
+ PropertyRNA *prop;
+
+ /* identifiers */
+ ot->name = "Set Range to Strips";
+ ot->idname = "SEQUENCER_OT_set_range_to_strips";
+ ot->description = "Set the frame range to the selected strips start and end";
+
+ /* api callbacks */
+ ot->exec = sequencer_set_range_to_strips_exec;
+ ot->poll = sequencer_edit_poll;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+ prop = RNA_def_boolean(ot->srna, "preview", false, "Preview", "Set the preview range instead");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+}
diff --git a/source/blender/editors/space_sequencer/sequencer_intern.h b/source/blender/editors/space_sequencer/sequencer_intern.h
index 851d3b5f3aa..0a51578da3b 100644
--- a/source/blender/editors/space_sequencer/sequencer_intern.h
+++ b/source/blender/editors/space_sequencer/sequencer_intern.h
@@ -149,6 +149,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);
+
/* preview specific operators */
void SEQUENCER_OT_view_all_preview(struct wmOperatorType *ot);
@@ -160,7 +162,7 @@ void SEQUENCER_OT_select_less(struct wmOperatorType *ot);
void SEQUENCER_OT_select_linked(struct wmOperatorType *ot);
void SEQUENCER_OT_select_linked_pick(struct wmOperatorType *ot);
void SEQUENCER_OT_select_handles(struct wmOperatorType *ot);
-void SEQUENCER_OT_select_active_side(struct wmOperatorType *ot);
+void SEQUENCER_OT_select_side(struct wmOperatorType *ot);
void SEQUENCER_OT_select_box(struct wmOperatorType *ot);
void SEQUENCER_OT_select_inverse(struct wmOperatorType *ot);
void SEQUENCER_OT_select_grouped(struct wmOperatorType *ot);
diff --git a/source/blender/editors/space_sequencer/sequencer_ops.c b/source/blender/editors/space_sequencer/sequencer_ops.c
index b0bb775de83..af03035d10f 100644
--- a/source/blender/editors/space_sequencer/sequencer_ops.c
+++ b/source/blender/editors/space_sequencer/sequencer_ops.c
@@ -88,6 +88,8 @@ void sequencer_operatortypes(void)
WM_operatortype_append(SEQUENCER_OT_change_effect_type);
WM_operatortype_append(SEQUENCER_OT_change_path);
+ WM_operatortype_append(SEQUENCER_OT_set_range_to_strips);
+
/* sequencer_select.c */
WM_operatortype_append(SEQUENCER_OT_select_all);
WM_operatortype_append(SEQUENCER_OT_select);
@@ -96,7 +98,7 @@ void sequencer_operatortypes(void)
WM_operatortype_append(SEQUENCER_OT_select_linked_pick);
WM_operatortype_append(SEQUENCER_OT_select_linked);
WM_operatortype_append(SEQUENCER_OT_select_handles);
- WM_operatortype_append(SEQUENCER_OT_select_active_side);
+ WM_operatortype_append(SEQUENCER_OT_select_side);
WM_operatortype_append(SEQUENCER_OT_select_box);
WM_operatortype_append(SEQUENCER_OT_select_grouped);
diff --git a/source/blender/editors/space_sequencer/sequencer_select.c b/source/blender/editors/space_sequencer/sequencer_select.c
index 4c20fc1707a..a51b08f7525 100644
--- a/source/blender/editors/space_sequencer/sequencer_select.c
+++ b/source/blender/editors/space_sequencer/sequencer_select.c
@@ -27,6 +27,7 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
+#include "BLI_math.h"
#include "DNA_scene_types.h"
@@ -81,7 +82,7 @@ static void select_surrounding_handles(Scene *scene, Sequence *test) /* XXX BRIN
}
}
-/* used for mouse selection and for SEQUENCER_OT_select_active_side() */
+/* Used for mouse selection in SEQUENCER_OT_select. */
static void select_active_side(ListBase *seqbase, int sel_side, int channel, int frame)
{
Sequence *seq;
@@ -110,7 +111,43 @@ static void select_active_side(ListBase *seqbase, int sel_side, int channel, int
}
}
-/* used for mouse selection and for SEQUENCER_OT_select_active_side() */
+/* Used for mouse selection in SEQUENCER_OT_select_side. */
+static void select_active_side_range(ListBase *seqbase,
+ const int sel_side,
+ const int frame_ranges[MAXSEQ],
+ const int frame_ignore)
+{
+ Sequence *seq;
+
+ for (seq = seqbase->first; seq; seq = seq->next) {
+ if (seq->machine < MAXSEQ) {
+ const int frame = frame_ranges[seq->machine];
+ if (frame == frame_ignore) {
+ continue;
+ }
+ switch (sel_side) {
+ case SEQ_SIDE_LEFT:
+ if (frame > (seq->startdisp)) {
+ seq->flag &= ~(SEQ_RIGHTSEL | SEQ_LEFTSEL);
+ seq->flag |= SELECT;
+ }
+ break;
+ case SEQ_SIDE_RIGHT:
+ if (frame < (seq->startdisp)) {
+ seq->flag &= ~(SEQ_RIGHTSEL | SEQ_LEFTSEL);
+ seq->flag |= SELECT;
+ }
+ break;
+ case SEQ_SIDE_BOTH:
+ seq->flag &= ~(SEQ_RIGHTSEL | SEQ_LEFTSEL);
+ seq->flag |= SELECT;
+ break;
+ }
+ }
+ }
+}
+
+/* used for mouse selection in SEQUENCER_OT_select */
static void select_linked_time(ListBase *seqbase, Sequence *seq_link)
{
Sequence *seq;
@@ -913,20 +950,39 @@ void SEQUENCER_OT_select_handles(wmOperatorType *ot)
}
/* select side operator */
-static int sequencer_select_active_side_exec(bContext *C, wmOperator *op)
+static int sequencer_select_side_exec(bContext *C, wmOperator *op)
{
Scene *scene = CTX_data_scene(C);
Editing *ed = BKE_sequencer_editing_get(scene, false);
- Sequence *seq_act = BKE_sequencer_active_get(scene);
- if (ed == NULL || seq_act == NULL) {
- return OPERATOR_CANCELLED;
+ const int sel_side = RNA_enum_get(op->ptr, "side");
+ const int frame_init = sel_side == SEQ_SIDE_LEFT ? INT_MIN : INT_MAX;
+ int frame_ranges[MAXSEQ];
+ bool selected = false;
+
+ copy_vn_i(frame_ranges, ARRAY_SIZE(frame_ranges), frame_init);
+
+ for (Sequence *seq = ed->seqbasep->first; seq; seq = seq->next) {
+ if (UNLIKELY(seq->machine >= MAXSEQ)) {
+ continue;
+ }
+ int *frame_limit_p = &frame_ranges[seq->machine];
+ if (seq->flag & SELECT) {
+ selected = true;
+ if (sel_side == SEQ_SIDE_LEFT) {
+ *frame_limit_p = max_ii(*frame_limit_p, seq->startdisp);
+ }
+ else {
+ *frame_limit_p = min_ii(*frame_limit_p, seq->startdisp);
+ }
+ }
}
- seq_act->flag |= SELECT;
+ if (selected == false) {
+ return OPERATOR_CANCELLED;
+ }
- select_active_side(
- ed->seqbasep, RNA_enum_get(op->ptr, "side"), seq_act->machine, seq_act->startdisp);
+ select_active_side_range(ed->seqbasep, sel_side, frame_ranges, frame_init);
ED_outliner_select_sync_from_sequence_tag(C);
@@ -935,15 +991,15 @@ static int sequencer_select_active_side_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
-void SEQUENCER_OT_select_active_side(wmOperatorType *ot)
+void SEQUENCER_OT_select_side(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Select Active Side";
- ot->idname = "SEQUENCER_OT_select_active_side";
- ot->description = "Select strips on the nominated side of the active strip";
+ ot->name = "Select Side";
+ ot->idname = "SEQUENCER_OT_select_side";
+ ot->description = "Select strips on the nominated side of the selected strips";
/* api callbacks */
- ot->exec = sequencer_select_active_side_exec;
+ ot->exec = sequencer_select_side_exec;
ot->poll = sequencer_edit_poll;
/* flags */
@@ -955,7 +1011,7 @@ void SEQUENCER_OT_select_active_side(wmOperatorType *ot)
prop_side_types,
SEQ_SIDE_BOTH,
"Side",
- "The side of the handle that is selected");
+ "The side to which the selection is applied");
}
/* box_select operator */
diff --git a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c
index a5b7fac624d..e53957b054d 100644
--- a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c
+++ b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c
@@ -1183,6 +1183,10 @@ static int view3d_ruler_remove_invoke(bContext *C, wmOperator *op, const wmEvent
else {
ruler_item_remove(C, gzgroup, ruler_item);
}
+
+ /* Update the annotation layer. */
+ view3d_ruler_to_gpencil(C, gzgroup);
+
ED_region_tag_redraw(ar);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c
index a66e76abc58..15208c1a7d2 100644
--- a/source/blender/editors/transform/transform_snap.c
+++ b/source/blender/editors/transform/transform_snap.c
@@ -379,6 +379,8 @@ void applyProject(TransInfo *t)
.snap_select = t->tsnap.modeSelect,
.use_object_edit_cage = (t->flag & T_EDIT) != 0,
.use_occlusion_test = false,
+ .use_backface_culling = (t->scene->toolsettings->snap_flag &
+ SCE_SNAP_BACKFACE_CULLING) != 0,
},
mval_fl,
NULL,
@@ -1364,6 +1366,8 @@ short snapObjectsTransform(
.snap_select = t->tsnap.modeSelect,
.use_object_edit_cage = (t->flag & T_EDIT) != 0,
.use_occlusion_test = t->scene->toolsettings->snap_mode != SCE_SNAP_MODE_FACE,
+ .use_backface_culling = (t->scene->toolsettings->snap_flag &
+ SCE_SNAP_BACKFACE_CULLING) != 0,
},
mval,
t->tsnap.snapTarget,
diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c
index f35a2808f22..14e8b8f97e0 100644
--- a/source/blender/editors/transform/transform_snap_object.c
+++ b/source/blender/editors/transform/transform_snap_object.c
@@ -201,8 +201,12 @@ static SnapObjectData_EditMesh *snap_object_data_editmesh_get(SnapObjectContext
return *sod_p;
}
-typedef void (*IterSnapObjsCallback)(
- SnapObjectContext *sctx, bool is_obedit, Object *ob, float obmat[4][4], void *data);
+typedef void (*IterSnapObjsCallback)(SnapObjectContext *sctx,
+ bool is_obedit,
+ bool use_backface_culling,
+ Object *ob,
+ float obmat[4][4],
+ void *data);
/**
* Walks through all objects in the scene to create the list of objects to snap.
@@ -219,6 +223,7 @@ static void iter_snap_objects(SnapObjectContext *sctx,
const View3D *v3d = sctx->v3d_data.v3d;
const eSnapSelect snap_select = params->snap_select;
const bool use_object_edit_cage = params->use_object_edit_cage;
+ const bool use_backface_culling = params->use_backface_culling;
Base *base_act = view_layer->basact;
for (Base *base = view_layer->object_bases.first; base != NULL; base = base->next) {
@@ -250,12 +255,14 @@ static void iter_snap_objects(SnapObjectContext *sctx,
DupliObject *dupli_ob;
ListBase *lb = object_duplilist(sctx->depsgraph, sctx->scene, obj_eval);
for (dupli_ob = lb->first; dupli_ob; dupli_ob = dupli_ob->next) {
- sob_callback(sctx, use_object_edit_cage, dupli_ob->ob, dupli_ob->mat, data);
+ sob_callback(
+ sctx, use_object_edit_cage, use_backface_culling, dupli_ob->ob, dupli_ob->mat, data);
}
free_object_duplilist(lb);
}
- sob_callback(sctx, use_object_edit_cage, obj_eval, obj_eval->obmat, data);
+ sob_callback(
+ sctx, use_object_edit_cage, use_backface_culling, obj_eval, obj_eval->obmat, data);
}
}
@@ -350,6 +357,70 @@ static void raycast_all_cb(void *userdata, int index, const BVHTreeRay *ray, BVH
}
}
+static bool raycast_tri_backface_culling_test(
+ const float dir[3], const float v0[3], const float v1[3], const float v2[3], float no[3])
+{
+ cross_tri_v3(no, v0, v1, v2);
+ return dot_v3v3(no, dir) < 0.0f;
+}
+
+/* Callback to raycast with backface culling (Mesh). */
+static void mesh_looptri_raycast_backface_culling_cb(void *userdata,
+ int index,
+ const BVHTreeRay *ray,
+ BVHTreeRayHit *hit)
+{
+ const BVHTreeFromMesh *data = (BVHTreeFromMesh *)userdata;
+ const MVert *vert = data->vert;
+ const MLoopTri *lt = &data->looptri[index];
+ const float *vtri_co[3] = {
+ vert[data->loop[lt->tri[0]].v].co,
+ vert[data->loop[lt->tri[1]].v].co,
+ vert[data->loop[lt->tri[2]].v].co,
+ };
+ float dist = bvhtree_ray_tri_intersection(ray, hit->dist, UNPACK3(vtri_co));
+
+ if (dist >= 0 && dist < hit->dist) {
+ float no[3];
+ if (raycast_tri_backface_culling_test(ray->direction, UNPACK3(vtri_co), no)) {
+ hit->index = index;
+ hit->dist = dist;
+ madd_v3_v3v3fl(hit->co, ray->origin, ray->direction, dist);
+ normalize_v3_v3(hit->no, no);
+ }
+ }
+}
+
+/* Callback to raycast with backface culling (EditMesh). */
+static void editmesh_looptri_raycast_backface_culling_cb(void *userdata,
+ int index,
+ const BVHTreeRay *ray,
+ BVHTreeRayHit *hit)
+{
+ const BVHTreeFromEditMesh *data = (BVHTreeFromEditMesh *)userdata;
+ BMEditMesh *em = data->em;
+ const BMLoop **ltri = (const BMLoop **)em->looptris[index];
+
+ const float *t0, *t1, *t2;
+ t0 = ltri[0]->v->co;
+ t1 = ltri[1]->v->co;
+ t2 = ltri[2]->v->co;
+
+ {
+ float dist = bvhtree_ray_tri_intersection(ray, hit->dist, t0, t1, t2);
+
+ if (dist >= 0 && dist < hit->dist) {
+ float no[3];
+ if (raycast_tri_backface_culling_test(ray->direction, t0, t1, t2, no)) {
+ hit->index = index;
+ hit->dist = dist;
+ madd_v3_v3v3fl(hit->co, ray->origin, ray->direction, dist);
+ normalize_v3_v3(hit->no, no);
+ }
+ }
+ }
+}
+
static bool raycastMesh(SnapObjectContext *sctx,
const float ray_start[3],
const float ray_dir[3],
@@ -358,6 +429,7 @@ static bool raycastMesh(SnapObjectContext *sctx,
const float obmat[4][4],
const unsigned int ob_index,
bool use_hide,
+ bool use_backface_culling,
/* read/write args */
float *ray_depth,
/* return args */
@@ -494,7 +566,8 @@ static bool raycastMesh(SnapObjectContext *sctx,
ray_normal_local,
0.0f,
&hit,
- treedata->raycast_callback,
+ use_backface_culling ? mesh_looptri_raycast_backface_culling_cb :
+ treedata->raycast_callback,
treedata) != -1) {
hit.dist += len_diff;
hit.dist /= local_scale;
@@ -530,6 +603,7 @@ static bool raycastEditMesh(SnapObjectContext *sctx,
BMEditMesh *em,
const float obmat[4][4],
const unsigned int ob_index,
+ bool use_backface_culling,
/* read/write args */
float *ray_depth,
/* return args */
@@ -670,7 +744,8 @@ static bool raycastEditMesh(SnapObjectContext *sctx,
ray_normal_local,
0.0f,
&hit,
- treedata->raycast_callback,
+ use_backface_culling ? editmesh_looptri_raycast_backface_culling_cb :
+ treedata->raycast_callback,
treedata) != -1) {
hit.dist += len_diff;
hit.dist /= local_scale;
@@ -715,6 +790,7 @@ static bool raycastObj(SnapObjectContext *sctx,
const unsigned int ob_index,
bool use_obedit,
bool use_occlusion_test,
+ bool use_backface_culling,
/* read/write args */
float *ray_depth,
/* return args */
@@ -753,6 +829,7 @@ static bool raycastObj(SnapObjectContext *sctx,
em,
obmat,
ob_index,
+ use_backface_culling,
ray_depth,
r_loc,
r_no,
@@ -773,6 +850,7 @@ static bool raycastObj(SnapObjectContext *sctx,
obmat,
ob_index,
use_hide,
+ use_backface_culling,
ray_depth,
r_loc,
r_no,
@@ -792,6 +870,7 @@ static bool raycastObj(SnapObjectContext *sctx,
obmat,
ob_index,
false,
+ use_backface_culling,
ray_depth,
r_loc,
r_no,
@@ -832,8 +911,12 @@ struct RaycastObjUserData {
bool ret;
};
-static void raycast_obj_cb(
- SnapObjectContext *sctx, bool use_obedit, Object *ob, float obmat[4][4], void *data)
+static void raycast_obj_cb(SnapObjectContext *sctx,
+ bool use_obedit,
+ bool use_backface_culling,
+ Object *ob,
+ float obmat[4][4],
+ void *data)
{
struct RaycastObjUserData *dt = data;
@@ -845,6 +928,7 @@ static void raycast_obj_cb(
dt->ob_index++,
use_obedit,
dt->use_occlusion_test,
+ use_backface_culling,
dt->ray_depth,
dt->r_loc,
dt->r_no,
@@ -1088,8 +1172,6 @@ typedef void (*Nearest2DGetTriEdgesCallback)(const int index, int e_index[3], vo
typedef void (*Nearest2DCopyVertNoCallback)(const int index, float r_no[3], void *data);
typedef struct Nearest2dUserData {
- bool is_persp;
-
void *userdata;
Nearest2DGetVertCoCallback get_vert_co;
Nearest2DGetEdgeVertsCallback get_edge_verts_index;
@@ -1097,6 +1179,8 @@ typedef struct Nearest2dUserData {
Nearest2DGetTriEdgesCallback get_tri_edges_index;
Nearest2DCopyVertNoCallback copy_vert_no;
+ bool is_persp;
+ bool use_backface_culling;
} Nearest2dUserData;
static void cb_snap_vert(void *userdata,
@@ -1181,6 +1265,20 @@ static void cb_snap_tri_edges(void *userdata,
{
struct Nearest2dUserData *data = userdata;
+ if (data->use_backface_culling) {
+ int vindex[3];
+ data->get_tri_verts_index(index, vindex, data->userdata);
+
+ const float *t0, *t1, *t2;
+ data->get_vert_co(vindex[0], &t0, data->userdata);
+ data->get_vert_co(vindex[1], &t1, data->userdata);
+ data->get_vert_co(vindex[2], &t2, data->userdata);
+ float dummy[3];
+ if (raycast_tri_backface_culling_test(precalc->ray_direction, t0, t1, t2, dummy)) {
+ return;
+ }
+ }
+
int eindex[3];
data->get_tri_edges_index(index, eindex, data->userdata);
for (int i = 3; i--;) {
@@ -1204,6 +1302,18 @@ static void cb_snap_tri_verts(void *userdata,
int vindex[3];
data->get_tri_verts_index(index, vindex, data->userdata);
+
+ if (data->use_backface_culling) {
+ const float *t0, *t1, *t2;
+ data->get_vert_co(vindex[0], &t0, data->userdata);
+ data->get_vert_co(vindex[1], &t1, data->userdata);
+ data->get_vert_co(vindex[2], &t2, data->userdata);
+ float dummy[3];
+ if (raycast_tri_backface_culling_test(precalc->ray_direction, t0, t1, t2, dummy)) {
+ return;
+ }
+ }
+
for (int i = 3; i--;) {
if (vindex[i] == nearest->index) {
continue;
@@ -1222,6 +1332,7 @@ static short snap_mesh_polygon(SnapObjectContext *sctx,
SnapData *snapdata,
Object *ob,
const float obmat[4][4],
+ bool use_backface_culling,
/* read/write args */
float *dist_px,
/* return args */
@@ -1246,6 +1357,7 @@ static short snap_mesh_polygon(SnapObjectContext *sctx,
Nearest2dUserData nearest2d = {
.is_persp = snapdata->view_proj == VIEW_PROJ_PERSP,
+ .use_backface_culling = use_backface_culling,
};
BVHTreeNearest nearest = {
@@ -1366,6 +1478,7 @@ static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx,
const float obmat[4][4],
float original_dist_px,
const float prev_co[3],
+ bool use_backface_culling,
/* read/write args */
float *dist_px,
/* return args */
@@ -1392,6 +1505,7 @@ static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx,
Nearest2dUserData nearest2d;
{
nearest2d.is_persp = snapdata->view_proj == VIEW_PROJ_PERSP;
+ nearest2d.use_backface_culling = use_backface_culling;
if (sod->type == SNAP_MESH) {
nearest2d.userdata = &((SnapObjectData_Mesh *)sod)->treedata;
nearest2d.get_vert_co = (Nearest2DGetVertCoCallback)cb_mvert_co_get;
@@ -1995,6 +2109,7 @@ static short snapMesh(SnapObjectContext *sctx,
Object *ob,
Mesh *me,
const float obmat[4][4],
+ bool use_backface_culling,
/* read/write args */
float *dist_px,
/* return args */
@@ -2107,13 +2222,14 @@ static short snapMesh(SnapObjectContext *sctx,
}
Nearest2dUserData nearest2d = {
- .is_persp = snapdata->view_proj == VIEW_PROJ_PERSP,
.userdata = treedata,
.get_vert_co = (Nearest2DGetVertCoCallback)cb_mvert_co_get,
.get_edge_verts_index = (Nearest2DGetEdgeVertsCallback)cb_medge_verts_get,
.get_tri_verts_index = (Nearest2DGetTriVertsCallback)cb_mlooptri_verts_get,
.get_tri_edges_index = (Nearest2DGetTriEdgesCallback)cb_mlooptri_edges_get,
.copy_vert_no = (Nearest2DCopyVertNoCallback)cb_mvert_no_copy,
+ .is_persp = snapdata->view_proj == VIEW_PROJ_PERSP,
+ .use_backface_culling = use_backface_culling,
};
BVHTreeNearest nearest = {
@@ -2233,6 +2349,7 @@ static short snapEditMesh(SnapObjectContext *sctx,
Object *ob,
BMEditMesh *em,
const float obmat[4][4],
+ bool use_backface_culling,
/* read/write args */
float *dist_px,
/* return args */
@@ -2346,11 +2463,12 @@ static short snapEditMesh(SnapObjectContext *sctx,
}
Nearest2dUserData nearest2d = {
- .is_persp = snapdata->view_proj == VIEW_PROJ_PERSP,
.userdata = em,
.get_vert_co = (Nearest2DGetVertCoCallback)cb_bvert_co_get,
.get_edge_verts_index = (Nearest2DGetEdgeVertsCallback)cb_bedge_verts_get,
.copy_vert_no = (Nearest2DCopyVertNoCallback)cb_bvert_no_copy,
+ .is_persp = snapdata->view_proj == VIEW_PROJ_PERSP,
+ .use_backface_culling = use_backface_culling,
};
BVHTreeNearest nearest = {
@@ -2436,6 +2554,7 @@ static short snapObject(SnapObjectContext *sctx,
Object *ob,
float obmat[4][4],
bool use_obedit,
+ bool use_backface_culling,
/* read/write args */
float *dist_px,
/* return args */
@@ -2453,7 +2572,8 @@ static short snapObject(SnapObjectContext *sctx,
if (BKE_object_is_in_editmode(ob)) {
BMEditMesh *em = BKE_editmesh_from_object(ob);
if (use_obedit) {
- retval = snapEditMesh(sctx, snapdata, ob, em, obmat, dist_px, r_loc, r_no, r_index);
+ retval = snapEditMesh(
+ sctx, snapdata, ob, em, obmat, use_backface_culling, dist_px, r_loc, r_no, r_index);
break;
}
else if (em->mesh_eval_final) {
@@ -2465,7 +2585,8 @@ static short snapObject(SnapObjectContext *sctx,
return 0;
}
- retval = snapMesh(sctx, snapdata, ob, me, obmat, dist_px, r_loc, r_no, r_index);
+ retval = snapMesh(
+ sctx, snapdata, ob, me, obmat, use_backface_culling, dist_px, r_loc, r_no, r_index);
break;
}
case OB_ARMATURE:
@@ -2477,8 +2598,16 @@ static short snapObject(SnapObjectContext *sctx,
case OB_SURF:
case OB_FONT: {
if (ob->runtime.mesh_eval) {
- retval |= snapMesh(
- sctx, snapdata, ob, ob->runtime.mesh_eval, obmat, dist_px, r_loc, r_no, r_index);
+ retval |= snapMesh(sctx,
+ snapdata,
+ ob,
+ ob->runtime.mesh_eval,
+ obmat,
+ use_backface_culling,
+ dist_px,
+ r_loc,
+ r_no,
+ r_index);
}
break;
}
@@ -2519,8 +2648,12 @@ struct SnapObjUserData {
short ret;
};
-static void sanp_obj_cb(
- SnapObjectContext *sctx, bool is_obedit, Object *ob, float obmat[4][4], void *data)
+static void sanp_obj_cb(SnapObjectContext *sctx,
+ bool is_obedit,
+ bool use_backface_culling,
+ Object *ob,
+ float obmat[4][4],
+ void *data)
{
struct SnapObjUserData *dt = data;
@@ -2529,6 +2662,7 @@ static void sanp_obj_cb(
ob,
obmat,
is_obedit,
+ use_backface_culling,
/* read/write args */
dt->dist_px,
/* return args */
@@ -2881,7 +3015,8 @@ static short transform_snap_context_project_view3d_mixed_impl(
new_clipplane[3] += 0.01f;
/* Try to snap only to the polygon. */
- elem_test = snap_mesh_polygon(sctx, &snapdata, ob, obmat, &dist_px_tmp, loc, no, &index);
+ elem_test = snap_mesh_polygon(
+ sctx, &snapdata, ob, obmat, params->use_backface_culling, &dist_px_tmp, loc, no, &index);
if (elem_test) {
elem = elem_test;
}
@@ -2904,8 +3039,17 @@ static short transform_snap_context_project_view3d_mixed_impl(
(snap_to_flag & (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE_MIDPOINT |
SCE_SNAP_MODE_EDGE_PERPENDICULAR))) {
snapdata.snap_to_flag = snap_to_flag;
- elem = snap_mesh_edge_verts_mixed(
- sctx, &snapdata, ob, obmat, *dist_px, prev_co, &dist_px_tmp, loc, no, &index);
+ elem = snap_mesh_edge_verts_mixed(sctx,
+ &snapdata,
+ ob,
+ obmat,
+ *dist_px,
+ prev_co,
+ params->use_backface_culling,
+ &dist_px_tmp,
+ loc,
+ no,
+ &index);
}
if (elem & snap_to_flag) {
diff --git a/source/blender/imbuf/intern/indexer.c b/source/blender/imbuf/intern/indexer.c
index 97a0cc85301..46095b7eedc 100644
--- a/source/blender/imbuf/intern/indexer.c
+++ b/source/blender/imbuf/intern/indexer.c
@@ -366,7 +366,7 @@ void IMB_anim_get_fname(struct anim *anim, char *file, int size)
BLI_strncpy(file, fname, size);
}
-static void get_proxy_filename(struct anim *anim,
+static bool get_proxy_filename(struct anim *anim,
IMB_Proxy_Size preview_size,
char *fname,
bool temp)
@@ -393,7 +393,12 @@ static void get_proxy_filename(struct anim *anim,
get_index_dir(anim, index_dir, sizeof(index_dir));
+ if (BLI_path_ncmp(anim->name, index_dir, FILE_MAXDIR) == 0) {
+ return false;
+ }
+
BLI_join_dirfile(fname, FILE_MAXFILE + FILE_MAXDIR, index_dir, proxy_name);
+ return true;
}
static void get_tc_filename(struct anim *anim, IMB_Timecode_Type tc, char *fname)
@@ -1154,8 +1159,9 @@ IndexBuildContext *IMB_anim_index_rebuild_context(struct anim *anim,
IMB_Proxy_Size proxy_size = proxy_sizes[i];
if (proxy_size & proxy_sizes_to_build) {
char filename[FILE_MAX];
- get_proxy_filename(anim, proxy_size, filename, false);
-
+ if (get_proxy_filename(anim, proxy_size, filename, false) == false) {
+ return NULL;
+ }
void **filename_key_p;
if (!BLI_gset_ensure_p_ex(file_list, filename, &filename_key_p)) {
*filename_key_p = BLI_strdup(filename);
@@ -1176,7 +1182,9 @@ IndexBuildContext *IMB_anim_index_rebuild_context(struct anim *anim,
IMB_Proxy_Size proxy_size = proxy_sizes[i];
if (proxy_size & built_proxies) {
char filename[FILE_MAX];
- get_proxy_filename(anim, proxy_size, filename, false);
+ if (get_proxy_filename(anim, proxy_size, filename, false) == false) {
+ return NULL;
+ }
printf("Skipping proxy: %s\n", filename);
}
}
diff --git a/source/blender/makesdna/DNA_brush_defaults.h b/source/blender/makesdna/DNA_brush_defaults.h
index 714c205cda2..b2d4124a348 100644
--- a/source/blender/makesdna/DNA_brush_defaults.h
+++ b/source/blender/makesdna/DNA_brush_defaults.h
@@ -34,6 +34,7 @@
{ \
.blend = 0, \
.flag = (BRUSH_ALPHA_PRESSURE | BRUSH_SPACE | BRUSH_SPACE_ATTEN), \
+ .sampling_flag = (BRUSH_PAINT_ANTIALIASING), \
\
.ob_mode = OB_MODE_ALL_PAINT, \
\
diff --git a/source/blender/makesdna/DNA_brush_types.h b/source/blender/makesdna/DNA_brush_types.h
index fc8763f1519..63fbf576bba 100644
--- a/source/blender/makesdna/DNA_brush_types.h
+++ b/source/blender/makesdna/DNA_brush_types.h
@@ -245,8 +245,9 @@ typedef struct Brush {
float weight;
/** Brush diameter. */
int size;
- /** General purpose flag. */
+ /** General purpose flags. */
int flag;
+ int sampling_flag;
/** Pressure influence for mask. */
int mask_pressure;
/** Jitter the position of the brush. */
@@ -283,7 +284,7 @@ typedef struct Brush {
/** Source for fill tool color gradient application. */
char gradient_fill_mode;
- char _pad;
+ char _pad[5];
/** Projection shape (sphere, circle). */
char falloff_shape;
float falloff_angle;
@@ -435,6 +436,11 @@ typedef enum eBrushFlags {
BRUSH_CURVE = (1u << 31),
} eBrushFlags;
+/* Brush.sampling_flag */
+typedef enum eBrushSamplingFlags {
+ BRUSH_PAINT_ANTIALIASING = (1 << 0),
+} eBrushSamplingFlags;
+
typedef enum {
BRUSH_MASK_PRESSURE_RAMP = (1 << 1),
BRUSH_MASK_PRESSURE_CUTOFF = (1 << 2),
diff --git a/source/blender/makesdna/DNA_gpencil_types.h b/source/blender/makesdna/DNA_gpencil_types.h
index 1435d0a64b4..33dfe66a151 100644
--- a/source/blender/makesdna/DNA_gpencil_types.h
+++ b/source/blender/makesdna/DNA_gpencil_types.h
@@ -447,17 +447,16 @@ typedef struct bGPdata_Runtime {
* - buffer must be initialized before use, but freed after
* whole paint operation is over
*/
- /** Number of elements currently used in cache. */
- short sbuffer_used;
/** Flags for stroke that cache represents. */
short sbuffer_sflag;
+ /** Number of elements currently used in cache. */
+ int sbuffer_used;
/** Number of total elements available in cache. */
- short sbuffer_size;
- char _pad[4];
+ int sbuffer_size;
/** Number of control-points for stroke. */
int tot_cp_points;
- char _pad1_[4];
+ char _pad_[4];
/** Array of control-points for stroke. */
bGPDcontrolpoint *cp_points;
} bGPdata_Runtime;
diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h
index 1ebd19d6af1..81dc91950fb 100644
--- a/source/blender/makesdna/DNA_modifier_types.h
+++ b/source/blender/makesdna/DNA_modifier_types.h
@@ -1119,7 +1119,13 @@ typedef struct SolidifyModifierData {
float offset_fac_vg;
/** Clamp offset based on surrounding geometry. */
float offset_clamp;
- char _pad[4];
+ char mode;
+
+ /** Variables for #MOD_SOLIDIFY_MODE_NONMANIFOLD. */
+ char nonmanifold_offset_mode;
+ char nonmanifold_boundary_mode;
+
+ char _pad;
float crease_inner;
float crease_outer;
float crease_rim;
@@ -1128,6 +1134,7 @@ typedef struct SolidifyModifierData {
short mat_ofs_rim;
} SolidifyModifierData;
+/** #SolidifyModifierData.flag */
enum {
MOD_SOLIDIFY_RIM = (1 << 0),
MOD_SOLIDIFY_EVEN = (1 << 1),
@@ -1138,6 +1145,27 @@ enum {
#endif
MOD_SOLIDIFY_FLIP = (1 << 5),
MOD_SOLIDIFY_NOSHELL = (1 << 6),
+ MOD_SOLIDIFY_OFFSET_ANGLE_CLAMP = (1 << 7),
+};
+
+/** #SolidifyModifierData.mode */
+enum {
+ MOD_SOLIDIFY_MODE_EXTRUDE = 0,
+ MOD_SOLIDIFY_MODE_NONMANIFOLD = 1,
+};
+
+/** #SolidifyModifierData.nonmanifold_offset_mode */
+enum {
+ MOD_SOLIDIFY_NONMANIFOLD_OFFSET_MODE_FIXED = 0,
+ MOD_SOLIDIFY_NONMANIFOLD_OFFSET_MODE_EVEN = 1,
+ MOD_SOLIDIFY_NONMANIFOLD_OFFSET_MODE_CONSTRAINTS = 2,
+};
+
+/** #SolidifyModifierData.nonmanifold_boundary_mode */
+enum {
+ MOD_SOLIDIFY_NONMANIFOLD_BOUNDARY_MODE_NONE = 0,
+ MOD_SOLIDIFY_NONMANIFOLD_BOUNDARY_MODE_ROUND = 1,
+ MOD_SOLIDIFY_NONMANIFOLD_BOUNDARY_MODE_FLAT = 2,
};
typedef struct ScrewModifierData {
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index 3794508d5a2..2ca9e3b2ef7 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -2035,6 +2035,7 @@ enum {
#define SCE_SNAP_PROJECT (1 << 3)
#define SCE_SNAP_NO_SELF (1 << 4)
#define SCE_SNAP_ABS_GRID (1 << 5)
+#define SCE_SNAP_BACKFACE_CULLING (1 << 6)
/* ToolSettings.snap_target */
#define SCE_SNAP_TARGET_CLOSEST 0
diff --git a/source/blender/makesdna/DNA_screen_types.h b/source/blender/makesdna/DNA_screen_types.h
index bf491e2eaea..ec42e9bd04f 100644
--- a/source/blender/makesdna/DNA_screen_types.h
+++ b/source/blender/makesdna/DNA_screen_types.h
@@ -461,9 +461,10 @@ enum {
/** Update size of regions within the area. */
AREA_FLAG_REGION_SIZE_UPDATE = (1 << 3),
AREA_FLAG_ACTIVE_TOOL_UPDATE = (1 << 4),
+
// AREA_FLAG_UNUSED_5 = (1 << 5),
- /** Used to check if we should switch back to prevspace (of a different type). */
- AREA_FLAG_TEMP_TYPE = (1 << 6),
+ AREA_FLAG_UNUSED_6 = (1 << 6), /* cleared */
+
/**
* For temporary full-screens (file browser, image editor render)
* that are opened above user set full-screens.
diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h
index 0f957a946d9..82f6da8bb46 100644
--- a/source/blender/makesdna/DNA_space_types.h
+++ b/source/blender/makesdna/DNA_space_types.h
@@ -79,6 +79,22 @@ typedef struct SpaceLink {
char _pad0[6];
} SpaceLink;
+/* SpaceLink.link_flag */
+enum {
+ /**
+ * The space is not a regular one opened through the editor menu (for example) but spawned by an
+ * operator to fulfill some task and then disappear again. Can typically be cancelled using Esc,
+ * but that is handled on the editor level. */
+ SPACE_FLAG_TYPE_TEMPORARY = (1 << 0),
+ /**
+ * Used to mark a space as active but "overlapped" by temporary fullscreen spaces. Without this
+ * we wouldn't be able to restore the correct active space after closing temp fullscreens
+ * reliably if the same space type is opened twice in a fullscreen stack (see T19296). We don't
+ * actually open the same space twice, we have to pretend it is by managing area order carefully.
+ */
+ SPACE_FLAG_TYPE_WAS_ACTIVE = (1 << 1),
+};
+
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c
index 99c1bdfdbee..a392e4c080f 100644
--- a/source/blender/makesrna/intern/rna_brush.c
+++ b/source/blender/makesrna/intern/rna_brush.c
@@ -2007,6 +2007,11 @@ static void rna_def_brush(BlenderRNA *brna)
"Apply the maximum grab strength to the active vertex instead of the cursor location");
RNA_def_property_update(prop, 0, "rna_Brush_update");
+ prop = RNA_def_property(srna, "use_paint_antialiasing", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "sampling_flag", BRUSH_PAINT_ANTIALIASING);
+ RNA_def_property_ui_text(prop, "Antialasing", "Smooths the edges of the strokes");
+ RNA_def_property_update(prop, 0, "rna_Brush_update");
+
prop = RNA_def_property(srna, "use_pressure_strength", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", BRUSH_ALPHA_PRESSURE);
RNA_def_property_ui_icon(prop, ICON_STYLUS_PRESSURE, 0);
diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c
index cc01554f73a..5890c3fe8a2 100644
--- a/source/blender/makesrna/intern/rna_mesh.c
+++ b/source/blender/makesrna/intern/rna_mesh.c
@@ -3006,17 +3006,17 @@ static void rna_def_mesh(BlenderRNA *brna)
"generating triangles. A value greater than 0 disables Fix Poles");
RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
- prop = RNA_def_property(srna, "remesh_smooth_normals", PROP_BOOLEAN, PROP_NONE);
+ prop = RNA_def_property(srna, "use_remesh_smooth_normals", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", ME_REMESH_SMOOTH_NORMALS);
RNA_def_property_ui_text(prop, "Smooth Normals", "Smooth the normals of the remesher result");
RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
- prop = RNA_def_property(srna, "remesh_fix_poles", PROP_BOOLEAN, PROP_NONE);
+ prop = RNA_def_property(srna, "use_remesh_fix_poles", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", ME_REMESH_FIX_POLES);
RNA_def_property_ui_text(prop, "Fix Poles", "Produces less poles and a better topology flow");
RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
- prop = RNA_def_property(srna, "remesh_preserve_volume", PROP_BOOLEAN, PROP_NONE);
+ prop = RNA_def_property(srna, "use_remesh_preserve_volume", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", ME_REMESH_REPROJECT_VOLUME);
RNA_def_property_ui_text(
prop,
@@ -3024,7 +3024,7 @@ static void rna_def_mesh(BlenderRNA *brna)
"Projects the mesh to preserve the volume and details of the original mesh");
RNA_def_property_update(prop, 0, "rna_Mesh_update_draw");
- prop = RNA_def_property(srna, "remesh_preserve_paint_mask", PROP_BOOLEAN, PROP_NONE);
+ prop = RNA_def_property(srna, "use_remesh_preserve_paint_mask", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", ME_REMESH_REPROJECT_PAINT_MASK);
RNA_def_property_boolean_default(prop, false);
RNA_def_property_ui_text(prop, "Preserve Paint Mask", "Keep the current mask on the new mesh");
diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c
index d8387cf4736..2fee003fd75 100644
--- a/source/blender/makesrna/intern/rna_modifier.c
+++ b/source/blender/makesrna/intern/rna_modifier.c
@@ -4071,16 +4071,71 @@ static void rna_def_modifier_surface(BlenderRNA *brna)
static void rna_def_modifier_solidify(BlenderRNA *brna)
{
+ static const EnumPropertyItem mode_items[] = {
+ {MOD_SOLIDIFY_MODE_EXTRUDE,
+ "EXTRUDE",
+ 0,
+ "Simple",
+ "Output a solidified version of a mesh by simple extrusion"},
+ {MOD_SOLIDIFY_MODE_NONMANIFOLD,
+ "NON_MANIFOLD",
+ 0,
+ "Complex",
+ "Output a manifold mesh even if the base mesh is non-manifold, "
+ "where edges have 3 or more connecting faces."
+ "This method is slower"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ static const EnumPropertyItem nonmanifold_thickness_mode_items[] = {
+ {MOD_SOLIDIFY_NONMANIFOLD_OFFSET_MODE_FIXED,
+ "FIXED",
+ 0,
+ "Fixed",
+ "Most basic thickness calculation"},
+ {MOD_SOLIDIFY_NONMANIFOLD_OFFSET_MODE_EVEN,
+ "EVEN",
+ 0,
+ "Even",
+ "Even thickness calculation which takes the angle between faces into account"},
+ {MOD_SOLIDIFY_NONMANIFOLD_OFFSET_MODE_CONSTRAINTS,
+ "CONSTRAINTS",
+ 0,
+ "Constraints",
+ "Thickness calculation using constraints, most advanced"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ static const EnumPropertyItem nonmanifold_boundary_mode_items[] = {
+ {MOD_SOLIDIFY_NONMANIFOLD_BOUNDARY_MODE_NONE, "NONE", 0, "None", "No shape correction"},
+ {MOD_SOLIDIFY_NONMANIFOLD_BOUNDARY_MODE_ROUND,
+ "ROUND",
+ 0,
+ "Round",
+ "Round open perimeter shape"},
+ {MOD_SOLIDIFY_NONMANIFOLD_BOUNDARY_MODE_FLAT,
+ "FLAT",
+ 0,
+ "Flat",
+ "Flat open perimeter shape"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
StructRNA *srna;
PropertyRNA *prop;
srna = RNA_def_struct(brna, "SolidifyModifier", "Modifier");
- RNA_def_struct_ui_text(srna,
- "Solidify Modifier",
- "Create a solid skin by extruding, compensating for sharp angles");
+ RNA_def_struct_ui_text(
+ srna, "Solidify Modifier", "Create a solid skin, compensating for sharp angles");
RNA_def_struct_sdna(srna, "SolidifyModifierData");
RNA_def_struct_ui_icon(srna, ICON_MOD_SOLIDIFY);
+ prop = RNA_def_property(srna, "solidify_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "mode");
+ RNA_def_property_enum_items(prop, mode_items);
+ RNA_def_property_ui_text(prop, "Mode", "Selects the used algorithm");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
prop = RNA_def_property(srna, "thickness", PROP_FLOAT, PROP_DISTANCE);
RNA_def_property_float_sdna(prop, NULL, "offset");
RNA_def_property_range(prop, -FLT_MAX, FLT_MAX);
@@ -4095,6 +4150,11 @@ static void rna_def_modifier_solidify(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Clamp", "Offset clamp based on geometry scale");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+ prop = RNA_def_property(srna, "use_thickness_angle_clamp", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_SOLIDIFY_OFFSET_ANGLE_CLAMP);
+ RNA_def_property_ui_text(prop, "Angle Clamp", "Clamp thickness based on angles");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
prop = RNA_def_property(srna, "thickness_vertex_group", PROP_FLOAT, PROP_FACTOR);
RNA_def_property_float_sdna(prop, NULL, "offset_fac_vg");
RNA_def_property_range(prop, 0.0, 1.0);
@@ -4188,6 +4248,18 @@ static void rna_def_modifier_solidify(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, NULL, "flag", MOD_SOLIDIFY_NOSHELL);
RNA_def_property_ui_text(prop, "Only Rim", "Only add the rim to the original data");
RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ /* Settings for #MOD_SOLIDIFY_MODE_NONMANIFOLD */
+ prop = RNA_def_property(srna, "nonmanifold_thickness_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "nonmanifold_offset_mode");
+ RNA_def_property_enum_items(prop, nonmanifold_thickness_mode_items);
+ RNA_def_property_ui_text(prop, "Thickness Mode", "Selects the used thickness algorithm");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
+
+ prop = RNA_def_property(srna, "nonmanifold_boundary_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, nonmanifold_boundary_mode_items);
+ RNA_def_property_ui_text(prop, "Boundary Shape", "Selects the boundary adjustment algorithm");
+ RNA_def_property_update(prop, 0, "rna_Modifier_update");
}
static void rna_def_modifier_screw(BlenderRNA *brna)
diff --git a/source/blender/makesrna/intern/rna_packedfile.c b/source/blender/makesrna/intern/rna_packedfile.c
index dda1c637f39..8319612ea91 100644
--- a/source/blender/makesrna/intern/rna_packedfile.c
+++ b/source/blender/makesrna/intern/rna_packedfile.c
@@ -32,6 +32,7 @@
#include "rna_internal.h"
const EnumPropertyItem rna_enum_unpack_method_items[] = {
+ {PF_REMOVE, "REMOVE", 0, "Remove Pack", ""},
{PF_USE_LOCAL, "USE_LOCAL", 0, "Use Local File", ""},
{PF_WRITE_LOCAL, "WRITE_LOCAL", 0, "Write Local File (overwrite existing)", ""},
{PF_USE_ORIGINAL, "USE_ORIGINAL", 0, "Use Original File", ""},
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index f1e20b32ddc..b9bc7b2bbf5 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -3035,6 +3035,11 @@ static void rna_def_tool_settings(BlenderRNA *brna)
"Project individual elements on the surface of other objects");
RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* header redraw */
+ prop = RNA_def_property(srna, "use_snap_backface_culling", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_sdna(prop, NULL, "snap_flag", SCE_SNAP_BACKFACE_CULLING);
+ RNA_def_property_ui_text(prop, "Backface Culling", "Exclude back facing geometry from snapping");
+ RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); /* header redraw */
+
prop = RNA_def_property(srna, "use_snap_self", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_negative_sdna(prop, NULL, "snap_flag", SCE_SNAP_NO_SELF);
RNA_def_property_ui_text(prop, "Project onto Self", "Snap onto itself (Edit Mode Only)");
diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c
index 18985d41551..2c5f93e28ed 100644
--- a/source/blender/makesrna/intern/rna_sequencer.c
+++ b/source/blender/makesrna/intern/rna_sequencer.c
@@ -2699,16 +2699,17 @@ static void rna_def_gaussian_blur(StructRNA *srna)
static void rna_def_text(StructRNA *srna)
{
+ /* Avoid text icons because they imply this aligns within a frame, see: T71082 */
static const EnumPropertyItem text_align_x_items[] = {
- {SEQ_TEXT_ALIGN_X_LEFT, "LEFT", ICON_ALIGN_LEFT, "Left", ""},
- {SEQ_TEXT_ALIGN_X_CENTER, "CENTER", ICON_ALIGN_CENTER, "Center", ""},
- {SEQ_TEXT_ALIGN_X_RIGHT, "RIGHT", ICON_ALIGN_RIGHT, "Right", ""},
+ {SEQ_TEXT_ALIGN_X_LEFT, "LEFT", 0, "Left", ""},
+ {SEQ_TEXT_ALIGN_X_CENTER, "CENTER", 0, "Center", ""},
+ {SEQ_TEXT_ALIGN_X_RIGHT, "RIGHT", 0, "Right", ""},
{0, NULL, 0, NULL, NULL},
};
static const EnumPropertyItem text_align_y_items[] = {
- {SEQ_TEXT_ALIGN_Y_TOP, "TOP", ICON_ALIGN_TOP, "Top", ""},
- {SEQ_TEXT_ALIGN_Y_CENTER, "CENTER", ICON_ALIGN_MIDDLE, "Center", ""},
- {SEQ_TEXT_ALIGN_Y_BOTTOM, "BOTTOM", ICON_ALIGN_BOTTOM, "Bottom", ""},
+ {SEQ_TEXT_ALIGN_Y_TOP, "TOP", 0, "Top", ""},
+ {SEQ_TEXT_ALIGN_Y_CENTER, "CENTER", 0, "Center", ""},
+ {SEQ_TEXT_ALIGN_Y_BOTTOM, "BOTTOM", 0, "Bottom", ""},
{0, NULL, 0, NULL, NULL},
};
@@ -2765,7 +2766,7 @@ static void rna_def_text(StructRNA *srna)
RNA_def_property_enum_sdna(prop, NULL, "align");
RNA_def_property_enum_items(prop, text_align_x_items);
RNA_def_property_ui_text(
- prop, "Align X", "Align the text along the X axis, relative to the text midpoint");
+ prop, "Align X", "Align the text along the X axis, relative to the text bounds");
RNA_def_property_update(
prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update");
@@ -2773,7 +2774,7 @@ static void rna_def_text(StructRNA *srna)
RNA_def_property_enum_sdna(prop, NULL, "align_y");
RNA_def_property_enum_items(prop, text_align_y_items);
RNA_def_property_ui_text(
- prop, "Align Y", "Align the image along the Y axis, relative to the text midpoint");
+ prop, "Align Y", "Align the text along the Y axis, relative to the text bounds");
RNA_def_property_update(
prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_preprocessed_update");
diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c
index 3df678358d8..9ecfc7f675f 100644
--- a/source/blender/makesrna/intern/rna_userdef.c
+++ b/source/blender/makesrna/intern/rna_userdef.c
@@ -2979,6 +2979,12 @@ static void rna_def_userdef_theme_space_seq(BlenderRNA *brna)
RNA_def_property_array(prop, 3);
RNA_def_property_ui_text(prop, "Metadata Text", "");
RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
+
+ prop = RNA_def_property(srna, "preview_range", PROP_FLOAT, PROP_COLOR_GAMMA);
+ RNA_def_property_float_sdna(prop, NULL, "anim_preview_range");
+ RNA_def_property_array(prop, 4);
+ RNA_def_property_ui_text(prop, "Preview Range", "Color of preview range overlay");
+ RNA_def_property_update(prop, 0, "rna_userdef_theme_update");
}
static void rna_def_userdef_theme_space_action(BlenderRNA *brna)
diff --git a/source/blender/modifiers/CMakeLists.txt b/source/blender/modifiers/CMakeLists.txt
index 569900e7872..045d07b69b1 100644
--- a/source/blender/modifiers/CMakeLists.txt
+++ b/source/blender/modifiers/CMakeLists.txt
@@ -94,6 +94,8 @@ set(SRC
intern/MOD_smooth.c
intern/MOD_softbody.c
intern/MOD_solidify.c
+ intern/MOD_solidify_extrude.c
+ intern/MOD_solidify_nonmanifold.c
intern/MOD_subsurf.c
intern/MOD_surface.c
intern/MOD_surfacedeform.c
@@ -113,6 +115,7 @@ set(SRC
MOD_modifiertypes.h
intern/MOD_fluidsim_util.h
intern/MOD_meshcache_util.h
+ intern/MOD_solidify_util.h
intern/MOD_util.h
intern/MOD_weightvg_util.h
)
diff --git a/source/blender/modifiers/intern/MOD_solidify.c b/source/blender/modifiers/intern/MOD_solidify.c
index 292e659fe03..8ea0a602b65 100644
--- a/source/blender/modifiers/intern/MOD_solidify.c
+++ b/source/blender/modifiers/intern/MOD_solidify.c
@@ -23,142 +23,25 @@
#include "BLI_utildefines.h"
-#include "BLI_bitmap.h"
-#include "BLI_math.h"
-#include "BLI_utildefines_stack.h"
-
#include "DNA_mesh_types.h"
-#include "DNA_meshdata_types.h"
-
-#include "MEM_guardedalloc.h"
-#include "BKE_mesh.h"
#include "BKE_particle.h"
-#include "BKE_deform.h"
#include "MOD_modifiertypes.h"
-#include "MOD_util.h"
+
+#include "MOD_solidify_util.h"
#ifdef __GNUC__
# pragma GCC diagnostic error "-Wsign-conversion"
#endif
-/* skip shell thickness for non-manifold edges, see [#35710] */
-#define USE_NONMANIFOLD_WORKAROUND
-
-/* *** derived mesh high quality normal calculation function *** */
-/* could be exposed for other functions to use */
-
-typedef struct EdgeFaceRef {
- int p1; /* init as -1 */
- int p2;
-} EdgeFaceRef;
-
-BLI_INLINE bool edgeref_is_init(const EdgeFaceRef *edge_ref)
+static bool dependsOnNormals(ModifierData *md)
{
- return !((edge_ref->p1 == 0) && (edge_ref->p2 == 0));
-}
-
-/**
- * \param dm: Mesh to calculate normals for.
- * \param face_nors: Precalculated face normals.
- * \param r_vert_nors: Return vert normals.
- */
-static void mesh_calc_hq_normal(Mesh *mesh, float (*poly_nors)[3], float (*r_vert_nors)[3])
-{
- int i, numVerts, numEdges, numPolys;
- MPoly *mpoly, *mp;
- MLoop *mloop, *ml;
- MEdge *medge, *ed;
- MVert *mvert, *mv;
-
- numVerts = mesh->totvert;
- numEdges = mesh->totedge;
- numPolys = mesh->totpoly;
- mpoly = mesh->mpoly;
- medge = mesh->medge;
- mvert = mesh->mvert;
- mloop = mesh->mloop;
-
- /* we don't want to overwrite any referenced layers */
-
- /* Doesn't work here! */
-#if 0
- mv = CustomData_duplicate_referenced_layer(&dm->vertData, CD_MVERT, numVerts);
- cddm->mvert = mv;
-#endif
-
- mv = mvert;
- mp = mpoly;
-
- {
- EdgeFaceRef *edge_ref_array = MEM_calloc_arrayN(
- (size_t)numEdges, sizeof(EdgeFaceRef), "Edge Connectivity");
- EdgeFaceRef *edge_ref;
- float edge_normal[3];
-
- /* Add an edge reference if it's not there, pointing back to the face index. */
- for (i = 0; i < numPolys; i++, mp++) {
- int j;
-
- ml = mloop + mp->loopstart;
-
- for (j = 0; j < mp->totloop; j++, ml++) {
- /* --- add edge ref to face --- */
- edge_ref = &edge_ref_array[ml->e];
- if (!edgeref_is_init(edge_ref)) {
- edge_ref->p1 = i;
- edge_ref->p2 = -1;
- }
- else if ((edge_ref->p1 != -1) && (edge_ref->p2 == -1)) {
- edge_ref->p2 = i;
- }
- else {
- /* 3+ faces using an edge, we can't handle this usefully */
- edge_ref->p1 = edge_ref->p2 = -1;
-#ifdef USE_NONMANIFOLD_WORKAROUND
- medge[ml->e].flag |= ME_EDGE_TMP_TAG;
-#endif
- }
- /* --- done --- */
- }
- }
-
- for (i = 0, ed = medge, edge_ref = edge_ref_array; i < numEdges; i++, ed++, edge_ref++) {
- /* Get the edge vert indices, and edge value (the face indices that use it) */
-
- if (edgeref_is_init(edge_ref) && (edge_ref->p1 != -1)) {
- if (edge_ref->p2 != -1) {
- /* We have 2 faces using this edge, calculate the edges normal
- * using the angle between the 2 faces as a weighting */
-#if 0
- add_v3_v3v3(edge_normal, face_nors[edge_ref->f1], face_nors[edge_ref->f2]);
- normalize_v3_length(
- edge_normal,
- angle_normalized_v3v3(face_nors[edge_ref->f1], face_nors[edge_ref->f2]));
-#else
- mid_v3_v3v3_angle_weighted(
- edge_normal, poly_nors[edge_ref->p1], poly_nors[edge_ref->p2]);
-#endif
- }
- else {
- /* only one face attached to that edge */
- /* an edge without another attached- the weight on this is undefined */
- copy_v3_v3(edge_normal, poly_nors[edge_ref->p1]);
- }
- add_v3_v3(r_vert_nors[ed->v1], edge_normal);
- add_v3_v3(r_vert_nors[ed->v2], edge_normal);
- }
- }
- MEM_freeN(edge_ref_array);
- }
-
- /* normalize vertex normals and assign */
- for (i = 0; i < numVerts; i++, mv++) {
- if (normalize_v3(r_vert_nors[i]) == 0.0f) {
- normal_short_to_float_v3(r_vert_nors[i], mv->no);
- }
- }
+ const SolidifyModifierData *smd = (SolidifyModifierData *)md;
+ /* even when we calculate our own normals,
+ * the vertex normals are used as a fallback
+ * if manifold is enabled vertex normals are not used */
+ return smd->mode == MOD_SOLIDIFY_MODE_EXTRUDE;
}
static void initData(ModifierData *md)
@@ -167,6 +50,9 @@ static void initData(ModifierData *md)
smd->offset = 0.01f;
smd->offset_fac = -1.0f;
smd->flag = MOD_SOLIDIFY_RIM;
+ smd->mode = MOD_SOLIDIFY_MODE_EXTRUDE;
+ smd->nonmanifold_offset_mode = MOD_SOLIDIFY_NONMANIFOLD_OFFSET_MODE_CONSTRAINTS;
+ smd->nonmanifold_boundary_mode = MOD_SOLIDIFY_NONMANIFOLD_BOUNDARY_MODE_NONE;
}
static void requiredDataMask(Object *UNUSED(ob),
@@ -181,803 +67,16 @@ static void requiredDataMask(Object *UNUSED(ob),
}
}
-/* specific function for solidify - define locally */
-BLI_INLINE void madd_v3v3short_fl(float r[3], const short a[3], const float f)
-{
- r[0] += (float)a[0] * f;
- r[1] += (float)a[1] * f;
- r[2] += (float)a[2] * f;
-}
-
static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
{
- Mesh *result;
const SolidifyModifierData *smd = (SolidifyModifierData *)md;
-
- MVert *mv, *mvert, *orig_mvert;
- MEdge *ed, *medge, *orig_medge;
- MLoop *ml, *mloop, *orig_mloop;
- MPoly *mp, *mpoly, *orig_mpoly;
- const uint numVerts = (uint)mesh->totvert;
- const uint numEdges = (uint)mesh->totedge;
- const uint numPolys = (uint)mesh->totpoly;
- const uint numLoops = (uint)mesh->totloop;
- uint newLoops = 0, newPolys = 0, newEdges = 0, newVerts = 0, rimVerts = 0;
-
- /* only use material offsets if we have 2 or more materials */
- const short mat_nr_max = ctx->object->totcol > 1 ? ctx->object->totcol - 1 : 0;
- const short mat_ofs = mat_nr_max ? smd->mat_ofs : 0;
- const short mat_ofs_rim = mat_nr_max ? smd->mat_ofs_rim : 0;
-
- /* use for edges */
- /* over-alloc new_vert_arr, old_vert_arr */
- uint *new_vert_arr = NULL;
- STACK_DECLARE(new_vert_arr);
-
- uint *new_edge_arr = NULL;
- STACK_DECLARE(new_edge_arr);
-
- uint *old_vert_arr = MEM_calloc_arrayN(
- numVerts, sizeof(*old_vert_arr), "old_vert_arr in solidify");
-
- uint *edge_users = NULL;
- char *edge_order = NULL;
-
- float(*vert_nors)[3] = NULL;
- float(*poly_nors)[3] = NULL;
-
- const bool need_poly_normals = (smd->flag & MOD_SOLIDIFY_NORMAL_CALC) ||
- (smd->flag & MOD_SOLIDIFY_EVEN);
-
- const float ofs_orig = -(((-smd->offset_fac + 1.0f) * 0.5f) * smd->offset);
- const float ofs_new = smd->offset + ofs_orig;
- const float offset_fac_vg = smd->offset_fac_vg;
- const float offset_fac_vg_inv = 1.0f - smd->offset_fac_vg;
- const bool do_flip = (smd->flag & MOD_SOLIDIFY_FLIP) != 0;
- const bool do_clamp = (smd->offset_clamp != 0.0f);
- const bool do_shell = ((smd->flag & MOD_SOLIDIFY_RIM) && (smd->flag & MOD_SOLIDIFY_NOSHELL)) ==
- 0;
-
- /* weights */
- MDeformVert *dvert;
- const bool defgrp_invert = (smd->flag & MOD_SOLIDIFY_VGROUP_INV) != 0;
- int defgrp_index;
-
- /* array size is doubled in case of using a shell */
- const uint stride = do_shell ? 2 : 1;
-
- MOD_get_vgroup(ctx->object, mesh, smd->defgrp_name, &dvert, &defgrp_index);
-
- orig_mvert = mesh->mvert;
- orig_medge = mesh->medge;
- orig_mloop = mesh->mloop;
- orig_mpoly = mesh->mpoly;
-
- if (need_poly_normals) {
- /* calculate only face normals */
- poly_nors = MEM_malloc_arrayN(numPolys, sizeof(*poly_nors), __func__);
- BKE_mesh_calc_normals_poly(orig_mvert,
- NULL,
- (int)numVerts,
- orig_mloop,
- orig_mpoly,
- (int)numLoops,
- (int)numPolys,
- poly_nors,
- true);
- }
-
- STACK_INIT(new_vert_arr, numVerts * 2);
- STACK_INIT(new_edge_arr, numEdges * 2);
-
- if (smd->flag & MOD_SOLIDIFY_RIM) {
- BLI_bitmap *orig_mvert_tag = BLI_BITMAP_NEW(numVerts, __func__);
- uint eidx;
- uint i;
-
-#define INVALID_UNUSED ((uint)-1)
-#define INVALID_PAIR ((uint)-2)
-
- new_vert_arr = MEM_malloc_arrayN(numVerts, 2 * sizeof(*new_vert_arr), __func__);
- new_edge_arr = MEM_malloc_arrayN(((numEdges * 2) + numVerts), sizeof(*new_edge_arr), __func__);
-
- edge_users = MEM_malloc_arrayN(numEdges, sizeof(*edge_users), "solid_mod edges");
- edge_order = MEM_malloc_arrayN(numEdges, sizeof(*edge_order), "solid_mod eorder");
-
- /* save doing 2 loops here... */
-#if 0
- copy_vn_i(edge_users, numEdges, INVALID_UNUSED);
-#endif
-
- for (eidx = 0, ed = orig_medge; eidx < numEdges; eidx++, ed++) {
- edge_users[eidx] = INVALID_UNUSED;
- }
-
- for (i = 0, mp = orig_mpoly; i < numPolys; i++, mp++) {
- MLoop *ml_prev;
- int j;
-
- ml = orig_mloop + mp->loopstart;
- ml_prev = ml + (mp->totloop - 1);
-
- for (j = 0; j < mp->totloop; j++, ml++) {
- /* add edge user */
- eidx = ml_prev->e;
- if (edge_users[eidx] == INVALID_UNUSED) {
- ed = orig_medge + eidx;
- BLI_assert(ELEM(ml_prev->v, ed->v1, ed->v2) && ELEM(ml->v, ed->v1, ed->v2));
- edge_users[eidx] = (ml_prev->v > ml->v) == (ed->v1 < ed->v2) ? i : (i + numPolys);
- edge_order[eidx] = j;
- }
- else {
- edge_users[eidx] = INVALID_PAIR;
- }
- ml_prev = ml;
- }
- }
-
- for (eidx = 0, ed = orig_medge; eidx < numEdges; eidx++, ed++) {
- if (!ELEM(edge_users[eidx], INVALID_UNUSED, INVALID_PAIR)) {
- BLI_BITMAP_ENABLE(orig_mvert_tag, ed->v1);
- BLI_BITMAP_ENABLE(orig_mvert_tag, ed->v2);
- STACK_PUSH(new_edge_arr, eidx);
- newPolys++;
- newLoops += 4;
- }
- }
-
- for (i = 0; i < numVerts; i++) {
- if (BLI_BITMAP_TEST(orig_mvert_tag, i)) {
- old_vert_arr[i] = STACK_SIZE(new_vert_arr);
- STACK_PUSH(new_vert_arr, i);
- rimVerts++;
- }
- else {
- old_vert_arr[i] = INVALID_UNUSED;
- }
- }
-
- MEM_freeN(orig_mvert_tag);
- }
-
- if (do_shell == false) {
- /* only add rim vertices */
- newVerts = rimVerts;
- /* each extruded face needs an opposite edge */
- newEdges = newPolys;
- }
- else {
- /* (stride == 2) in this case, so no need to add newVerts/newEdges */
- BLI_assert(newVerts == 0);
- BLI_assert(newEdges == 0);
- }
-
- if (smd->flag & MOD_SOLIDIFY_NORMAL_CALC) {
- vert_nors = MEM_calloc_arrayN(numVerts, 3 * sizeof(float), "mod_solid_vno_hq");
- mesh_calc_hq_normal(mesh, poly_nors, vert_nors);
- }
-
- result = BKE_mesh_new_nomain_from_template(mesh,
- (int)((numVerts * stride) + newVerts),
- (int)((numEdges * stride) + newEdges + rimVerts),
- 0,
- (int)((numLoops * stride) + newLoops),
- (int)((numPolys * stride) + newPolys));
-
- mpoly = result->mpoly;
- mloop = result->mloop;
- medge = result->medge;
- mvert = result->mvert;
-
- if (do_shell) {
- CustomData_copy_data(&mesh->vdata, &result->vdata, 0, 0, (int)numVerts);
- CustomData_copy_data(&mesh->vdata, &result->vdata, 0, (int)numVerts, (int)numVerts);
-
- CustomData_copy_data(&mesh->edata, &result->edata, 0, 0, (int)numEdges);
- CustomData_copy_data(&mesh->edata, &result->edata, 0, (int)numEdges, (int)numEdges);
-
- CustomData_copy_data(&mesh->ldata, &result->ldata, 0, 0, (int)numLoops);
- /* DO NOT copy here the 'copied' part of loop data, we want to reverse loops
- * (so that winding of copied face get reversed, so that normals get reversed
- * and point in expected direction...).
- * If we also copy data here, then this data get overwritten
- * (and allocated memory becomes memleak). */
-
- CustomData_copy_data(&mesh->pdata, &result->pdata, 0, 0, (int)numPolys);
- CustomData_copy_data(&mesh->pdata, &result->pdata, 0, (int)numPolys, (int)numPolys);
+ if (smd->mode == MOD_SOLIDIFY_MODE_EXTRUDE) {
+ return MOD_solidify_extrude_applyModifier(md, ctx, mesh);
}
- else {
- int i, j;
- CustomData_copy_data(&mesh->vdata, &result->vdata, 0, 0, (int)numVerts);
- for (i = 0, j = (int)numVerts; i < numVerts; i++) {
- if (old_vert_arr[i] != INVALID_UNUSED) {
- CustomData_copy_data(&mesh->vdata, &result->vdata, i, j, 1);
- j++;
- }
- }
-
- CustomData_copy_data(&mesh->edata, &result->edata, 0, 0, (int)numEdges);
-
- for (i = 0, j = (int)numEdges; i < numEdges; i++) {
- if (!ELEM(edge_users[i], INVALID_UNUSED, INVALID_PAIR)) {
- MEdge *ed_src, *ed_dst;
- CustomData_copy_data(&mesh->edata, &result->edata, i, j, 1);
-
- ed_src = &medge[i];
- ed_dst = &medge[j];
- ed_dst->v1 = old_vert_arr[ed_src->v1] + numVerts;
- ed_dst->v2 = old_vert_arr[ed_src->v2] + numVerts;
- j++;
- }
- }
-
- /* will be created later */
- CustomData_copy_data(&mesh->ldata, &result->ldata, 0, 0, (int)numLoops);
- CustomData_copy_data(&mesh->pdata, &result->pdata, 0, 0, (int)numPolys);
+ else if (smd->mode == MOD_SOLIDIFY_MODE_NONMANIFOLD) {
+ return MOD_solidify_nonmanifold_applyModifier(md, ctx, mesh);
}
-
-#undef INVALID_UNUSED
-#undef INVALID_PAIR
-
- /* initializes: (i_end, do_shell_align, mv) */
-#define INIT_VERT_ARRAY_OFFSETS(test) \
- if (((ofs_new >= ofs_orig) == do_flip) == test) { \
- i_end = numVerts; \
- do_shell_align = true; \
- mv = mvert; \
- } \
- else { \
- if (do_shell) { \
- i_end = numVerts; \
- do_shell_align = true; \
- } \
- else { \
- i_end = newVerts; \
- do_shell_align = false; \
- } \
- mv = &mvert[numVerts]; \
- } \
- (void)0
-
- /* flip normals */
-
- if (do_shell) {
- uint i;
-
- mp = mpoly + numPolys;
- for (i = 0; i < mesh->totpoly; i++, mp++) {
- const int loop_end = mp->totloop - 1;
- MLoop *ml2;
- uint e;
- int j;
-
- /* reverses the loop direction (MLoop.v as well as custom-data)
- * MLoop.e also needs to be corrected too, done in a separate loop below. */
- ml2 = mloop + mp->loopstart + mesh->totloop;
-#if 0
- for (j = 0; j < mp->totloop; j++) {
- CustomData_copy_data(&mesh->ldata,
- &result->ldata,
- mp->loopstart + j,
- mp->loopstart + (loop_end - j) + mesh->totloop,
- 1);
- }
-#else
- /* slightly more involved, keep the first vertex the same for the copy,
- * ensures the diagonals in the new face match the original. */
- j = 0;
- for (int j_prev = loop_end; j < mp->totloop; j_prev = j++) {
- CustomData_copy_data(&mesh->ldata,
- &result->ldata,
- mp->loopstart + j,
- mp->loopstart + (loop_end - j_prev) + mesh->totloop,
- 1);
- }
-#endif
-
- if (mat_ofs) {
- mp->mat_nr += mat_ofs;
- CLAMP(mp->mat_nr, 0, mat_nr_max);
- }
-
- e = ml2[0].e;
- for (j = 0; j < loop_end; j++) {
- ml2[j].e = ml2[j + 1].e;
- }
- ml2[loop_end].e = e;
-
- mp->loopstart += mesh->totloop;
-
- for (j = 0; j < mp->totloop; j++) {
- ml2[j].e += numEdges;
- ml2[j].v += numVerts;
- }
- }
-
- for (i = 0, ed = medge + numEdges; i < numEdges; i++, ed++) {
- ed->v1 += numVerts;
- ed->v2 += numVerts;
- }
- }
-
- /* note, copied vertex layers don't have flipped normals yet. do this after applying offset */
- if ((smd->flag & MOD_SOLIDIFY_EVEN) == 0) {
- /* no even thickness, very simple */
- float scalar_short;
- float scalar_short_vgroup;
-
- /* for clamping */
- float *vert_lens = NULL;
- const float offset = fabsf(smd->offset) * smd->offset_clamp;
- const float offset_sq = offset * offset;
-
- if (do_clamp) {
- uint i;
-
- vert_lens = MEM_malloc_arrayN(numVerts, sizeof(float), "vert_lens");
- copy_vn_fl(vert_lens, (int)numVerts, FLT_MAX);
- for (i = 0; i < numEdges; i++) {
- const float ed_len_sq = len_squared_v3v3(mvert[medge[i].v1].co, mvert[medge[i].v2].co);
- vert_lens[medge[i].v1] = min_ff(vert_lens[medge[i].v1], ed_len_sq);
- vert_lens[medge[i].v2] = min_ff(vert_lens[medge[i].v2], ed_len_sq);
- }
- }
-
- if (ofs_new != 0.0f) {
- uint i_orig, i_end;
- bool do_shell_align;
-
- scalar_short = scalar_short_vgroup = ofs_new / 32767.0f;
-
- INIT_VERT_ARRAY_OFFSETS(false);
-
- for (i_orig = 0; i_orig < i_end; i_orig++, mv++) {
- const uint i = do_shell_align ? i_orig : new_vert_arr[i_orig];
- if (dvert) {
- MDeformVert *dv = &dvert[i];
- if (defgrp_invert) {
- scalar_short_vgroup = 1.0f - defvert_find_weight(dv, defgrp_index);
- }
- else {
- scalar_short_vgroup = defvert_find_weight(dv, defgrp_index);
- }
- scalar_short_vgroup = (offset_fac_vg + (scalar_short_vgroup * offset_fac_vg_inv)) *
- scalar_short;
- }
- if (do_clamp) {
- /* always reset becaise we may have set before */
- if (dvert == NULL) {
- scalar_short_vgroup = scalar_short;
- }
- if (vert_lens[i] < offset_sq) {
- float scalar = sqrtf(vert_lens[i]) / offset;
- scalar_short_vgroup *= scalar;
- }
- }
- madd_v3v3short_fl(mv->co, mv->no, scalar_short_vgroup);
- }
- }
-
- if (ofs_orig != 0.0f) {
- uint i_orig, i_end;
- bool do_shell_align;
-
- scalar_short = scalar_short_vgroup = ofs_orig / 32767.0f;
-
- /* as above but swapped */
- INIT_VERT_ARRAY_OFFSETS(true);
-
- for (i_orig = 0; i_orig < i_end; i_orig++, mv++) {
- const uint i = do_shell_align ? i_orig : new_vert_arr[i_orig];
- if (dvert) {
- MDeformVert *dv = &dvert[i];
- if (defgrp_invert) {
- scalar_short_vgroup = 1.0f - defvert_find_weight(dv, defgrp_index);
- }
- else {
- scalar_short_vgroup = defvert_find_weight(dv, defgrp_index);
- }
- scalar_short_vgroup = (offset_fac_vg + (scalar_short_vgroup * offset_fac_vg_inv)) *
- scalar_short;
- }
- if (do_clamp) {
- /* always reset becaise we may have set before */
- if (dvert == NULL) {
- scalar_short_vgroup = scalar_short;
- }
- if (vert_lens[i] < offset_sq) {
- float scalar = sqrtf(vert_lens[i]) / offset;
- scalar_short_vgroup *= scalar;
- }
- }
- madd_v3v3short_fl(mv->co, mv->no, scalar_short_vgroup);
- }
- }
-
- if (do_clamp) {
- MEM_freeN(vert_lens);
- }
- }
- else {
-#ifdef USE_NONMANIFOLD_WORKAROUND
- const bool check_non_manifold = (smd->flag & MOD_SOLIDIFY_NORMAL_CALC) != 0;
-#endif
- /* same as EM_solidify() in editmesh_lib.c */
- float *vert_angles = MEM_calloc_arrayN(
- numVerts, 2 * sizeof(float), "mod_solid_pair"); /* 2 in 1 */
- float *vert_accum = vert_angles + numVerts;
- uint vidx;
- uint i;
-
- if (vert_nors == NULL) {
- vert_nors = MEM_malloc_arrayN(numVerts, 3 * sizeof(float), "mod_solid_vno");
- for (i = 0, mv = mvert; i < numVerts; i++, mv++) {
- normal_short_to_float_v3(vert_nors[i], mv->no);
- }
- }
-
- for (i = 0, mp = mpoly; i < numPolys; i++, mp++) {
- /* #BKE_mesh_calc_poly_angles logic is inlined here */
- float nor_prev[3];
- float nor_next[3];
-
- int i_curr = mp->totloop - 1;
- int i_next = 0;
-
- ml = &mloop[mp->loopstart];
-
- sub_v3_v3v3(nor_prev, mvert[ml[i_curr - 1].v].co, mvert[ml[i_curr].v].co);
- normalize_v3(nor_prev);
-
- while (i_next < mp->totloop) {
- float angle;
- sub_v3_v3v3(nor_next, mvert[ml[i_curr].v].co, mvert[ml[i_next].v].co);
- normalize_v3(nor_next);
- angle = angle_normalized_v3v3(nor_prev, nor_next);
-
- /* --- not related to angle calc --- */
- if (angle < FLT_EPSILON) {
- angle = FLT_EPSILON;
- }
-
- vidx = ml[i_curr].v;
- vert_accum[vidx] += angle;
-
-#ifdef USE_NONMANIFOLD_WORKAROUND
- /* skip 3+ face user edges */
- if ((check_non_manifold == false) ||
- LIKELY(((orig_medge[ml[i_curr].e].flag & ME_EDGE_TMP_TAG) == 0) &&
- ((orig_medge[ml[i_next].e].flag & ME_EDGE_TMP_TAG) == 0))) {
- vert_angles[vidx] += shell_v3v3_normalized_to_dist(vert_nors[vidx], poly_nors[i]) *
- angle;
- }
- else {
- vert_angles[vidx] += angle;
- }
-#else
- vert_angles[vidx] += shell_v3v3_normalized_to_dist(vert_nors[vidx], poly_nors[i]) * angle;
-#endif
- /* --- end non-angle-calc section --- */
-
- /* step */
- copy_v3_v3(nor_prev, nor_next);
- i_curr = i_next;
- i_next++;
- }
- }
-
- /* vertex group support */
- if (dvert) {
- MDeformVert *dv = dvert;
- float scalar;
-
- if (defgrp_invert) {
- for (i = 0; i < numVerts; i++, dv++) {
- scalar = 1.0f - defvert_find_weight(dv, defgrp_index);
- scalar = offset_fac_vg + (scalar * offset_fac_vg_inv);
- vert_angles[i] *= scalar;
- }
- }
- else {
- for (i = 0; i < numVerts; i++, dv++) {
- scalar = defvert_find_weight(dv, defgrp_index);
- scalar = offset_fac_vg + (scalar * offset_fac_vg_inv);
- vert_angles[i] *= scalar;
- }
- }
- }
-
- if (do_clamp) {
- float *vert_lens_sq = MEM_malloc_arrayN(numVerts, sizeof(float), "vert_lens");
- const float offset = fabsf(smd->offset) * smd->offset_clamp;
- const float offset_sq = offset * offset;
- copy_vn_fl(vert_lens_sq, (int)numVerts, FLT_MAX);
- for (i = 0; i < numEdges; i++) {
- const float ed_len = len_squared_v3v3(mvert[medge[i].v1].co, mvert[medge[i].v2].co);
- vert_lens_sq[medge[i].v1] = min_ff(vert_lens_sq[medge[i].v1], ed_len);
- vert_lens_sq[medge[i].v2] = min_ff(vert_lens_sq[medge[i].v2], ed_len);
- }
- for (i = 0; i < numVerts; i++) {
- if (vert_lens_sq[i] < offset_sq) {
- float scalar = sqrtf(vert_lens_sq[i]) / offset;
- vert_angles[i] *= scalar;
- }
- }
- MEM_freeN(vert_lens_sq);
- }
-
- if (ofs_new != 0.0f) {
- uint i_orig, i_end;
- bool do_shell_align;
-
- INIT_VERT_ARRAY_OFFSETS(false);
-
- for (i_orig = 0; i_orig < i_end; i_orig++, mv++) {
- const uint i_other = do_shell_align ? i_orig : new_vert_arr[i_orig];
- if (vert_accum[i_other]) { /* zero if unselected */
- madd_v3_v3fl(
- mv->co, vert_nors[i_other], ofs_new * (vert_angles[i_other] / vert_accum[i_other]));
- }
- }
- }
-
- if (ofs_orig != 0.0f) {
- uint i_orig, i_end;
- bool do_shell_align;
-
- /* same as above but swapped, intentional use of 'ofs_new' */
- INIT_VERT_ARRAY_OFFSETS(true);
-
- for (i_orig = 0; i_orig < i_end; i_orig++, mv++) {
- const uint i_other = do_shell_align ? i_orig : new_vert_arr[i_orig];
- if (vert_accum[i_other]) { /* zero if unselected */
- madd_v3_v3fl(
- mv->co, vert_nors[i_other], ofs_orig * (vert_angles[i_other] / vert_accum[i_other]));
- }
- }
- }
-
- MEM_freeN(vert_angles);
- }
-
- if (vert_nors) {
- MEM_freeN(vert_nors);
- }
-
- /* must recalculate normals with vgroups since they can displace unevenly [#26888] */
- if ((mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) || (smd->flag & MOD_SOLIDIFY_RIM) || dvert) {
- result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
- }
- else if (do_shell) {
- uint i;
- /* flip vertex normals for copied verts */
- mv = mvert + numVerts;
- for (i = 0; i < numVerts; i++, mv++) {
- negate_v3_short(mv->no);
- }
- }
-
- if (smd->flag & MOD_SOLIDIFY_RIM) {
- uint i;
-
- /* bugger, need to re-calculate the normals for the new edge faces.
- * This could be done in many ways, but probably the quickest way
- * is to calculate the average normals for side faces only.
- * Then blend them with the normals of the edge verts.
- *
- * at the moment its easiest to allocate an entire array for every vertex,
- * even though we only need edge verts - campbell
- */
-
-#define SOLIDIFY_SIDE_NORMALS
-
-#ifdef SOLIDIFY_SIDE_NORMALS
- /* Note that, due to the code setting cd_dirty_vert a few lines above,
- * do_side_normals is always false. - Sybren */
- const bool do_side_normals = !(result->runtime.cd_dirty_vert & CD_MASK_NORMAL);
- /* annoying to allocate these since we only need the edge verts, */
- float(*edge_vert_nos)[3] = do_side_normals ?
- MEM_calloc_arrayN(numVerts, 3 * sizeof(float), __func__) :
- NULL;
- float nor[3];
-#endif
- const uchar crease_rim = smd->crease_rim * 255.0f;
- const uchar crease_outer = smd->crease_outer * 255.0f;
- const uchar crease_inner = smd->crease_inner * 255.0f;
-
- int *origindex_edge;
- int *orig_ed;
- uint j;
-
- if (crease_rim || crease_outer || crease_inner) {
- result->cd_flag |= ME_CDFLAG_EDGE_CREASE;
- }
-
- /* add faces & edges */
- origindex_edge = CustomData_get_layer(&result->edata, CD_ORIGINDEX);
- orig_ed = (origindex_edge) ? &origindex_edge[(numEdges * stride) + newEdges] : NULL;
- ed = &medge[(numEdges * stride) + newEdges]; /* start after copied edges */
- for (i = 0; i < rimVerts; i++, ed++) {
- ed->v1 = new_vert_arr[i];
- ed->v2 = (do_shell ? new_vert_arr[i] : i) + numVerts;
- ed->flag |= ME_EDGEDRAW | ME_EDGERENDER;
-
- if (orig_ed) {
- *orig_ed = ORIGINDEX_NONE;
- orig_ed++;
- }
-
- if (crease_rim) {
- ed->crease = crease_rim;
- }
- }
-
- /* faces */
- mp = mpoly + (numPolys * stride);
- ml = mloop + (numLoops * stride);
- j = 0;
- for (i = 0; i < newPolys; i++, mp++) {
- uint eidx = new_edge_arr[i];
- uint pidx = edge_users[eidx];
- int k1, k2;
- bool flip;
-
- if (pidx >= numPolys) {
- pidx -= numPolys;
- flip = true;
- }
- else {
- flip = false;
- }
-
- ed = medge + eidx;
-
- /* copy most of the face settings */
- CustomData_copy_data(
- &mesh->pdata, &result->pdata, (int)pidx, (int)((numPolys * stride) + i), 1);
- mp->loopstart = (int)(j + (numLoops * stride));
- mp->flag = mpoly[pidx].flag;
-
- /* notice we use 'mp->totloop' which is later overwritten,
- * we could lookup the original face but there's no point since this is a copy
- * and will have the same value, just take care when changing order of assignment */
-
- /* prev loop */
- k1 = mpoly[pidx].loopstart + (((edge_order[eidx] - 1) + mp->totloop) % mp->totloop);
-
- k2 = mpoly[pidx].loopstart + (edge_order[eidx]);
-
- mp->totloop = 4;
-
- CustomData_copy_data(
- &mesh->ldata, &result->ldata, k2, (int)((numLoops * stride) + j + 0), 1);
- CustomData_copy_data(
- &mesh->ldata, &result->ldata, k1, (int)((numLoops * stride) + j + 1), 1);
- CustomData_copy_data(
- &mesh->ldata, &result->ldata, k1, (int)((numLoops * stride) + j + 2), 1);
- CustomData_copy_data(
- &mesh->ldata, &result->ldata, k2, (int)((numLoops * stride) + j + 3), 1);
-
- if (flip == false) {
- ml[j].v = ed->v1;
- ml[j++].e = eidx;
-
- ml[j].v = ed->v2;
- ml[j++].e = (numEdges * stride) + old_vert_arr[ed->v2] + newEdges;
-
- ml[j].v = (do_shell ? ed->v2 : old_vert_arr[ed->v2]) + numVerts;
- ml[j++].e = (do_shell ? eidx : i) + numEdges;
-
- ml[j].v = (do_shell ? ed->v1 : old_vert_arr[ed->v1]) + numVerts;
- ml[j++].e = (numEdges * stride) + old_vert_arr[ed->v1] + newEdges;
- }
- else {
- ml[j].v = ed->v2;
- ml[j++].e = eidx;
-
- ml[j].v = ed->v1;
- ml[j++].e = (numEdges * stride) + old_vert_arr[ed->v1] + newEdges;
-
- ml[j].v = (do_shell ? ed->v1 : old_vert_arr[ed->v1]) + numVerts;
- ml[j++].e = (do_shell ? eidx : i) + numEdges;
-
- ml[j].v = (do_shell ? ed->v2 : old_vert_arr[ed->v2]) + numVerts;
- ml[j++].e = (numEdges * stride) + old_vert_arr[ed->v2] + newEdges;
- }
-
- if (origindex_edge) {
- origindex_edge[ml[j - 3].e] = ORIGINDEX_NONE;
- origindex_edge[ml[j - 1].e] = ORIGINDEX_NONE;
- }
-
- /* use the next material index if option enabled */
- if (mat_ofs_rim) {
- mp->mat_nr += mat_ofs_rim;
- CLAMP(mp->mat_nr, 0, mat_nr_max);
- }
- if (crease_outer) {
- /* crease += crease_outer; without wrapping */
- char *cr = &(ed->crease);
- int tcr = *cr + crease_outer;
- *cr = tcr > 255 ? 255 : tcr;
- }
-
- if (crease_inner) {
- /* crease += crease_inner; without wrapping */
- char *cr = &(medge[numEdges + (do_shell ? eidx : i)].crease);
- int tcr = *cr + crease_inner;
- *cr = tcr > 255 ? 255 : tcr;
- }
-
-#ifdef SOLIDIFY_SIDE_NORMALS
- if (do_side_normals) {
- normal_quad_v3(nor,
- mvert[ml[j - 4].v].co,
- mvert[ml[j - 3].v].co,
- mvert[ml[j - 2].v].co,
- mvert[ml[j - 1].v].co);
-
- add_v3_v3(edge_vert_nos[ed->v1], nor);
- add_v3_v3(edge_vert_nos[ed->v2], nor);
- }
-#endif
- }
-
-#ifdef SOLIDIFY_SIDE_NORMALS
- if (do_side_normals) {
- const MEdge *ed_orig = medge;
- ed = medge + (numEdges * stride);
- for (i = 0; i < rimVerts; i++, ed++, ed_orig++) {
- float nor_cpy[3];
- short *nor_short;
- int k;
-
- /* note, only the first vertex (lower half of the index) is calculated */
- BLI_assert(ed->v1 < numVerts);
- normalize_v3_v3(nor_cpy, edge_vert_nos[ed_orig->v1]);
-
- for (k = 0; k < 2; k++) { /* loop over both verts of the edge */
- nor_short = mvert[*(&ed->v1 + k)].no;
- normal_short_to_float_v3(nor, nor_short);
- add_v3_v3(nor, nor_cpy);
- normalize_v3(nor);
- normal_float_to_short_v3(nor_short, nor);
- }
- }
-
- MEM_freeN(edge_vert_nos);
- }
-#endif
-
- MEM_freeN(new_vert_arr);
- MEM_freeN(new_edge_arr);
-
- MEM_freeN(edge_users);
- MEM_freeN(edge_order);
- }
-
- if (old_vert_arr) {
- MEM_freeN(old_vert_arr);
- }
-
- if (poly_nors) {
- MEM_freeN(poly_nors);
- }
-
- if (numPolys == 0 && numEdges != 0) {
- modifier_setError(md, "Faces needed for useful output");
- }
-
- return result;
-}
-
-#undef SOLIDIFY_SIDE_NORMALS
-
-static bool dependsOnNormals(ModifierData *UNUSED(md))
-{
- /* even when we calculate our own normals,
- * the vertex normals are used as a fallback */
- return true;
+ return mesh;
}
ModifierTypeInfo modifierType_Solidify = {
diff --git a/source/blender/modifiers/intern/MOD_solidify_extrude.c b/source/blender/modifiers/intern/MOD_solidify_extrude.c
new file mode 100644
index 00000000000..8c5a2551c0b
--- /dev/null
+++ b/source/blender/modifiers/intern/MOD_solidify_extrude.c
@@ -0,0 +1,1105 @@
+/*
+ * 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.
+ */
+
+/** \file
+ * \ingroup modifiers
+ */
+
+#include "BLI_utildefines.h"
+
+#include "BLI_bitmap.h"
+#include "BLI_math.h"
+#include "BLI_utildefines_stack.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BKE_mesh.h"
+#include "BKE_particle.h"
+#include "BKE_deform.h"
+
+#include "MOD_modifiertypes.h"
+#include "MOD_util.h"
+#include "MOD_solidify_util.h" /* own include */
+
+#ifdef __GNUC__
+# pragma GCC diagnostic error "-Wsign-conversion"
+#endif
+
+/* -------------------------------------------------------------------- */
+/** \name Local Utilities
+ * \{ */
+
+/* specific function for solidify - define locally */
+BLI_INLINE void madd_v3v3short_fl(float r[3], const short a[3], const float f)
+{
+ r[0] += (float)a[0] * f;
+ r[1] += (float)a[1] * f;
+ r[2] += (float)a[2] * f;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name High Quality Normal Calculation Function
+ * \{ */
+
+/* skip shell thickness for non-manifold edges, see [#35710] */
+#define USE_NONMANIFOLD_WORKAROUND
+
+/* *** derived mesh high quality normal calculation function *** */
+/* could be exposed for other functions to use */
+
+typedef struct EdgeFaceRef {
+ int p1; /* init as -1 */
+ int p2;
+} EdgeFaceRef;
+
+BLI_INLINE bool edgeref_is_init(const EdgeFaceRef *edge_ref)
+{
+ return !((edge_ref->p1 == 0) && (edge_ref->p2 == 0));
+}
+
+/**
+ * \param dm: Mesh to calculate normals for.
+ * \param poly_nors: Precalculated face normals.
+ * \param r_vert_nors: Return vert normals.
+ */
+static void mesh_calc_hq_normal(Mesh *mesh, float (*poly_nors)[3], float (*r_vert_nors)[3])
+{
+ int i, numVerts, numEdges, numPolys;
+ MPoly *mpoly, *mp;
+ MLoop *mloop, *ml;
+ MEdge *medge, *ed;
+ MVert *mvert, *mv;
+
+ numVerts = mesh->totvert;
+ numEdges = mesh->totedge;
+ numPolys = mesh->totpoly;
+ mpoly = mesh->mpoly;
+ medge = mesh->medge;
+ mvert = mesh->mvert;
+ mloop = mesh->mloop;
+
+ /* we don't want to overwrite any referenced layers */
+
+ /* Doesn't work here! */
+#if 0
+ mv = CustomData_duplicate_referenced_layer(&dm->vertData, CD_MVERT, numVerts);
+ cddm->mvert = mv;
+#endif
+
+ mv = mvert;
+ mp = mpoly;
+
+ {
+ EdgeFaceRef *edge_ref_array = MEM_calloc_arrayN(
+ (size_t)numEdges, sizeof(EdgeFaceRef), "Edge Connectivity");
+ EdgeFaceRef *edge_ref;
+ float edge_normal[3];
+
+ /* Add an edge reference if it's not there, pointing back to the face index. */
+ for (i = 0; i < numPolys; i++, mp++) {
+ int j;
+
+ ml = mloop + mp->loopstart;
+
+ for (j = 0; j < mp->totloop; j++, ml++) {
+ /* --- add edge ref to face --- */
+ edge_ref = &edge_ref_array[ml->e];
+ if (!edgeref_is_init(edge_ref)) {
+ edge_ref->p1 = i;
+ edge_ref->p2 = -1;
+ }
+ else if ((edge_ref->p1 != -1) && (edge_ref->p2 == -1)) {
+ edge_ref->p2 = i;
+ }
+ else {
+ /* 3+ faces using an edge, we can't handle this usefully */
+ edge_ref->p1 = edge_ref->p2 = -1;
+#ifdef USE_NONMANIFOLD_WORKAROUND
+ medge[ml->e].flag |= ME_EDGE_TMP_TAG;
+#endif
+ }
+ /* --- done --- */
+ }
+ }
+
+ for (i = 0, ed = medge, edge_ref = edge_ref_array; i < numEdges; i++, ed++, edge_ref++) {
+ /* Get the edge vert indices, and edge value (the face indices that use it) */
+
+ if (edgeref_is_init(edge_ref) && (edge_ref->p1 != -1)) {
+ if (edge_ref->p2 != -1) {
+ /* We have 2 faces using this edge, calculate the edges normal
+ * using the angle between the 2 faces as a weighting */
+#if 0
+ add_v3_v3v3(edge_normal, face_nors[edge_ref->f1], face_nors[edge_ref->f2]);
+ normalize_v3_length(
+ edge_normal,
+ angle_normalized_v3v3(face_nors[edge_ref->f1], face_nors[edge_ref->f2]));
+#else
+ mid_v3_v3v3_angle_weighted(
+ edge_normal, poly_nors[edge_ref->p1], poly_nors[edge_ref->p2]);
+#endif
+ }
+ else {
+ /* only one face attached to that edge */
+ /* an edge without another attached- the weight on this is undefined */
+ copy_v3_v3(edge_normal, poly_nors[edge_ref->p1]);
+ }
+ add_v3_v3(r_vert_nors[ed->v1], edge_normal);
+ add_v3_v3(r_vert_nors[ed->v2], edge_normal);
+ }
+ }
+ MEM_freeN(edge_ref_array);
+ }
+
+ /* normalize vertex normals and assign */
+ for (i = 0; i < numVerts; i++, mv++) {
+ if (normalize_v3(r_vert_nors[i]) == 0.0f) {
+ normal_short_to_float_v3(r_vert_nors[i], mv->no);
+ }
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Main Solidify Function
+ * \{ */
+
+Mesh *MOD_solidify_extrude_applyModifier(ModifierData *md,
+ const ModifierEvalContext *ctx,
+ Mesh *mesh)
+{
+ Mesh *result;
+ const SolidifyModifierData *smd = (SolidifyModifierData *)md;
+
+ MVert *mv, *mvert, *orig_mvert;
+ MEdge *ed, *medge, *orig_medge;
+ MLoop *ml, *mloop, *orig_mloop;
+ MPoly *mp, *mpoly, *orig_mpoly;
+ const uint numVerts = (uint)mesh->totvert;
+ const uint numEdges = (uint)mesh->totedge;
+ const uint numPolys = (uint)mesh->totpoly;
+ const uint numLoops = (uint)mesh->totloop;
+ uint newLoops = 0, newPolys = 0, newEdges = 0, newVerts = 0, rimVerts = 0;
+
+ /* only use material offsets if we have 2 or more materials */
+ const short mat_nr_max = ctx->object->totcol > 1 ? ctx->object->totcol - 1 : 0;
+ const short mat_ofs = mat_nr_max ? smd->mat_ofs : 0;
+ const short mat_ofs_rim = mat_nr_max ? smd->mat_ofs_rim : 0;
+
+ /* use for edges */
+ /* over-alloc new_vert_arr, old_vert_arr */
+ uint *new_vert_arr = NULL;
+ STACK_DECLARE(new_vert_arr);
+
+ uint *new_edge_arr = NULL;
+ STACK_DECLARE(new_edge_arr);
+
+ uint *old_vert_arr = MEM_calloc_arrayN(
+ numVerts, sizeof(*old_vert_arr), "old_vert_arr in solidify");
+
+ uint *edge_users = NULL;
+ char *edge_order = NULL;
+
+ float(*vert_nors)[3] = NULL;
+ float(*poly_nors)[3] = NULL;
+
+ const bool need_poly_normals = (smd->flag & MOD_SOLIDIFY_NORMAL_CALC) ||
+ (smd->flag & MOD_SOLIDIFY_EVEN) ||
+ (smd->flag & MOD_SOLIDIFY_OFFSET_ANGLE_CLAMP);
+
+ const float ofs_orig = -(((-smd->offset_fac + 1.0f) * 0.5f) * smd->offset);
+ const float ofs_new = smd->offset + ofs_orig;
+ const float offset_fac_vg = smd->offset_fac_vg;
+ const float offset_fac_vg_inv = 1.0f - smd->offset_fac_vg;
+ const bool do_flip = (smd->flag & MOD_SOLIDIFY_FLIP) != 0;
+ const bool do_clamp = (smd->offset_clamp != 0.0f);
+ const bool do_angle_clamp = (smd->flag & MOD_SOLIDIFY_OFFSET_ANGLE_CLAMP) != 0;
+ const bool do_shell = ((smd->flag & MOD_SOLIDIFY_RIM) && (smd->flag & MOD_SOLIDIFY_NOSHELL)) ==
+ 0;
+
+ /* weights */
+ MDeformVert *dvert;
+ const bool defgrp_invert = (smd->flag & MOD_SOLIDIFY_VGROUP_INV) != 0;
+ int defgrp_index;
+
+ /* array size is doubled in case of using a shell */
+ const uint stride = do_shell ? 2 : 1;
+
+ MOD_get_vgroup(ctx->object, mesh, smd->defgrp_name, &dvert, &defgrp_index);
+
+ orig_mvert = mesh->mvert;
+ orig_medge = mesh->medge;
+ orig_mloop = mesh->mloop;
+ orig_mpoly = mesh->mpoly;
+
+ if (need_poly_normals) {
+ /* calculate only face normals */
+ poly_nors = MEM_malloc_arrayN(numPolys, sizeof(*poly_nors), __func__);
+ BKE_mesh_calc_normals_poly(orig_mvert,
+ NULL,
+ (int)numVerts,
+ orig_mloop,
+ orig_mpoly,
+ (int)numLoops,
+ (int)numPolys,
+ poly_nors,
+ true);
+ }
+
+ STACK_INIT(new_vert_arr, numVerts * 2);
+ STACK_INIT(new_edge_arr, numEdges * 2);
+
+ if (smd->flag & MOD_SOLIDIFY_RIM) {
+ BLI_bitmap *orig_mvert_tag = BLI_BITMAP_NEW(numVerts, __func__);
+ uint eidx;
+ uint i;
+
+#define INVALID_UNUSED ((uint)-1)
+#define INVALID_PAIR ((uint)-2)
+
+ new_vert_arr = MEM_malloc_arrayN(numVerts, 2 * sizeof(*new_vert_arr), __func__);
+ new_edge_arr = MEM_malloc_arrayN(((numEdges * 2) + numVerts), sizeof(*new_edge_arr), __func__);
+
+ edge_users = MEM_malloc_arrayN(numEdges, sizeof(*edge_users), "solid_mod edges");
+ edge_order = MEM_malloc_arrayN(numEdges, sizeof(*edge_order), "solid_mod eorder");
+
+ /* save doing 2 loops here... */
+#if 0
+ copy_vn_i(edge_users, numEdges, INVALID_UNUSED);
+#endif
+
+ for (eidx = 0, ed = orig_medge; eidx < numEdges; eidx++, ed++) {
+ edge_users[eidx] = INVALID_UNUSED;
+ }
+
+ for (i = 0, mp = orig_mpoly; i < numPolys; i++, mp++) {
+ MLoop *ml_prev;
+ int j;
+
+ ml = orig_mloop + mp->loopstart;
+ ml_prev = ml + (mp->totloop - 1);
+
+ for (j = 0; j < mp->totloop; j++, ml++) {
+ /* add edge user */
+ eidx = ml_prev->e;
+ if (edge_users[eidx] == INVALID_UNUSED) {
+ ed = orig_medge + eidx;
+ BLI_assert(ELEM(ml_prev->v, ed->v1, ed->v2) && ELEM(ml->v, ed->v1, ed->v2));
+ edge_users[eidx] = (ml_prev->v > ml->v) == (ed->v1 < ed->v2) ? i : (i + numPolys);
+ edge_order[eidx] = j;
+ }
+ else {
+ edge_users[eidx] = INVALID_PAIR;
+ }
+ ml_prev = ml;
+ }
+ }
+
+ for (eidx = 0, ed = orig_medge; eidx < numEdges; eidx++, ed++) {
+ if (!ELEM(edge_users[eidx], INVALID_UNUSED, INVALID_PAIR)) {
+ BLI_BITMAP_ENABLE(orig_mvert_tag, ed->v1);
+ BLI_BITMAP_ENABLE(orig_mvert_tag, ed->v2);
+ STACK_PUSH(new_edge_arr, eidx);
+ newPolys++;
+ newLoops += 4;
+ }
+ }
+
+ for (i = 0; i < numVerts; i++) {
+ if (BLI_BITMAP_TEST(orig_mvert_tag, i)) {
+ old_vert_arr[i] = STACK_SIZE(new_vert_arr);
+ STACK_PUSH(new_vert_arr, i);
+ rimVerts++;
+ }
+ else {
+ old_vert_arr[i] = INVALID_UNUSED;
+ }
+ }
+
+ MEM_freeN(orig_mvert_tag);
+ }
+
+ if (do_shell == false) {
+ /* only add rim vertices */
+ newVerts = rimVerts;
+ /* each extruded face needs an opposite edge */
+ newEdges = newPolys;
+ }
+ else {
+ /* (stride == 2) in this case, so no need to add newVerts/newEdges */
+ BLI_assert(newVerts == 0);
+ BLI_assert(newEdges == 0);
+ }
+
+ if (smd->flag & MOD_SOLIDIFY_NORMAL_CALC) {
+ vert_nors = MEM_calloc_arrayN(numVerts, 3 * sizeof(float), "mod_solid_vno_hq");
+ mesh_calc_hq_normal(mesh, poly_nors, vert_nors);
+ }
+
+ result = BKE_mesh_new_nomain_from_template(mesh,
+ (int)((numVerts * stride) + newVerts),
+ (int)((numEdges * stride) + newEdges + rimVerts),
+ 0,
+ (int)((numLoops * stride) + newLoops),
+ (int)((numPolys * stride) + newPolys));
+
+ mpoly = result->mpoly;
+ mloop = result->mloop;
+ medge = result->medge;
+ mvert = result->mvert;
+
+ if (do_shell) {
+ CustomData_copy_data(&mesh->vdata, &result->vdata, 0, 0, (int)numVerts);
+ CustomData_copy_data(&mesh->vdata, &result->vdata, 0, (int)numVerts, (int)numVerts);
+
+ CustomData_copy_data(&mesh->edata, &result->edata, 0, 0, (int)numEdges);
+ CustomData_copy_data(&mesh->edata, &result->edata, 0, (int)numEdges, (int)numEdges);
+
+ CustomData_copy_data(&mesh->ldata, &result->ldata, 0, 0, (int)numLoops);
+ /* DO NOT copy here the 'copied' part of loop data, we want to reverse loops
+ * (so that winding of copied face get reversed, so that normals get reversed
+ * and point in expected direction...).
+ * If we also copy data here, then this data get overwritten
+ * (and allocated memory becomes memleak). */
+
+ CustomData_copy_data(&mesh->pdata, &result->pdata, 0, 0, (int)numPolys);
+ CustomData_copy_data(&mesh->pdata, &result->pdata, 0, (int)numPolys, (int)numPolys);
+ }
+ else {
+ int i, j;
+ CustomData_copy_data(&mesh->vdata, &result->vdata, 0, 0, (int)numVerts);
+ for (i = 0, j = (int)numVerts; i < numVerts; i++) {
+ if (old_vert_arr[i] != INVALID_UNUSED) {
+ CustomData_copy_data(&mesh->vdata, &result->vdata, i, j, 1);
+ j++;
+ }
+ }
+
+ CustomData_copy_data(&mesh->edata, &result->edata, 0, 0, (int)numEdges);
+
+ for (i = 0, j = (int)numEdges; i < numEdges; i++) {
+ if (!ELEM(edge_users[i], INVALID_UNUSED, INVALID_PAIR)) {
+ MEdge *ed_src, *ed_dst;
+ CustomData_copy_data(&mesh->edata, &result->edata, i, j, 1);
+
+ ed_src = &medge[i];
+ ed_dst = &medge[j];
+ ed_dst->v1 = old_vert_arr[ed_src->v1] + numVerts;
+ ed_dst->v2 = old_vert_arr[ed_src->v2] + numVerts;
+ j++;
+ }
+ }
+
+ /* will be created later */
+ CustomData_copy_data(&mesh->ldata, &result->ldata, 0, 0, (int)numLoops);
+ CustomData_copy_data(&mesh->pdata, &result->pdata, 0, 0, (int)numPolys);
+ }
+
+ /* initializes: (i_end, do_shell_align, mv) */
+#define INIT_VERT_ARRAY_OFFSETS(test) \
+ if (((ofs_new >= ofs_orig) == do_flip) == test) { \
+ i_end = numVerts; \
+ do_shell_align = true; \
+ mv = mvert; \
+ } \
+ else { \
+ if (do_shell) { \
+ i_end = numVerts; \
+ do_shell_align = true; \
+ } \
+ else { \
+ i_end = newVerts; \
+ do_shell_align = false; \
+ } \
+ mv = &mvert[numVerts]; \
+ } \
+ (void)0
+
+ /* flip normals */
+
+ if (do_shell) {
+ uint i;
+
+ mp = mpoly + numPolys;
+ for (i = 0; i < mesh->totpoly; i++, mp++) {
+ const int loop_end = mp->totloop - 1;
+ MLoop *ml2;
+ uint e;
+ int j;
+
+ /* reverses the loop direction (MLoop.v as well as custom-data)
+ * MLoop.e also needs to be corrected too, done in a separate loop below. */
+ ml2 = mloop + mp->loopstart + mesh->totloop;
+#if 0
+ for (j = 0; j < mp->totloop; j++) {
+ CustomData_copy_data(&mesh->ldata,
+ &result->ldata,
+ mp->loopstart + j,
+ mp->loopstart + (loop_end - j) + mesh->totloop,
+ 1);
+ }
+#else
+ /* slightly more involved, keep the first vertex the same for the copy,
+ * ensures the diagonals in the new face match the original. */
+ j = 0;
+ for (int j_prev = loop_end; j < mp->totloop; j_prev = j++) {
+ CustomData_copy_data(&mesh->ldata,
+ &result->ldata,
+ mp->loopstart + j,
+ mp->loopstart + (loop_end - j_prev) + mesh->totloop,
+ 1);
+ }
+#endif
+
+ if (mat_ofs) {
+ mp->mat_nr += mat_ofs;
+ CLAMP(mp->mat_nr, 0, mat_nr_max);
+ }
+
+ e = ml2[0].e;
+ for (j = 0; j < loop_end; j++) {
+ ml2[j].e = ml2[j + 1].e;
+ }
+ ml2[loop_end].e = e;
+
+ mp->loopstart += mesh->totloop;
+
+ for (j = 0; j < mp->totloop; j++) {
+ ml2[j].e += numEdges;
+ ml2[j].v += numVerts;
+ }
+ }
+
+ for (i = 0, ed = medge + numEdges; i < numEdges; i++, ed++) {
+ ed->v1 += numVerts;
+ ed->v2 += numVerts;
+ }
+ }
+
+ /* note, copied vertex layers don't have flipped normals yet. do this after applying offset */
+ if ((smd->flag & MOD_SOLIDIFY_EVEN) == 0) {
+ /* no even thickness, very simple */
+ float scalar_short;
+ float scalar_short_vgroup;
+
+ /* for clamping */
+ float *vert_lens = NULL;
+ float *vert_angs = NULL;
+ const float offset = fabsf(smd->offset) * smd->offset_clamp;
+ const float offset_sq = offset * offset;
+
+ if (do_clamp) {
+ uint i;
+
+ vert_lens = MEM_malloc_arrayN(numVerts, sizeof(float), "vert_lens");
+ copy_vn_fl(vert_lens, (int)numVerts, FLT_MAX);
+ for (i = 0; i < numEdges; i++) {
+ const float ed_len_sq = len_squared_v3v3(mvert[medge[i].v1].co, mvert[medge[i].v2].co);
+ vert_lens[medge[i].v1] = min_ff(vert_lens[medge[i].v1], ed_len_sq);
+ vert_lens[medge[i].v2] = min_ff(vert_lens[medge[i].v2], ed_len_sq);
+ }
+ if (do_angle_clamp) {
+ uint eidx;
+ vert_angs = MEM_malloc_arrayN(numVerts, sizeof(float), "vert_angs");
+ copy_vn_fl(vert_angs, (int)numVerts, 0.5f * M_PI);
+ uint(*edge_user_pairs)[2] = MEM_malloc_arrayN(
+ numEdges, sizeof(*edge_user_pairs), "edge_user_pairs");
+ for (eidx = 0; eidx < numEdges; eidx++) {
+ edge_user_pairs[eidx][0] = INVALID_UNUSED;
+ edge_user_pairs[eidx][1] = INVALID_UNUSED;
+ }
+ for (i = 0, mp = orig_mpoly; i < numPolys; i++, mp++) {
+ ml = orig_mloop + mp->loopstart;
+ MLoop *ml_prev = ml + (mp->totloop - 1);
+
+ for (int j = 0; j < mp->totloop; j++, ml++) {
+ /* add edge user */
+ eidx = ml_prev->e;
+ ed = orig_medge + eidx;
+ BLI_assert(ELEM(ml_prev->v, ed->v1, ed->v2) && ELEM(ml->v, ed->v1, ed->v2));
+ char flip = (char)((ml_prev->v > ml->v) == (ed->v1 < ed->v2));
+ if (edge_user_pairs[eidx][flip] == INVALID_UNUSED) {
+ edge_user_pairs[eidx][flip] = i;
+ }
+ else {
+ edge_user_pairs[eidx][0] = INVALID_PAIR;
+ edge_user_pairs[eidx][1] = INVALID_PAIR;
+ }
+ ml_prev = ml;
+ }
+ }
+ ed = orig_medge;
+ float e[3];
+ for (i = 0; i < numEdges; i++, ed++) {
+ if (!ELEM(edge_user_pairs[i][0], INVALID_UNUSED, INVALID_PAIR) &&
+ !ELEM(edge_user_pairs[i][1], INVALID_UNUSED, INVALID_PAIR)) {
+ const float *n0 = poly_nors[edge_user_pairs[i][0]];
+ const float *n1 = poly_nors[edge_user_pairs[i][1]];
+ sub_v3_v3v3(e, orig_mvert[ed->v1].co, orig_mvert[ed->v2].co);
+ normalize_v3(e);
+ const float angle = angle_signed_on_axis_v3v3_v3(n0, n1, e);
+ vert_angs[ed->v1] = max_ff(vert_angs[ed->v1], angle);
+ vert_angs[ed->v2] = max_ff(vert_angs[ed->v2], angle);
+ }
+ }
+ MEM_freeN(edge_user_pairs);
+ }
+ }
+
+ if (ofs_new != 0.0f) {
+ uint i_orig, i_end;
+ bool do_shell_align;
+
+ scalar_short = scalar_short_vgroup = ofs_new / 32767.0f;
+
+ INIT_VERT_ARRAY_OFFSETS(false);
+
+ for (i_orig = 0; i_orig < i_end; i_orig++, mv++) {
+ const uint i = do_shell_align ? i_orig : new_vert_arr[i_orig];
+ if (dvert) {
+ MDeformVert *dv = &dvert[i];
+ if (defgrp_invert) {
+ scalar_short_vgroup = 1.0f - defvert_find_weight(dv, defgrp_index);
+ }
+ else {
+ scalar_short_vgroup = defvert_find_weight(dv, defgrp_index);
+ }
+ scalar_short_vgroup = (offset_fac_vg + (scalar_short_vgroup * offset_fac_vg_inv)) *
+ scalar_short;
+ }
+ if (do_clamp && offset > FLT_EPSILON) {
+ /* always reset because we may have set before */
+ if (dvert == NULL) {
+ scalar_short_vgroup = scalar_short;
+ }
+ if (do_angle_clamp) {
+ float cos_ang = cosf(((2 * M_PI) - vert_angs[i]) * 0.5f);
+ if (cos_ang > 0) {
+ float max_off = sqrtf(vert_lens[i]) * 0.5f / cos_ang;
+ if (max_off < offset * 0.5f) {
+ scalar_short_vgroup *= max_off / offset * 2;
+ }
+ }
+ }
+ else {
+ if (vert_lens[i] < offset_sq) {
+ float scalar = sqrtf(vert_lens[i]) / offset;
+ scalar_short_vgroup *= scalar;
+ }
+ }
+ }
+ madd_v3v3short_fl(mv->co, mv->no, scalar_short_vgroup);
+ }
+ }
+
+ if (ofs_orig != 0.0f) {
+ uint i_orig, i_end;
+ bool do_shell_align;
+
+ scalar_short = scalar_short_vgroup = ofs_orig / 32767.0f;
+
+ /* as above but swapped */
+ INIT_VERT_ARRAY_OFFSETS(true);
+
+ for (i_orig = 0; i_orig < i_end; i_orig++, mv++) {
+ const uint i = do_shell_align ? i_orig : new_vert_arr[i_orig];
+ if (dvert) {
+ MDeformVert *dv = &dvert[i];
+ if (defgrp_invert) {
+ scalar_short_vgroup = 1.0f - defvert_find_weight(dv, defgrp_index);
+ }
+ else {
+ scalar_short_vgroup = defvert_find_weight(dv, defgrp_index);
+ }
+ scalar_short_vgroup = (offset_fac_vg + (scalar_short_vgroup * offset_fac_vg_inv)) *
+ scalar_short;
+ }
+ if (do_clamp && offset > FLT_EPSILON) {
+ /* always reset because we may have set before */
+ if (dvert == NULL) {
+ scalar_short_vgroup = scalar_short;
+ }
+ if (do_angle_clamp) {
+ float cos_ang = cosf(vert_angs[i_orig] * 0.5f);
+ if (cos_ang > 0) {
+ float max_off = sqrtf(vert_lens[i]) * 0.5f / cos_ang;
+ if (max_off < offset * 0.5f) {
+ scalar_short_vgroup *= max_off / offset * 2;
+ }
+ }
+ }
+ else {
+ if (vert_lens[i] < offset_sq) {
+ float scalar = sqrtf(vert_lens[i]) / offset;
+ scalar_short_vgroup *= scalar;
+ }
+ }
+ }
+ madd_v3v3short_fl(mv->co, mv->no, scalar_short_vgroup);
+ }
+ }
+
+ if (do_clamp) {
+ MEM_freeN(vert_lens);
+ if (do_angle_clamp) {
+ MEM_freeN(vert_angs);
+ }
+ }
+ }
+ else {
+#ifdef USE_NONMANIFOLD_WORKAROUND
+ const bool check_non_manifold = (smd->flag & MOD_SOLIDIFY_NORMAL_CALC) != 0;
+#endif
+ /* same as EM_solidify() in editmesh_lib.c */
+ float *vert_angles = MEM_calloc_arrayN(
+ numVerts, 2 * sizeof(float), "mod_solid_pair"); /* 2 in 1 */
+ float *vert_accum = vert_angles + numVerts;
+ uint vidx;
+ uint i;
+
+ if (vert_nors == NULL) {
+ vert_nors = MEM_malloc_arrayN(numVerts, 3 * sizeof(float), "mod_solid_vno");
+ for (i = 0, mv = mvert; i < numVerts; i++, mv++) {
+ normal_short_to_float_v3(vert_nors[i], mv->no);
+ }
+ }
+
+ for (i = 0, mp = mpoly; i < numPolys; i++, mp++) {
+ /* #BKE_mesh_calc_poly_angles logic is inlined here */
+ float nor_prev[3];
+ float nor_next[3];
+
+ int i_curr = mp->totloop - 1;
+ int i_next = 0;
+
+ ml = &mloop[mp->loopstart];
+
+ sub_v3_v3v3(nor_prev, mvert[ml[i_curr - 1].v].co, mvert[ml[i_curr].v].co);
+ normalize_v3(nor_prev);
+
+ while (i_next < mp->totloop) {
+ float angle;
+ sub_v3_v3v3(nor_next, mvert[ml[i_curr].v].co, mvert[ml[i_next].v].co);
+ normalize_v3(nor_next);
+ angle = angle_normalized_v3v3(nor_prev, nor_next);
+
+ /* --- not related to angle calc --- */
+ if (angle < FLT_EPSILON) {
+ angle = FLT_EPSILON;
+ }
+
+ vidx = ml[i_curr].v;
+ vert_accum[vidx] += angle;
+
+#ifdef USE_NONMANIFOLD_WORKAROUND
+ /* skip 3+ face user edges */
+ if ((check_non_manifold == false) ||
+ LIKELY(((orig_medge[ml[i_curr].e].flag & ME_EDGE_TMP_TAG) == 0) &&
+ ((orig_medge[ml[i_next].e].flag & ME_EDGE_TMP_TAG) == 0))) {
+ vert_angles[vidx] += shell_v3v3_normalized_to_dist(vert_nors[vidx], poly_nors[i]) *
+ angle;
+ }
+ else {
+ vert_angles[vidx] += angle;
+ }
+#else
+ vert_angles[vidx] += shell_v3v3_normalized_to_dist(vert_nors[vidx], poly_nors[i]) * angle;
+#endif
+ /* --- end non-angle-calc section --- */
+
+ /* step */
+ copy_v3_v3(nor_prev, nor_next);
+ i_curr = i_next;
+ i_next++;
+ }
+ }
+
+ /* vertex group support */
+ if (dvert) {
+ MDeformVert *dv = dvert;
+ float scalar;
+
+ if (defgrp_invert) {
+ for (i = 0; i < numVerts; i++, dv++) {
+ scalar = 1.0f - defvert_find_weight(dv, defgrp_index);
+ scalar = offset_fac_vg + (scalar * offset_fac_vg_inv);
+ vert_angles[i] *= scalar;
+ }
+ }
+ else {
+ for (i = 0; i < numVerts; i++, dv++) {
+ scalar = defvert_find_weight(dv, defgrp_index);
+ scalar = offset_fac_vg + (scalar * offset_fac_vg_inv);
+ vert_angles[i] *= scalar;
+ }
+ }
+ }
+
+ if (do_clamp) {
+ const float clamp_fac = 1 + (do_angle_clamp ? fabsf(smd->offset_fac) : 0);
+ const float offset = fabsf(smd->offset) * smd->offset_clamp * clamp_fac;
+ if (offset > FLT_EPSILON) {
+ float *vert_lens_sq = MEM_malloc_arrayN(numVerts, sizeof(float), "vert_lens_sq");
+ const float offset_sq = offset * offset;
+ copy_vn_fl(vert_lens_sq, (int)numVerts, FLT_MAX);
+ for (i = 0; i < numEdges; i++) {
+ const float ed_len = len_squared_v3v3(mvert[medge[i].v1].co, mvert[medge[i].v2].co);
+ vert_lens_sq[medge[i].v1] = min_ff(vert_lens_sq[medge[i].v1], ed_len);
+ vert_lens_sq[medge[i].v2] = min_ff(vert_lens_sq[medge[i].v2], ed_len);
+ }
+ if (do_angle_clamp) {
+ uint eidx;
+ float *vert_angs = MEM_malloc_arrayN(numVerts, sizeof(float), "vert_angs even");
+ copy_vn_fl(vert_angs, (int)numVerts, 0.5f * M_PI);
+ uint(*edge_user_pairs)[2] = MEM_malloc_arrayN(
+ numEdges, sizeof(*edge_user_pairs), "edge_user_pairs");
+ for (eidx = 0; eidx < numEdges; eidx++) {
+ edge_user_pairs[eidx][0] = INVALID_UNUSED;
+ edge_user_pairs[eidx][1] = INVALID_UNUSED;
+ }
+ for (i = 0, mp = orig_mpoly; i < numPolys; i++, mp++) {
+ ml = orig_mloop + mp->loopstart;
+ MLoop *ml_prev = ml + (mp->totloop - 1);
+
+ for (int j = 0; j < mp->totloop; j++, ml++) {
+ /* add edge user */
+ eidx = ml_prev->e;
+ ed = orig_medge + eidx;
+ BLI_assert(ELEM(ml_prev->v, ed->v1, ed->v2) && ELEM(ml->v, ed->v1, ed->v2));
+ char flip = (char)((ml_prev->v > ml->v) == (ed->v1 < ed->v2));
+ if (edge_user_pairs[eidx][flip] == INVALID_UNUSED) {
+ edge_user_pairs[eidx][flip] = i;
+ }
+ else {
+ edge_user_pairs[eidx][0] = INVALID_PAIR;
+ edge_user_pairs[eidx][1] = INVALID_PAIR;
+ }
+ ml_prev = ml;
+ }
+ }
+ ed = orig_medge;
+ for (i = 0; i < numEdges; i++, ed++) {
+ if (!ELEM(edge_user_pairs[i][0], INVALID_UNUSED, INVALID_PAIR) &&
+ !ELEM(edge_user_pairs[i][1], INVALID_UNUSED, INVALID_PAIR)) {
+ const float *n0 = poly_nors[edge_user_pairs[i][0]];
+ const float *n1 = poly_nors[edge_user_pairs[i][1]];
+ const float angle = M_PI - angle_normalized_v3v3(n0, n1);
+ vert_angs[ed->v1] = max_ff(vert_angs[ed->v1], angle);
+ vert_angs[ed->v2] = max_ff(vert_angs[ed->v2], angle);
+ }
+ }
+ MEM_freeN(edge_user_pairs);
+
+ for (i = 0; i < numVerts; i++) {
+ float cos_ang = cosf(vert_angs[i] * 0.5f);
+ if (cos_ang > 0) {
+ float max_off = sqrtf(vert_lens_sq[i]) * 0.5f / cos_ang;
+ if (max_off < offset * 0.5f) {
+ vert_angles[i] *= max_off / offset * 2;
+ }
+ }
+ }
+ MEM_freeN(vert_angs);
+ }
+ else {
+ for (i = 0; i < numVerts; i++) {
+ if (vert_lens_sq[i] < offset_sq) {
+ float scalar = sqrtf(vert_lens_sq[i]) / offset;
+ vert_angles[i] *= scalar;
+ }
+ }
+ }
+ MEM_freeN(vert_lens_sq);
+ }
+ }
+
+#undef INVALID_UNUSED
+#undef INVALID_PAIR
+
+ if (ofs_new != 0.0f) {
+ uint i_orig, i_end;
+ bool do_shell_align;
+
+ INIT_VERT_ARRAY_OFFSETS(false);
+
+ for (i_orig = 0; i_orig < i_end; i_orig++, mv++) {
+ const uint i_other = do_shell_align ? i_orig : new_vert_arr[i_orig];
+ if (vert_accum[i_other]) { /* zero if unselected */
+ madd_v3_v3fl(
+ mv->co, vert_nors[i_other], ofs_new * (vert_angles[i_other] / vert_accum[i_other]));
+ }
+ }
+ }
+
+ if (ofs_orig != 0.0f) {
+ uint i_orig, i_end;
+ bool do_shell_align;
+
+ /* same as above but swapped, intentional use of 'ofs_new' */
+ INIT_VERT_ARRAY_OFFSETS(true);
+
+ for (i_orig = 0; i_orig < i_end; i_orig++, mv++) {
+ const uint i_other = do_shell_align ? i_orig : new_vert_arr[i_orig];
+ if (vert_accum[i_other]) { /* zero if unselected */
+ madd_v3_v3fl(
+ mv->co, vert_nors[i_other], ofs_orig * (vert_angles[i_other] / vert_accum[i_other]));
+ }
+ }
+ }
+
+ MEM_freeN(vert_angles);
+ }
+
+ if (vert_nors) {
+ MEM_freeN(vert_nors);
+ }
+
+ /* must recalculate normals with vgroups since they can displace unevenly [#26888] */
+ if ((mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) || (smd->flag & MOD_SOLIDIFY_RIM) || dvert) {
+ result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+ }
+ else if (do_shell) {
+ uint i;
+ /* flip vertex normals for copied verts */
+ mv = mvert + numVerts;
+ for (i = 0; i < numVerts; i++, mv++) {
+ negate_v3_short(mv->no);
+ }
+ }
+
+ if (smd->flag & MOD_SOLIDIFY_RIM) {
+ uint i;
+
+ /* bugger, need to re-calculate the normals for the new edge faces.
+ * This could be done in many ways, but probably the quickest way
+ * is to calculate the average normals for side faces only.
+ * Then blend them with the normals of the edge verts.
+ *
+ * at the moment its easiest to allocate an entire array for every vertex,
+ * even though we only need edge verts - campbell
+ */
+
+#define SOLIDIFY_SIDE_NORMALS
+
+#ifdef SOLIDIFY_SIDE_NORMALS
+ /* Note that, due to the code setting cd_dirty_vert a few lines above,
+ * do_side_normals is always false. - Sybren */
+ const bool do_side_normals = !(result->runtime.cd_dirty_vert & CD_MASK_NORMAL);
+ /* annoying to allocate these since we only need the edge verts, */
+ float(*edge_vert_nos)[3] = do_side_normals ?
+ MEM_calloc_arrayN(numVerts, 3 * sizeof(float), __func__) :
+ NULL;
+ float nor[3];
+#endif
+ const uchar crease_rim = smd->crease_rim * 255.0f;
+ const uchar crease_outer = smd->crease_outer * 255.0f;
+ const uchar crease_inner = smd->crease_inner * 255.0f;
+
+ int *origindex_edge;
+ int *orig_ed;
+ uint j;
+
+ if (crease_rim || crease_outer || crease_inner) {
+ result->cd_flag |= ME_CDFLAG_EDGE_CREASE;
+ }
+
+ /* add faces & edges */
+ origindex_edge = CustomData_get_layer(&result->edata, CD_ORIGINDEX);
+ orig_ed = (origindex_edge) ? &origindex_edge[(numEdges * stride) + newEdges] : NULL;
+ ed = &medge[(numEdges * stride) + newEdges]; /* start after copied edges */
+ for (i = 0; i < rimVerts; i++, ed++) {
+ ed->v1 = new_vert_arr[i];
+ ed->v2 = (do_shell ? new_vert_arr[i] : i) + numVerts;
+ ed->flag |= ME_EDGEDRAW | ME_EDGERENDER;
+
+ if (orig_ed) {
+ *orig_ed = ORIGINDEX_NONE;
+ orig_ed++;
+ }
+
+ if (crease_rim) {
+ ed->crease = crease_rim;
+ }
+ }
+
+ /* faces */
+ mp = mpoly + (numPolys * stride);
+ ml = mloop + (numLoops * stride);
+ j = 0;
+ for (i = 0; i < newPolys; i++, mp++) {
+ uint eidx = new_edge_arr[i];
+ uint pidx = edge_users[eidx];
+ int k1, k2;
+ bool flip;
+
+ if (pidx >= numPolys) {
+ pidx -= numPolys;
+ flip = true;
+ }
+ else {
+ flip = false;
+ }
+
+ ed = medge + eidx;
+
+ /* copy most of the face settings */
+ CustomData_copy_data(
+ &mesh->pdata, &result->pdata, (int)pidx, (int)((numPolys * stride) + i), 1);
+ mp->loopstart = (int)(j + (numLoops * stride));
+ mp->flag = mpoly[pidx].flag;
+
+ /* notice we use 'mp->totloop' which is later overwritten,
+ * we could lookup the original face but there's no point since this is a copy
+ * and will have the same value, just take care when changing order of assignment */
+
+ /* prev loop */
+ k1 = mpoly[pidx].loopstart + (((edge_order[eidx] - 1) + mp->totloop) % mp->totloop);
+
+ k2 = mpoly[pidx].loopstart + (edge_order[eidx]);
+
+ mp->totloop = 4;
+
+ CustomData_copy_data(
+ &mesh->ldata, &result->ldata, k2, (int)((numLoops * stride) + j + 0), 1);
+ CustomData_copy_data(
+ &mesh->ldata, &result->ldata, k1, (int)((numLoops * stride) + j + 1), 1);
+ CustomData_copy_data(
+ &mesh->ldata, &result->ldata, k1, (int)((numLoops * stride) + j + 2), 1);
+ CustomData_copy_data(
+ &mesh->ldata, &result->ldata, k2, (int)((numLoops * stride) + j + 3), 1);
+
+ if (flip == false) {
+ ml[j].v = ed->v1;
+ ml[j++].e = eidx;
+
+ ml[j].v = ed->v2;
+ ml[j++].e = (numEdges * stride) + old_vert_arr[ed->v2] + newEdges;
+
+ ml[j].v = (do_shell ? ed->v2 : old_vert_arr[ed->v2]) + numVerts;
+ ml[j++].e = (do_shell ? eidx : i) + numEdges;
+
+ ml[j].v = (do_shell ? ed->v1 : old_vert_arr[ed->v1]) + numVerts;
+ ml[j++].e = (numEdges * stride) + old_vert_arr[ed->v1] + newEdges;
+ }
+ else {
+ ml[j].v = ed->v2;
+ ml[j++].e = eidx;
+
+ ml[j].v = ed->v1;
+ ml[j++].e = (numEdges * stride) + old_vert_arr[ed->v1] + newEdges;
+
+ ml[j].v = (do_shell ? ed->v1 : old_vert_arr[ed->v1]) + numVerts;
+ ml[j++].e = (do_shell ? eidx : i) + numEdges;
+
+ ml[j].v = (do_shell ? ed->v2 : old_vert_arr[ed->v2]) + numVerts;
+ ml[j++].e = (numEdges * stride) + old_vert_arr[ed->v2] + newEdges;
+ }
+
+ if (origindex_edge) {
+ origindex_edge[ml[j - 3].e] = ORIGINDEX_NONE;
+ origindex_edge[ml[j - 1].e] = ORIGINDEX_NONE;
+ }
+
+ /* use the next material index if option enabled */
+ if (mat_ofs_rim) {
+ mp->mat_nr += mat_ofs_rim;
+ CLAMP(mp->mat_nr, 0, mat_nr_max);
+ }
+ if (crease_outer) {
+ /* crease += crease_outer; without wrapping */
+ char *cr = &(ed->crease);
+ int tcr = *cr + crease_outer;
+ *cr = tcr > 255 ? 255 : tcr;
+ }
+
+ if (crease_inner) {
+ /* crease += crease_inner; without wrapping */
+ char *cr = &(medge[numEdges + (do_shell ? eidx : i)].crease);
+ int tcr = *cr + crease_inner;
+ *cr = tcr > 255 ? 255 : tcr;
+ }
+
+#ifdef SOLIDIFY_SIDE_NORMALS
+ if (do_side_normals) {
+ normal_quad_v3(nor,
+ mvert[ml[j - 4].v].co,
+ mvert[ml[j - 3].v].co,
+ mvert[ml[j - 2].v].co,
+ mvert[ml[j - 1].v].co);
+
+ add_v3_v3(edge_vert_nos[ed->v1], nor);
+ add_v3_v3(edge_vert_nos[ed->v2], nor);
+ }
+#endif
+ }
+
+#ifdef SOLIDIFY_SIDE_NORMALS
+ if (do_side_normals) {
+ const MEdge *ed_orig = medge;
+ ed = medge + (numEdges * stride);
+ for (i = 0; i < rimVerts; i++, ed++, ed_orig++) {
+ float nor_cpy[3];
+ short *nor_short;
+ int k;
+
+ /* note, only the first vertex (lower half of the index) is calculated */
+ BLI_assert(ed->v1 < numVerts);
+ normalize_v3_v3(nor_cpy, edge_vert_nos[ed_orig->v1]);
+
+ for (k = 0; k < 2; k++) { /* loop over both verts of the edge */
+ nor_short = mvert[*(&ed->v1 + k)].no;
+ normal_short_to_float_v3(nor, nor_short);
+ add_v3_v3(nor, nor_cpy);
+ normalize_v3(nor);
+ normal_float_to_short_v3(nor_short, nor);
+ }
+ }
+
+ MEM_freeN(edge_vert_nos);
+ }
+#endif
+
+ MEM_freeN(new_vert_arr);
+ MEM_freeN(new_edge_arr);
+
+ MEM_freeN(edge_users);
+ MEM_freeN(edge_order);
+ }
+
+ if (old_vert_arr) {
+ MEM_freeN(old_vert_arr);
+ }
+
+ if (poly_nors) {
+ MEM_freeN(poly_nors);
+ }
+
+ if (numPolys == 0 && numVerts != 0) {
+ modifier_setError(md, "Faces needed for useful output");
+ }
+
+ return result;
+}
+
+#undef SOLIDIFY_SIDE_NORMALS
+
+/** \} */
diff --git a/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c b/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c
new file mode 100644
index 00000000000..be7bbb86e4d
--- /dev/null
+++ b/source/blender/modifiers/intern/MOD_solidify_nonmanifold.c
@@ -0,0 +1,2268 @@
+/*
+ * 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.
+ */
+
+/** \file
+ * \ingroup modifiers
+ */
+
+#include "BLI_utildefines.h"
+
+#include "BLI_math.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BKE_mesh.h"
+#include "BKE_particle.h"
+#include "BKE_deform.h"
+
+#include "MOD_modifiertypes.h"
+#include "MOD_util.h"
+#include "MOD_solidify_util.h" /* Own include. */
+
+#ifdef __GNUC__
+# pragma GCC diagnostic error "-Wsign-conversion"
+#endif
+
+/* -------------------------------------------------------------------- */
+/** \name Local Utilities
+ * \{ */
+
+/**
+ * Similar to #project_v3_v3v3_normalized that returns the dot-product.
+ */
+static float project_v3_v3(float r[3], const float a[3])
+{
+ float d = dot_v3v3(r, a);
+ r[0] -= a[0] * d;
+ r[1] -= a[1] * d;
+ r[2] -= a[2] * d;
+ return d;
+}
+
+static float angle_signed_on_axis_normalized_v3v3_v3(const float n[3],
+ const float ref_n[3],
+ const float axis[3])
+{
+ float d = dot_v3v3(n, ref_n);
+ CLAMP(d, -1, 1);
+ float angle = acosf(d);
+ float cross[3];
+ cross_v3_v3v3(cross, n, ref_n);
+ if (dot_v3v3(cross, axis) >= 0) {
+ angle = 2 * M_PI - angle;
+ }
+ return angle;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Main Solidify Function
+ * \{ */
+
+/* Data structures for manifold solidify. */
+
+typedef struct NewFaceRef {
+ MPoly *face;
+ uint index;
+ bool reversed;
+ struct NewEdgeRef **link_edges;
+} NewFaceRef;
+
+typedef struct OldEdgeFaceRef {
+ uint *faces;
+ uint faces_len;
+ bool *faces_reversed;
+ uint used;
+} OldEdgeFaceRef;
+
+typedef struct OldVertEdgeRef {
+ uint *edges;
+ uint edges_len;
+} OldVertEdgeRef;
+
+typedef struct NewEdgeRef {
+ uint old_edge;
+ NewFaceRef *faces[2];
+ struct EdgeGroup *link_edge_groups[2];
+ float angle;
+ uint new_edge;
+} NewEdgeRef;
+
+typedef struct EdgeGroup {
+ bool valid;
+ NewEdgeRef **edges;
+ uint edges_len;
+ uint open_face_edge;
+ bool is_orig_closed;
+ bool is_even_split;
+ uint split;
+ bool is_singularity;
+ uint topo_group;
+ float co[3];
+ float no[3];
+ uint new_vert;
+} EdgeGroup;
+
+typedef struct FaceKeyPair {
+ float angle;
+ NewFaceRef *face;
+} FaceKeyPair;
+
+static int comp_float_int_pair(const void *a, const void *b)
+{
+ FaceKeyPair *x = (FaceKeyPair *)a;
+ FaceKeyPair *y = (FaceKeyPair *)b;
+ return (int)(x->angle > y->angle) - (int)(x->angle < y->angle);
+}
+
+Mesh *MOD_solidify_nonmanifold_applyModifier(ModifierData *md,
+ const ModifierEvalContext *ctx,
+ Mesh *mesh)
+{
+ Mesh *result;
+ const SolidifyModifierData *smd = (SolidifyModifierData *)md;
+
+ MVert *mv, *mvert, *orig_mvert;
+ MEdge *ed, *medge, *orig_medge;
+ MLoop *ml, *mloop, *orig_mloop;
+ MPoly *mp, *mpoly, *orig_mpoly;
+ const uint numVerts = (uint)mesh->totvert;
+ const uint numEdges = (uint)mesh->totedge;
+ const uint numPolys = (uint)mesh->totpoly;
+ const uint numLoops = (uint)mesh->totloop;
+
+ if (numPolys == 0 && numVerts != 0) {
+ modifier_setError(md, "Faces needed for useful output");
+ return mesh;
+ }
+
+ /* Only use material offsets if we have 2 or more materials. */
+ const short mat_nrs = ctx->object->totcol > 1 ? ctx->object->totcol : 1;
+ const short mat_nr_max = mat_nrs - 1;
+ const short mat_ofs = mat_nrs > 1 ? smd->mat_ofs : 0;
+ const short mat_ofs_rim = mat_nrs > 1 ? smd->mat_ofs_rim : 0;
+
+ float(*poly_nors)[3] = NULL;
+
+ const float ofs_front = (smd->offset_fac + 1.0f) * 0.5f * smd->offset;
+ const float ofs_back = ofs_front - smd->offset * smd->offset_fac;
+ const float offset_fac_vg = smd->offset_fac_vg;
+ const float offset_fac_vg_inv = 1.0f - smd->offset_fac_vg;
+ const float offset = fabsf(smd->offset) * smd->offset_clamp;
+ const bool do_angle_clamp = smd->flag & MOD_SOLIDIFY_OFFSET_ANGLE_CLAMP;
+ const bool do_flip = (smd->flag & MOD_SOLIDIFY_FLIP) != 0;
+ const bool do_rim = smd->flag & MOD_SOLIDIFY_RIM;
+ const bool do_shell = ((smd->flag & MOD_SOLIDIFY_RIM) && (smd->flag & MOD_SOLIDIFY_NOSHELL)) ==
+ 0;
+ const bool do_clamp = (smd->offset_clamp != 0.0f);
+
+ MDeformVert *dvert;
+ const bool defgrp_invert = (smd->flag & MOD_SOLIDIFY_VGROUP_INV) != 0;
+ int defgrp_index;
+
+ MOD_get_vgroup(ctx->object, mesh, smd->defgrp_name, &dvert, &defgrp_index);
+
+ orig_mvert = mesh->mvert;
+ orig_medge = mesh->medge;
+ orig_mloop = mesh->mloop;
+ orig_mpoly = mesh->mpoly;
+
+ uint numNewVerts = 0;
+ uint numNewEdges = 0;
+ uint numNewLoops = 0;
+ uint numNewPolys = 0;
+
+#define MOD_SOLIDIFY_EMPTY_TAG ((uint)-1)
+
+ /* Calculate only face normals. */
+ poly_nors = MEM_malloc_arrayN(numPolys, sizeof(*poly_nors), __func__);
+ BKE_mesh_calc_normals_poly(orig_mvert,
+ NULL,
+ (int)numVerts,
+ orig_mloop,
+ orig_mpoly,
+ (int)numLoops,
+ (int)numPolys,
+ poly_nors,
+ true);
+
+ NewFaceRef *face_sides_arr = MEM_malloc_arrayN(
+ numPolys * 2, sizeof(*face_sides_arr), "face_sides_arr in solidify");
+ bool *null_faces =
+ (smd->nonmanifold_offset_mode == MOD_SOLIDIFY_NONMANIFOLD_OFFSET_MODE_CONSTRAINTS) ?
+ MEM_calloc_arrayN(numPolys, sizeof(*null_faces), "null_faces in solidify") :
+ NULL;
+ uint largest_ngon = 3;
+ /* Calculate face to #NewFaceRef map. */
+ {
+ mp = orig_mpoly;
+ for (uint i = 0; i < numPolys; i++, mp++) {
+ /* Make normals for faces without area (should really be avoided though). */
+ if (len_squared_v3(poly_nors[i]) < 0.5f) {
+ MEdge *e = orig_medge + orig_mloop[mp->loopstart].e;
+ float edgedir[3];
+ sub_v3_v3v3(edgedir, orig_mvert[e->v2].co, orig_mvert[e->v1].co);
+ if (fabsf(edgedir[2]) < fabsf(edgedir[1])) {
+ poly_nors[i][2] = 1.0f;
+ }
+ else {
+ poly_nors[i][1] = 1.0f;
+ }
+ if (null_faces) {
+ null_faces[i] = true;
+ }
+ }
+
+ NewEdgeRef **link_edges = MEM_calloc_arrayN(
+ (uint)mp->totloop, sizeof(*link_edges), "NewFaceRef::link_edges in solidify");
+ face_sides_arr[i * 2] = (NewFaceRef){
+ .face = mp, .index = i, .reversed = false, .link_edges = link_edges};
+ link_edges = MEM_calloc_arrayN(
+ (uint)mp->totloop, sizeof(*link_edges), "NewFaceRef::link_edges in solidify");
+ face_sides_arr[i * 2 + 1] = (NewFaceRef){
+ .face = mp, .index = i, .reversed = true, .link_edges = link_edges};
+ if (mp->totloop > largest_ngon) {
+ largest_ngon = (uint)mp->totloop;
+ }
+ if (do_shell) {
+ numNewPolys += 2;
+ numNewLoops += (uint)mp->totloop * 2;
+ }
+ }
+ }
+
+ uint *edge_adj_faces_len = MEM_calloc_arrayN(
+ numEdges, sizeof(*edge_adj_faces_len), "edge_adj_faces_len in solidify");
+ /* Count for each edge how many faces it has adjacent. */
+ {
+ mp = orig_mpoly;
+ for (uint i = 0; i < numPolys; i++, mp++) {
+ ml = orig_mloop + mp->loopstart;
+ for (uint j = 0; j < mp->totloop; j++, ml++) {
+ edge_adj_faces_len[ml->e]++;
+ }
+ }
+ }
+
+ /* Original edge to #NewEdgeRef map. */
+ NewEdgeRef ***orig_edge_data_arr = MEM_calloc_arrayN(
+ numEdges, sizeof(*orig_edge_data_arr), "orig_edge_data_arr in solidify");
+ /* Original edge length cache. */
+ float *orig_edge_lengths = MEM_calloc_arrayN(
+ numEdges, sizeof(*orig_edge_lengths), "orig_edge_lengths in solidify");
+ /* Edge groups for every original vert. */
+ EdgeGroup **orig_vert_groups_arr = MEM_calloc_arrayN(
+ numVerts, sizeof(*orig_vert_groups_arr), "orig_vert_groups_arr in solidify");
+ /* Duplicate verts map. */
+ uint *vm = MEM_malloc_arrayN(numVerts, sizeof(*vm), "orig_vert_map in solidify");
+ for (uint i = 0; i < numVerts; i++) {
+ vm[i] = i;
+ }
+
+ uint edge_index = 0;
+ uint loop_index = 0;
+ uint poly_index = 0;
+
+ bool has_singularities = false;
+
+ /* Vert edge adjacent map. */
+ uint *vert_adj_edges_len = MEM_calloc_arrayN(
+ numVerts, sizeof(*vert_adj_edges_len), "vert_adj_edges_len in solidify");
+ OldVertEdgeRef **vert_adj_edges = MEM_calloc_arrayN(
+ numVerts, sizeof(*vert_adj_edges), "vert_adj_edges in solidify");
+
+ /* Create edge to #NewEdgeRef map. */
+ {
+ OldEdgeFaceRef **edge_adj_faces = MEM_calloc_arrayN(
+ numEdges, sizeof(*edge_adj_faces), "edge_adj_faces in solidify");
+
+ /* Create link_faces for edges. */
+ {
+ mp = orig_mpoly;
+ for (uint i = 0; i < numPolys; i++, mp++) {
+ ml = orig_mloop + mp->loopstart;
+ for (uint j = 0; j < mp->totloop; j++, ml++) {
+ const uint edge = ml->e;
+ const bool reversed = orig_medge[edge].v2 != ml->v;
+ OldEdgeFaceRef *old_face_edge_ref = edge_adj_faces[edge];
+ if (old_face_edge_ref == NULL) {
+ const uint len = edge_adj_faces_len[edge];
+ BLI_assert(len > 0);
+ uint *adj_faces = MEM_malloc_arrayN(
+ len, sizeof(*adj_faces), "OldEdgeFaceRef::faces in solidify");
+ bool *adj_faces_loops_reversed = MEM_malloc_arrayN(
+ len, sizeof(*adj_faces_loops_reversed), "OldEdgeFaceRef::reversed in solidify");
+ adj_faces[0] = i;
+ for (uint k = 1; k < len; k++) {
+ adj_faces[k] = MOD_SOLIDIFY_EMPTY_TAG;
+ }
+ adj_faces_loops_reversed[0] = reversed;
+ OldEdgeFaceRef *ref = MEM_mallocN(sizeof(*ref), "OldEdgeFaceRef in solidify");
+ *ref = (OldEdgeFaceRef){adj_faces, len, adj_faces_loops_reversed, 1};
+ edge_adj_faces[edge] = ref;
+ }
+ else {
+ for (uint k = 1; k < old_face_edge_ref->faces_len; k++) {
+ if (old_face_edge_ref->faces[k] == MOD_SOLIDIFY_EMPTY_TAG) {
+ old_face_edge_ref->faces[k] = i;
+ old_face_edge_ref->faces_reversed[k] = reversed;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ float edgedir[3] = {0, 0, 0};
+
+ /* Calculate edge lengths and len vert_adj edges. */
+ {
+ bool *face_singularity = MEM_calloc_arrayN(
+ numPolys, sizeof(*face_singularity), "face_sides_arr in solidify");
+ ed = orig_medge;
+ for (uint i = 0; i < numEdges; i++, ed++) {
+ if (edge_adj_faces_len[i] > 0) {
+ const uint v1 = vm[ed->v1];
+ const uint v2 = vm[ed->v2];
+ if (v1 != v2) {
+ sub_v3_v3v3(edgedir, orig_mvert[v2].co, orig_mvert[v1].co);
+ orig_edge_lengths[i] = len_squared_v3(edgedir);
+ }
+ if (v1 == v2 || orig_edge_lengths[i] <= FLT_EPSILON) {
+ if (v2 > v1) {
+ for (uint j = v2; j < numVerts; j++) {
+ if (vm[j] == v2) {
+ vm[j] = v1;
+ vert_adj_edges_len[v1] += vert_adj_edges_len[j];
+ vert_adj_edges_len[j] = 0;
+ }
+ }
+ }
+ else if (v2 < v1) {
+ for (uint j = v1; j < numVerts; j++) {
+ if (vm[j] == v1) {
+ vm[j] = v2;
+ vert_adj_edges_len[v2] += vert_adj_edges_len[j];
+ vert_adj_edges_len[j] = 0;
+ }
+ }
+ }
+ if (do_shell) {
+ numNewLoops -= edge_adj_faces_len[i] * 2;
+ }
+ if (v1 == v2) {
+ /* Remove polys. */
+ for (uint j = 0; j < edge_adj_faces[i]->faces_len; j++) {
+ const uint face = edge_adj_faces[i]->faces[j];
+ if (!face_singularity[face]) {
+ bool is_singularity = true;
+ for (uint k = 0; k < orig_mpoly[face].totloop; k++) {
+ if (vm[orig_mloop[((uint)orig_mpoly[face].loopstart) + k].v] != v1) {
+ is_singularity = false;
+ break;
+ }
+ }
+ if (is_singularity) {
+ face_singularity[face] = true;
+ if (do_shell) {
+ numNewPolys -= 2;
+ }
+ }
+ }
+ }
+ }
+ edge_adj_faces_len[i] = 0;
+ MEM_freeN(edge_adj_faces[i]->faces);
+ MEM_freeN(edge_adj_faces[i]->faces_reversed);
+ MEM_freeN(edge_adj_faces[i]);
+ edge_adj_faces[i] = NULL;
+ }
+ else if (edge_adj_faces_len[i] > 0) {
+ orig_edge_lengths[i] = sqrtf(orig_edge_lengths[i]);
+ vert_adj_edges_len[v1]++;
+ vert_adj_edges_len[v2]++;
+ }
+ }
+ }
+ MEM_freeN(face_singularity);
+ }
+
+ /* Create vert_adj_edges for verts. */
+ {
+ ed = orig_medge;
+ for (uint i = 0; i < numEdges; i++, ed++) {
+ if (edge_adj_faces_len[i] > 0) {
+ const uint vs[2] = {vm[ed->v1], vm[ed->v2]};
+ uint invalid_edge_index = 0;
+ bool invalid_edge_reversed = false;
+ for (uint j = 0; j < 2; j++) {
+ const uint vert = vs[j];
+ const uint len = vert_adj_edges_len[vert];
+ if (len > 0) {
+ OldVertEdgeRef *old_edge_vert_ref = vert_adj_edges[vert];
+ if (old_edge_vert_ref == NULL) {
+ uint *adj_edges = MEM_calloc_arrayN(
+ len, sizeof(*adj_edges), "OldVertEdgeRef::edges in solidify");
+ adj_edges[0] = i;
+ for (uint k = 1; k < len; k++) {
+ adj_edges[k] = MOD_SOLIDIFY_EMPTY_TAG;
+ }
+ OldVertEdgeRef *ref = MEM_mallocN(sizeof(*ref), "OldVertEdgeRef in solidify");
+ *ref = (OldVertEdgeRef){adj_edges, 1};
+ vert_adj_edges[vert] = ref;
+ }
+ else {
+ const uint *f = old_edge_vert_ref->edges;
+ for (uint k = 0; k < len && k <= old_edge_vert_ref->edges_len; k++, f++) {
+ const uint edge = old_edge_vert_ref->edges[k];
+ if (edge == MOD_SOLIDIFY_EMPTY_TAG || k == old_edge_vert_ref->edges_len) {
+ old_edge_vert_ref->edges[k] = i;
+ old_edge_vert_ref->edges_len++;
+ break;
+ }
+ else if (vm[orig_medge[edge].v1] == vs[1 - j]) {
+ invalid_edge_index = edge + 1;
+ invalid_edge_reversed = (j == 0);
+ break;
+ }
+ else if (vm[orig_medge[edge].v2] == vs[1 - j]) {
+ invalid_edge_index = edge + 1;
+ invalid_edge_reversed = (j == 1);
+ break;
+ }
+ }
+ if (invalid_edge_index) {
+ /* Should never actually be executed. */
+ if (j == 1) {
+ vert_adj_edges[vs[0]]->edges_len--;
+ }
+ break;
+ }
+ }
+ }
+ }
+ if (invalid_edge_index) {
+ const uint tmp = invalid_edge_index - 1;
+ invalid_edge_index = i;
+ i = tmp;
+ OldEdgeFaceRef *i_adj_faces = edge_adj_faces[i];
+ OldEdgeFaceRef *invalid_adj_faces = edge_adj_faces[invalid_edge_index];
+ uint j = 0;
+ for (uint k = 0; k < i_adj_faces->faces_len; k++) {
+ for (uint l = 0; l < invalid_adj_faces->faces_len; l++) {
+ if (i_adj_faces->faces[k] == invalid_adj_faces->faces[l] &&
+ i_adj_faces->faces[k] != MOD_SOLIDIFY_EMPTY_TAG) {
+ i_adj_faces->faces[k] = MOD_SOLIDIFY_EMPTY_TAG;
+ invalid_adj_faces->faces[l] = MOD_SOLIDIFY_EMPTY_TAG;
+ j++;
+ }
+ }
+ }
+ if (do_shell) {
+ numNewPolys -= 2 * j;
+ numNewLoops -= 4 * j;
+ }
+ const uint len = i_adj_faces->faces_len + invalid_adj_faces->faces_len - 2 * j;
+ uint *adj_faces = MEM_malloc_arrayN(
+ len, sizeof(*adj_faces), "OldEdgeFaceRef::faces in solidify");
+ bool *adj_faces_loops_reversed = MEM_malloc_arrayN(
+ len, sizeof(*adj_faces_loops_reversed), "OldEdgeFaceRef::reversed in solidify");
+ j = 0;
+ for (uint k = 0; k < i_adj_faces->faces_len; k++) {
+ if (i_adj_faces->faces[k] != MOD_SOLIDIFY_EMPTY_TAG) {
+ adj_faces[j] = i_adj_faces->faces[k];
+ adj_faces_loops_reversed[j++] = i_adj_faces->faces_reversed[k];
+ }
+ }
+ for (uint k = 0; k < invalid_adj_faces->faces_len; k++) {
+ if (invalid_adj_faces->faces[k] != MOD_SOLIDIFY_EMPTY_TAG) {
+ adj_faces[j] = invalid_adj_faces->faces[k];
+ adj_faces_loops_reversed[j++] = (invalid_edge_reversed !=
+ invalid_adj_faces->faces_reversed[k]);
+ }
+ }
+ BLI_assert(j == len);
+ edge_adj_faces_len[invalid_edge_index] = 0;
+ edge_adj_faces_len[i] = len;
+ MEM_freeN(i_adj_faces->faces);
+ MEM_freeN(i_adj_faces->faces_reversed);
+ i_adj_faces->faces_len = len;
+ i_adj_faces->faces = adj_faces;
+ i_adj_faces->faces_reversed = adj_faces_loops_reversed;
+ i_adj_faces->used += invalid_adj_faces->used;
+ MEM_freeN(invalid_adj_faces->faces);
+ MEM_freeN(invalid_adj_faces->faces_reversed);
+ MEM_freeN(invalid_adj_faces);
+ edge_adj_faces[invalid_edge_index] = i_adj_faces;
+ /* Reset counter to continue. */
+ i = invalid_edge_index;
+ }
+ }
+ }
+ }
+
+ /* Filter duplicate polys. */
+ {
+ ed = orig_medge;
+ for (uint i = 0; i < numEdges; i++, ed++) {
+ if (edge_adj_faces_len[i] > 0) {
+ const OldEdgeFaceRef *adj_faces = edge_adj_faces[i];
+ uint adj_len = adj_faces->faces_len;
+ if (adj_len > 1) {
+ /* For each face pair check if they have equal verts. */
+ for (uint j = 0; j < adj_len; j++) {
+ const uint face = adj_faces->faces[j];
+ const int j_loopstart = orig_mpoly[face].loopstart;
+ const int totloop = orig_mpoly[face].totloop;
+ const uint j_first_v = vm[orig_mloop[j_loopstart].v];
+ for (uint k = j + 1; k < adj_len; k++) {
+ if (orig_mpoly[adj_faces->faces[k]].totloop != totloop) {
+ continue;
+ }
+ /* Find first face first loop vert in second face loops. */
+ const int k_loopstart = orig_mpoly[adj_faces->faces[k]].loopstart;
+ int l;
+ ml = orig_mloop + k_loopstart;
+ for (l = 0; l < totloop && vm[ml->v] != j_first_v; l++, ml++) {
+ /* Pass. */
+ }
+ if (l == totloop) {
+ continue;
+ }
+ /* Check if all following loops have equal verts. */
+ const bool reversed = adj_faces->faces_reversed[j] != adj_faces->faces_reversed[k];
+ const int count_dir = reversed ? -1 : 1;
+ bool has_diff = false;
+ ml = orig_mloop + j_loopstart;
+ for (int m = 0, n = l + totloop; m < totloop && !has_diff;
+ m++, n += count_dir, ml++) {
+ has_diff = has_diff || vm[ml->v] != vm[orig_mloop[k_loopstart + n % totloop].v];
+ }
+ /* If the faces are equal, discard one (j). */
+ if (!has_diff) {
+ ml = orig_mloop + j_loopstart;
+ uint del_loops = 0;
+ for (uint m = 0; m < totloop; m++, ml++) {
+ const uint e = ml->e;
+ uint face_index = j;
+ uint *e_adj_faces_faces = edge_adj_faces[e]->faces;
+ bool *e_adj_faces_reversed = edge_adj_faces[e]->faces_reversed;
+ const uint faces_len = edge_adj_faces[e]->faces_len;
+ if (e != i) {
+ /* Find index of e in #adj_faces. */
+ for (face_index = 0;
+ face_index < faces_len && e_adj_faces_faces[face_index] != face;
+ face_index++) {
+ /* Pass. */
+ }
+ /* If not found. */
+ if (face_index == faces_len) {
+ continue;
+ }
+ }
+ else {
+ adj_len--;
+ }
+ memmove(e_adj_faces_faces + face_index,
+ e_adj_faces_faces + face_index + 1,
+ (faces_len - face_index - 1) * sizeof(*e_adj_faces_faces));
+ memmove(e_adj_faces_reversed + face_index,
+ e_adj_faces_reversed + face_index + 1,
+ (faces_len - face_index - 1) * sizeof(*e_adj_faces_reversed));
+ edge_adj_faces[e]->faces_len--;
+ if (edge_adj_faces_len[e] > 0) {
+ edge_adj_faces_len[e]--;
+ if (edge_adj_faces_len[e] == 0) {
+ edge_adj_faces[e]->used--;
+ edge_adj_faces[e] = NULL;
+ }
+ }
+ del_loops++;
+ }
+ if (do_shell) {
+ numNewPolys -= 2;
+ numNewLoops -= 2 * (uint)del_loops;
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* Create #NewEdgeRef array. */
+ {
+ ed = orig_medge;
+ for (uint i = 0; i < numEdges; i++, ed++) {
+ const uint v1 = vm[ed->v1];
+ const uint v2 = vm[ed->v2];
+ if (edge_adj_faces_len[i] > 0) {
+ sub_v3_v3v3(edgedir, orig_mvert[v2].co, orig_mvert[v1].co);
+ mul_v3_fl(edgedir, 1.0f / orig_edge_lengths[i]);
+
+ OldEdgeFaceRef *adj_faces = edge_adj_faces[i];
+ const uint adj_len = adj_faces->faces_len;
+ const uint *adj_faces_faces = adj_faces->faces;
+ const bool *adj_faces_reversed = adj_faces->faces_reversed;
+ uint new_edges_len = 0;
+ FaceKeyPair *sorted_faces = MEM_malloc_arrayN(
+ adj_len, sizeof(*sorted_faces), "sorted_faces in solidify");
+ if (adj_len > 1) {
+ new_edges_len = adj_len;
+ /* Get keys for sorting. */
+ float ref_nor[3] = {0, 0, 0};
+ float nor[3];
+ for (uint j = 0; j < adj_len; j++) {
+ const bool reverse = adj_faces_reversed[j];
+ const uint face_i = adj_faces_faces[j];
+ if (reverse) {
+ negate_v3_v3(nor, poly_nors[face_i]);
+ }
+ else {
+ copy_v3_v3(nor, poly_nors[face_i]);
+ }
+ float d = 1;
+ if (orig_mpoly[face_i].totloop > 3) {
+ d = project_v3_v3(nor, edgedir);
+ if (LIKELY(d != 0)) {
+ d = normalize_v3(nor);
+ }
+ else {
+ d = 1;
+ }
+ }
+ if (UNLIKELY(d == 0.0f)) {
+ sorted_faces[j].angle = 0.0f;
+ }
+ else if (j == 0) {
+ copy_v3_v3(ref_nor, nor);
+ sorted_faces[j].angle = 0.0f;
+ }
+ else {
+ float angle = angle_signed_on_axis_normalized_v3v3_v3(nor, ref_nor, edgedir);
+ sorted_faces[j].angle = -angle;
+ }
+ sorted_faces[j].face = face_sides_arr + adj_faces_faces[j] * 2 +
+ (adj_faces_reversed[j] ? 1 : 0);
+ }
+ /* Sort faces by order around the edge (keep order in faces,
+ * reversed and face_angles the same). */
+ qsort(sorted_faces, adj_len, sizeof(*sorted_faces), comp_float_int_pair);
+ }
+ else {
+ new_edges_len = 2;
+ sorted_faces[0].face = face_sides_arr + adj_faces_faces[0] * 2 +
+ (adj_faces_reversed[0] ? 1 : 0);
+ if (do_rim) {
+ /* Only add the loops parallel to the edge for now. */
+ numNewLoops += 2;
+ numNewPolys++;
+ }
+ }
+
+ /* Create a list of new edges and fill it. */
+ NewEdgeRef **new_edges = MEM_malloc_arrayN(
+ new_edges_len + 1, sizeof(*new_edges), "new_edges in solidify");
+ new_edges[new_edges_len] = NULL;
+ NewFaceRef *faces[2];
+ for (uint j = 0; j < new_edges_len; j++) {
+ float angle;
+ if (adj_len > 1) {
+ const uint next_j = j + 1 == adj_len ? 0 : j + 1;
+ faces[0] = sorted_faces[j].face;
+ faces[1] = sorted_faces[next_j].face->reversed ? sorted_faces[next_j].face - 1 :
+ sorted_faces[next_j].face + 1;
+ angle = sorted_faces[next_j].angle - sorted_faces[j].angle;
+ if (angle < 0) {
+ angle += 2 * M_PI;
+ }
+ }
+ else {
+ faces[0] = sorted_faces[0].face->reversed ? sorted_faces[0].face - j :
+ sorted_faces[0].face + j;
+ faces[1] = NULL;
+ angle = 0;
+ }
+ NewEdgeRef *edge_data = MEM_mallocN(sizeof(*edge_data), "edge_data in solidify");
+ uint edge_data_edge_index = MOD_SOLIDIFY_EMPTY_TAG;
+ if (do_shell || (adj_len == 1 && do_rim)) {
+ edge_data_edge_index = 0;
+ }
+ *edge_data = (NewEdgeRef){.old_edge = i,
+ .faces = {faces[0], faces[1]},
+ .link_edge_groups = {NULL, NULL},
+ .angle = angle,
+ .new_edge = edge_data_edge_index};
+ new_edges[j] = edge_data;
+ for (uint k = 0; k < 2; k++) {
+ if (faces[k] != NULL) {
+ ml = orig_mloop + faces[k]->face->loopstart;
+ for (int l = 0; l < faces[k]->face->totloop; l++, ml++) {
+ if (edge_adj_faces[ml->e] == edge_adj_faces[i]) {
+ if (ml->e != i && orig_edge_data_arr[ml->e] == NULL) {
+ orig_edge_data_arr[ml->e] = new_edges;
+ }
+ faces[k]->link_edges[l] = edge_data;
+ break;
+ }
+ }
+ }
+ }
+ }
+ MEM_freeN(sorted_faces);
+ orig_edge_data_arr[i] = new_edges;
+ if (do_shell || (adj_len == 1 && do_rim)) {
+ numNewEdges += new_edges_len;
+ }
+ }
+ }
+ }
+
+ for (uint i = 0; i < numEdges; i++) {
+ if (edge_adj_faces[i]) {
+ if (edge_adj_faces[i]->used > 1) {
+ edge_adj_faces[i]->used--;
+ }
+ else {
+ MEM_freeN(edge_adj_faces[i]->faces);
+ MEM_freeN(edge_adj_faces[i]->faces_reversed);
+ MEM_freeN(edge_adj_faces[i]);
+ }
+ }
+ }
+ MEM_freeN(edge_adj_faces);
+ }
+
+ MEM_freeN(vert_adj_edges_len);
+
+ /* Create sorted edge groups for every vert. */
+ {
+ OldVertEdgeRef **adj_edges_ptr = vert_adj_edges;
+ for (uint i = 0; i < numVerts; i++, adj_edges_ptr++) {
+ if (*adj_edges_ptr != NULL && (*adj_edges_ptr)->edges_len >= 2) {
+ EdgeGroup *edge_groups;
+
+ int eg_index = -1;
+ bool contains_long_groups = false;
+ uint topo_groups = 0;
+
+ /* Initial sorted creation. */
+ {
+ const uint *adj_edges = (*adj_edges_ptr)->edges;
+ const uint tot_adj_edges = (*adj_edges_ptr)->edges_len;
+
+ uint unassigned_edges_len = 0;
+ for (uint j = 0; j < tot_adj_edges; j++) {
+ NewEdgeRef **new_edges = orig_edge_data_arr[adj_edges[j]];
+ /* TODO check where the null pointer come from,
+ * because there should not be any... */
+ if (new_edges) {
+ while (*new_edges) {
+ unassigned_edges_len++;
+ new_edges++;
+ }
+ }
+ }
+ NewEdgeRef **unassigned_edges = MEM_malloc_arrayN(
+ unassigned_edges_len, sizeof(*unassigned_edges), "unassigned_edges in solidify");
+ for (uint j = 0, k = 0; j < tot_adj_edges; j++) {
+ NewEdgeRef **new_edges = orig_edge_data_arr[adj_edges[j]];
+ if (new_edges) {
+ while (*new_edges) {
+ unassigned_edges[k++] = *new_edges;
+ new_edges++;
+ }
+ }
+ }
+
+ edge_groups = MEM_calloc_arrayN(
+ (unassigned_edges_len / 2) + 1, sizeof(*edge_groups), "edge_groups in solidify");
+
+ uint assigned_edges_len = 0;
+ NewEdgeRef *found_edge = NULL;
+ uint found_edge_index = 0;
+ bool insert_at_start = false;
+ uint eg_capacity = 5;
+ NewFaceRef *eg_track_faces[2] = {NULL, NULL};
+ NewFaceRef *last_open_edge_track = NULL;
+ NewEdgeRef *edge = NULL;
+
+ while (assigned_edges_len < unassigned_edges_len) {
+ found_edge = NULL;
+ insert_at_start = false;
+ if (eg_index >= 0 && edge_groups[eg_index].edges_len == 0) {
+ uint j = 0;
+ edge = NULL;
+ while (!edge && j < unassigned_edges_len) {
+ edge = unassigned_edges[j++];
+ if (edge && last_open_edge_track &&
+ (edge->faces[0] != last_open_edge_track || edge->faces[1] != NULL)) {
+ edge = NULL;
+ }
+ }
+ if (!edge && last_open_edge_track) {
+ topo_groups++;
+ last_open_edge_track = NULL;
+ edge_groups[eg_index].topo_group++;
+ j = 0;
+ while (!edge && j < unassigned_edges_len) {
+ edge = unassigned_edges[j++];
+ }
+ }
+ else if (!last_open_edge_track && eg_index > 0) {
+ topo_groups++;
+ edge_groups[eg_index].topo_group++;
+ }
+ BLI_assert(edge != NULL);
+ found_edge_index = j - 1;
+ found_edge = edge;
+ if (!last_open_edge_track && vm[orig_medge[edge->old_edge].v1] == i) {
+ eg_track_faces[0] = edge->faces[0];
+ eg_track_faces[1] = edge->faces[1];
+ if (edge->faces[1] == NULL) {
+ last_open_edge_track = edge->faces[0]->reversed ? edge->faces[0] - 1 :
+ edge->faces[0] + 1;
+ }
+ }
+ else {
+ eg_track_faces[0] = edge->faces[1];
+ eg_track_faces[1] = edge->faces[0];
+ }
+ }
+ else if (eg_index >= 0) {
+ NewEdgeRef **edge_ptr = unassigned_edges;
+ for (found_edge_index = 0; found_edge_index < unassigned_edges_len;
+ found_edge_index++, edge_ptr++) {
+ if (*edge_ptr) {
+ edge = *edge_ptr;
+ if (edge->faces[0] == eg_track_faces[1]) {
+ insert_at_start = false;
+ eg_track_faces[1] = edge->faces[1];
+ found_edge = edge;
+ if (edge->faces[1] == NULL) {
+ edge_groups[eg_index].is_orig_closed = false;
+ last_open_edge_track = edge->faces[0]->reversed ? edge->faces[0] - 1 :
+ edge->faces[0] + 1;
+ }
+ break;
+ }
+ else if (edge->faces[0] == eg_track_faces[0]) {
+ insert_at_start = true;
+ eg_track_faces[0] = edge->faces[1];
+ found_edge = edge;
+ if (edge->faces[1] == NULL) {
+ edge_groups[eg_index].is_orig_closed = false;
+ }
+ break;
+ }
+ else if (edge->faces[1] != NULL) {
+ if (edge->faces[1] == eg_track_faces[1]) {
+ insert_at_start = false;
+ eg_track_faces[1] = edge->faces[0];
+ found_edge = edge;
+ break;
+ }
+ else if (edge->faces[1] == eg_track_faces[0]) {
+ insert_at_start = true;
+ eg_track_faces[0] = edge->faces[0];
+ found_edge = edge;
+ break;
+ }
+ }
+ }
+ }
+ }
+ if (found_edge) {
+ unassigned_edges[found_edge_index] = NULL;
+ assigned_edges_len++;
+ const uint needed_capacity = edge_groups[eg_index].edges_len + 1;
+ if (needed_capacity > eg_capacity) {
+ eg_capacity = needed_capacity + 1;
+ NewEdgeRef **new_eg = MEM_calloc_arrayN(
+ eg_capacity, sizeof(*new_eg), "edge_group realloc in solidify");
+ if (insert_at_start) {
+ memcpy(new_eg + 1,
+ edge_groups[eg_index].edges,
+ edge_groups[eg_index].edges_len * sizeof(*new_eg));
+ }
+ else {
+ memcpy(new_eg,
+ edge_groups[eg_index].edges,
+ edge_groups[eg_index].edges_len * sizeof(*new_eg));
+ }
+ MEM_freeN(edge_groups[eg_index].edges);
+ edge_groups[eg_index].edges = new_eg;
+ }
+ else if (insert_at_start) {
+ memmove(edge_groups[eg_index].edges + 1,
+ edge_groups[eg_index].edges,
+ edge_groups[eg_index].edges_len * sizeof(*edge_groups[eg_index].edges));
+ }
+ edge_groups[eg_index].edges[insert_at_start ? 0 : edge_groups[eg_index].edges_len] =
+ found_edge;
+ edge_groups[eg_index].edges_len++;
+ if (edge_groups[eg_index].edges[edge_groups[eg_index].edges_len - 1]->faces[1] !=
+ NULL) {
+ last_open_edge_track = NULL;
+ }
+ if (edge_groups[eg_index].edges_len > 3) {
+ contains_long_groups = true;
+ }
+ }
+ else {
+ eg_index++;
+ BLI_assert(eg_index < (unassigned_edges_len / 2));
+ eg_capacity = 5;
+ NewEdgeRef **edges = MEM_calloc_arrayN(
+ eg_capacity, sizeof(*edges), "edge_group in solidify");
+ edge_groups[eg_index] = (EdgeGroup){
+ .valid = true,
+ .edges = edges,
+ .edges_len = 0,
+ .open_face_edge = MOD_SOLIDIFY_EMPTY_TAG,
+ .is_orig_closed = true,
+ .is_even_split = false,
+ .split = 0,
+ .is_singularity = false,
+ .topo_group = topo_groups,
+ .co = {0.0f, 0.0f, 0.0f},
+ .no = {0.0f, 0.0f, 0.0f},
+ .new_vert = MOD_SOLIDIFY_EMPTY_TAG,
+ };
+ eg_track_faces[0] = NULL;
+ eg_track_faces[1] = NULL;
+ }
+ }
+ /* #eg_index is the number of groups from here on. */
+ eg_index++;
+ /* #topo_groups is the number of topo groups from here on. */
+ topo_groups++;
+ MEM_freeN(unassigned_edges);
+ }
+
+ /* Split of long self intersection groups */
+ {
+ uint splits = 0;
+ if (contains_long_groups) {
+ uint add_index = 0;
+ for (uint j = 0; j < eg_index; j++) {
+ const uint edges_len = edge_groups[j + add_index].edges_len;
+ if (edges_len > 3) {
+ bool has_doubles = false;
+ bool *doubles = MEM_calloc_arrayN(
+ edges_len, sizeof(*doubles), "doubles in solidify");
+ EdgeGroup g = edge_groups[j + add_index];
+ for (uint k = 0; k < edges_len; k++) {
+ for (uint l = k + 1; l < edges_len; l++) {
+ if (g.edges[k]->old_edge == g.edges[l]->old_edge) {
+ doubles[k] = true;
+ doubles[l] = true;
+ has_doubles = true;
+ }
+ }
+ }
+ if (has_doubles) {
+ const uint prior_splits = splits;
+ const uint prior_index = add_index;
+ int unique_start = -1;
+ int first_unique_end = -1;
+ int last_split = -1;
+ int first_split = -1;
+ bool first_even_split = false;
+ uint real_k = 0;
+ while (real_k < edges_len ||
+ (g.is_orig_closed &&
+ (real_k <=
+ (first_unique_end == -1 ? 0 : first_unique_end) + (int)edges_len ||
+ first_split != last_split))) {
+ const uint k = real_k % edges_len;
+ if (!doubles[k]) {
+ if (first_unique_end != -1 && unique_start == -1) {
+ unique_start = (int)real_k;
+ }
+ }
+ else if (first_unique_end == -1) {
+ first_unique_end = (int)k;
+ }
+ else if (unique_start != -1) {
+ const uint split = (((uint)unique_start + real_k + 1) / 2) % edges_len;
+ const bool is_even_split = (((uint)unique_start + real_k) & 1);
+ if (last_split != -1) {
+ /* Override g on first split (no insert). */
+ if (prior_splits != splits) {
+ memmove(edge_groups + j + add_index + 1,
+ edge_groups + j + add_index,
+ ((uint)eg_index - j) * sizeof(*edge_groups));
+ add_index++;
+ }
+ if (last_split > split) {
+ const uint size = (split + edges_len) - (uint)last_split;
+ NewEdgeRef **edges = MEM_malloc_arrayN(
+ size, sizeof(*edges), "edge_group split in solidify");
+ memcpy(edges,
+ g.edges + last_split,
+ (edges_len - (uint)last_split) * sizeof(*edges));
+ memcpy(edges + (edges_len - (uint)last_split),
+ g.edges,
+ split * sizeof(*edges));
+ edge_groups[j + add_index] = (EdgeGroup){
+ .valid = true,
+ .edges = edges,
+ .edges_len = size,
+ .open_face_edge = MOD_SOLIDIFY_EMPTY_TAG,
+ .is_orig_closed = g.is_orig_closed,
+ .is_even_split = is_even_split,
+ .split = add_index - prior_index + 1 + (uint)!g.is_orig_closed,
+ .is_singularity = false,
+ .topo_group = g.topo_group,
+ .co = {0.0f, 0.0f, 0.0f},
+ .no = {0.0f, 0.0f, 0.0f},
+ .new_vert = MOD_SOLIDIFY_EMPTY_TAG,
+ };
+ }
+ else {
+ const uint size = split - (uint)last_split;
+ NewEdgeRef **edges = MEM_malloc_arrayN(
+ size, sizeof(*edges), "edge_group split in solidify");
+ memcpy(edges, g.edges + last_split, size * sizeof(*edges));
+ edge_groups[j + add_index] = (EdgeGroup){
+ .valid = true,
+ .edges = edges,
+ .edges_len = size,
+ .open_face_edge = MOD_SOLIDIFY_EMPTY_TAG,
+ .is_orig_closed = g.is_orig_closed,
+ .is_even_split = is_even_split,
+ .split = add_index - prior_index + 1 + (uint)!g.is_orig_closed,
+ .is_singularity = false,
+ .topo_group = g.topo_group,
+ .co = {0.0f, 0.0f, 0.0f},
+ .no = {0.0f, 0.0f, 0.0f},
+ .new_vert = MOD_SOLIDIFY_EMPTY_TAG,
+ };
+ }
+ splits++;
+ }
+ last_split = (int)split;
+ if (first_split == -1) {
+ first_split = (int)split;
+ first_even_split = is_even_split;
+ }
+ unique_start = -1;
+ }
+ real_k++;
+ }
+ if (first_split != -1) {
+ if (!g.is_orig_closed) {
+ if (prior_splits != splits) {
+ memmove(edge_groups + (j + prior_index + 1),
+ edge_groups + (j + prior_index),
+ ((uint)eg_index + add_index - (j + prior_index)) *
+ sizeof(*edge_groups));
+ memmove(edge_groups + (j + add_index + 2),
+ edge_groups + (j + add_index + 1),
+ ((uint)eg_index - j) * sizeof(*edge_groups));
+ add_index++;
+ }
+ else {
+ memmove(edge_groups + (j + add_index + 2),
+ edge_groups + (j + add_index + 1),
+ ((uint)eg_index - j - 1) * sizeof(*edge_groups));
+ }
+ NewEdgeRef **edges = MEM_malloc_arrayN(
+ (uint)first_split, sizeof(*edges), "edge_group split in solidify");
+ memcpy(edges, g.edges, (uint)first_split * sizeof(*edges));
+ edge_groups[j + prior_index] = (EdgeGroup){
+ .valid = true,
+ .edges = edges,
+ .edges_len = (uint)first_split,
+ .open_face_edge = MOD_SOLIDIFY_EMPTY_TAG,
+ .is_orig_closed = g.is_orig_closed,
+ .is_even_split = first_even_split,
+ .split = 1,
+ .is_singularity = false,
+ .topo_group = g.topo_group,
+ .co = {0.0f, 0.0f, 0.0f},
+ .no = {0.0f, 0.0f, 0.0f},
+ .new_vert = MOD_SOLIDIFY_EMPTY_TAG,
+ };
+ add_index++;
+ splits++;
+ edges = MEM_malloc_arrayN(edges_len - (uint)last_split,
+ sizeof(*edges),
+ "edge_group split in solidify");
+ memcpy(edges,
+ g.edges + last_split,
+ (edges_len - (uint)last_split) * sizeof(*edges));
+ edge_groups[j + add_index] = (EdgeGroup){
+ .valid = true,
+ .edges = edges,
+ .edges_len = (edges_len - (uint)last_split),
+ .open_face_edge = MOD_SOLIDIFY_EMPTY_TAG,
+ .is_orig_closed = g.is_orig_closed,
+ .is_even_split = false,
+ .split = add_index - prior_index + 1,
+ .is_singularity = false,
+ .topo_group = g.topo_group,
+ .co = {0.0f, 0.0f, 0.0f},
+ .no = {0.0f, 0.0f, 0.0f},
+ .new_vert = MOD_SOLIDIFY_EMPTY_TAG,
+ };
+ }
+ if (prior_splits != splits) {
+ MEM_freeN(g.edges);
+ }
+ }
+ if (first_unique_end != -1 && prior_splits == splits) {
+ has_singularities = true;
+ edge_groups[j + add_index].is_singularity = true;
+ }
+ }
+ MEM_freeN(doubles);
+ }
+ }
+ }
+ }
+
+ orig_vert_groups_arr[i] = edge_groups;
+ /* Count new edges, loops, polys and add to link_edge_groups. */
+ {
+ uint new_verts = 0;
+ bool contains_open_splits = false;
+ uint open_edges = 0;
+ uint contains_splits = 0;
+ uint last_added = 0;
+ uint first_added = 0;
+ bool first_set = false;
+ for (EdgeGroup *g = edge_groups; g->valid; g++) {
+ NewEdgeRef **e = g->edges;
+ for (uint j = 0; j < g->edges_len; j++, e++) {
+ const uint flip = (uint)(vm[orig_medge[(*e)->old_edge].v2] == i);
+ BLI_assert(flip || vm[orig_medge[(*e)->old_edge].v1] == i);
+ (*e)->link_edge_groups[flip] = g;
+ }
+ uint added = 0;
+ if (do_shell || (do_rim && !g->is_orig_closed)) {
+ BLI_assert(g->new_vert == MOD_SOLIDIFY_EMPTY_TAG);
+ g->new_vert = numNewVerts++;
+ if (do_rim || (do_shell && g->split)) {
+ new_verts++;
+ contains_splits += (g->split != 0);
+ contains_open_splits |= g->split && !g->is_orig_closed;
+ added = g->split;
+ }
+ }
+ open_edges += (uint)(added < last_added);
+ if (!first_set) {
+ first_set = true;
+ first_added = added;
+ }
+ last_added = added;
+ if (!(g + 1)->valid || g->topo_group != (g + 1)->topo_group) {
+ if (new_verts > 2) {
+ numNewPolys++;
+ numNewEdges += new_verts;
+ open_edges += (uint)(first_added < last_added);
+ open_edges -= (uint)(open_edges && !contains_open_splits);
+ if (do_shell && do_rim) {
+ numNewLoops += new_verts * 2;
+ }
+ else if (do_shell) {
+ numNewLoops += new_verts * 2 - open_edges;
+ }
+ else { // do_rim
+ numNewLoops += new_verts * 2 + open_edges - contains_splits;
+ }
+ }
+ else if (new_verts == 2) {
+ numNewEdges++;
+ numNewLoops += 2u - (uint)(!(do_rim && do_shell) && contains_open_splits);
+ }
+ new_verts = 0;
+ contains_open_splits = false;
+ contains_splits = 0;
+ open_edges = 0;
+ last_added = 0;
+ first_added = 0;
+ first_set = false;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* Free vert_adj_edges memory. */
+ {
+ uint i = 0;
+ for (OldVertEdgeRef **p = vert_adj_edges; i < numVerts; i++, p++) {
+ if (*p) {
+ MEM_freeN((*p)->edges);
+ MEM_freeN(*p);
+ }
+ }
+ MEM_freeN(vert_adj_edges);
+ }
+
+ /* TODO create_regions if fix_intersections. */
+
+ /* General use pointer for #EdgeGroup iteration. */
+ EdgeGroup **gs_ptr;
+
+ /* Calculate EdgeGroup vertex coordinates. */
+ {
+ mv = orig_mvert;
+ gs_ptr = orig_vert_groups_arr;
+ for (uint i = 0; i < numVerts; i++, mv++, gs_ptr++) {
+ if (*gs_ptr) {
+ EdgeGroup *g = *gs_ptr;
+ for (uint j = 0; g->valid; j++, g++) {
+ if (!g->is_singularity) {
+ float *nor = g->no;
+ float move_nor[3] = {0, 0, 0};
+ bool disable_boundary_fix = (smd->nonmanifold_boundary_mode ==
+ MOD_SOLIDIFY_NONMANIFOLD_BOUNDARY_MODE_NONE ||
+ (g->is_orig_closed || g->split));
+ /* Constraints Method. */
+ if (smd->nonmanifold_offset_mode == MOD_SOLIDIFY_NONMANIFOLD_OFFSET_MODE_CONSTRAINTS) {
+ NewEdgeRef *first_edge = NULL;
+ NewEdgeRef **edge_ptr = g->edges;
+ /* Contains normal and offset [nx, ny, nz, ofs]. */
+ float(*normals_queue)[4] = MEM_malloc_arrayN(
+ g->edges_len + 1, sizeof(*normals_queue), "normals_queue in solidify");
+ uint queue_index = 0;
+
+ float face_nors[3][3];
+ float nor_ofs[3];
+
+ const bool cycle = (g->is_orig_closed && !g->split) || g->is_even_split;
+ for (uint k = 0; k < g->edges_len; k++, edge_ptr++) {
+ if (!(k & 1) || (!cycle && k == g->edges_len - 1)) {
+ NewEdgeRef *edge = *edge_ptr;
+ for (uint l = 0; l < 2; l++) {
+ NewFaceRef *face = edge->faces[l];
+ if (face && (first_edge == NULL ||
+ (first_edge->faces[0] != face && first_edge->faces[1] != face))) {
+ if (!null_faces[face->index]) {
+ mul_v3_v3fl(normals_queue[queue_index],
+ poly_nors[face->index],
+ face->reversed ? -1 : 1);
+ normals_queue[queue_index++][3] = face->reversed ? ofs_back : ofs_front;
+ }
+ else {
+ mul_v3_v3fl(face_nors[0], poly_nors[face->index], face->reversed ? -1 : 1);
+ nor_ofs[0] = face->reversed ? ofs_back : ofs_front;
+ }
+ }
+ }
+ if ((cycle && k == 0) || (!cycle && k + 3 >= g->edges_len)) {
+ first_edge = edge;
+ }
+ }
+ }
+ uint face_nors_len = 0;
+ const float stop_explosion = 1 - fabsf(smd->offset_fac) * 0.05f;
+ while (queue_index > 0) {
+ if (face_nors_len == 0) {
+ if (queue_index <= 2) {
+ for (uint k = 0; k < queue_index; k++) {
+ copy_v3_v3(face_nors[k], normals_queue[k]);
+ nor_ofs[k] = normals_queue[k][3];
+ }
+ face_nors_len = queue_index;
+ queue_index = 0;
+ }
+ else {
+ /* Find most different two normals. */
+ float min_p = 2;
+ uint min_n0 = 0;
+ uint min_n1 = 0;
+ for (uint k = 0; k < queue_index; k++) {
+ for (uint m = k + 1; m < queue_index; m++) {
+ float p = dot_v3v3(normals_queue[k], normals_queue[m]);
+ if (p <= min_p + FLT_EPSILON) {
+ min_p = p;
+ min_n0 = m;
+ min_n1 = k;
+ }
+ }
+ }
+ copy_v3_v3(face_nors[0], normals_queue[min_n0]);
+ copy_v3_v3(face_nors[1], normals_queue[min_n1]);
+ nor_ofs[0] = normals_queue[min_n0][3];
+ nor_ofs[1] = normals_queue[min_n1][3];
+ face_nors_len = 2;
+ queue_index--;
+ memmove(normals_queue + min_n0,
+ normals_queue + min_n0 + 1,
+ (queue_index - min_n0) * sizeof(*normals_queue));
+ queue_index--;
+ memmove(normals_queue + min_n1,
+ normals_queue + min_n1 + 1,
+ (queue_index - min_n1) * sizeof(*normals_queue));
+ min_p = 1;
+ min_n1 = 0;
+ float max_p = -1;
+ for (uint k = 0; k < queue_index; k++) {
+ max_p = -1;
+ for (uint m = 0; m < face_nors_len; m++) {
+ float p = dot_v3v3(face_nors[m], normals_queue[k]);
+ if (p > max_p + FLT_EPSILON) {
+ max_p = p;
+ }
+ }
+ if (max_p <= min_p + FLT_EPSILON) {
+ min_p = max_p;
+ min_n1 = k;
+ }
+ }
+ if (min_p < 0.8) {
+ copy_v3_v3(face_nors[2], normals_queue[min_n1]);
+ nor_ofs[2] = normals_queue[min_n1][3];
+ face_nors_len++;
+ queue_index--;
+ memmove(normals_queue + min_n1,
+ normals_queue + min_n1 + 1,
+ (queue_index - min_n1) * sizeof(*normals_queue));
+ }
+ }
+ }
+ else {
+ uint best = 0;
+ uint best_group = 0;
+ float best_p = -1.0f;
+ for (uint k = 0; k < queue_index; k++) {
+ for (uint m = 0; m < face_nors_len; m++) {
+ float p = dot_v3v3(face_nors[m], normals_queue[k]);
+ if (p > best_p + FLT_EPSILON) {
+ best_p = p;
+ best = m;
+ best_group = k;
+ }
+ }
+ }
+ add_v3_v3(face_nors[best], normals_queue[best_group]);
+ normalize_v3(face_nors[best]);
+ nor_ofs[best] = (nor_ofs[best] + normals_queue[best_group][3]) * 0.5f;
+ queue_index--;
+ memmove(normals_queue + best_group,
+ normals_queue + best_group + 1,
+ (queue_index - best_group) * sizeof(*normals_queue));
+ }
+ }
+ MEM_freeN(normals_queue);
+ /* When up to 3 constraint normals are found. */
+ float d, q;
+ switch (face_nors_len) {
+ case 0:
+ mul_v3_v3fl(nor, face_nors[0], nor_ofs[0]);
+ disable_boundary_fix = true;
+ break;
+ case 1:
+ mul_v3_v3fl(nor, face_nors[0], nor_ofs[0]);
+ disable_boundary_fix = true;
+ break;
+ case 2:
+ q = dot_v3v3(face_nors[0], face_nors[1]);
+ d = 1.0f - q * q;
+ if (LIKELY(d > FLT_EPSILON) && q < stop_explosion) {
+ d = 1.0f / d;
+ mul_v3_fl(face_nors[0], (nor_ofs[0] - nor_ofs[1] * q) * d);
+ mul_v3_fl(face_nors[1], (nor_ofs[1] - nor_ofs[0] * q) * d);
+ add_v3_v3v3(nor, face_nors[0], face_nors[1]);
+ }
+ else {
+ mul_v3_fl(face_nors[0], nor_ofs[0] * 0.5f);
+ mul_v3_fl(face_nors[1], nor_ofs[1] * 0.5f);
+ add_v3_v3v3(nor, face_nors[0], face_nors[1]);
+ }
+ if (!disable_boundary_fix) {
+ cross_v3_v3v3(move_nor, face_nors[0], face_nors[1]);
+ }
+ break;
+ case 3:
+ q = dot_v3v3(face_nors[0], face_nors[1]);
+ d = 1.0f - q * q;
+ float *free_nor = move_nor; /* No need to allocate a new array. */
+ cross_v3_v3v3(free_nor, face_nors[0], face_nors[1]);
+ if (LIKELY(d > FLT_EPSILON) && q < stop_explosion) {
+ d = 1.0f / d;
+ mul_v3_fl(face_nors[0], (nor_ofs[0] - nor_ofs[1] * q) * d);
+ mul_v3_fl(face_nors[1], (nor_ofs[1] - nor_ofs[0] * q) * d);
+ add_v3_v3v3(nor, face_nors[0], face_nors[1]);
+ }
+ else {
+ mul_v3_fl(face_nors[0], nor_ofs[0] * 0.5f);
+ mul_v3_fl(face_nors[1], nor_ofs[1] * 0.5f);
+ add_v3_v3v3(nor, face_nors[0], face_nors[1]);
+ }
+ mul_v3_fl(face_nors[2], nor_ofs[2]);
+ d = dot_v3v3(face_nors[2], free_nor);
+ if (LIKELY(fabsf(d) > FLT_EPSILON)) {
+ sub_v3_v3v3(face_nors[0], nor, face_nors[2]); /* Override face_nor[0]. */
+ mul_v3_fl(free_nor, dot_v3v3(face_nors[2], face_nors[0]) / d);
+ sub_v3_v3(nor, free_nor);
+ }
+ disable_boundary_fix = true;
+ break;
+ default:
+ BLI_assert(0);
+ }
+ }
+ /* Simple/Even Method. */
+ else {
+ float total_angle = 0;
+ float total_angle_back = 0;
+ NewEdgeRef *first_edge = NULL;
+ NewEdgeRef **edge_ptr = g->edges;
+ float face_nor[3];
+ float nor_back[3] = {0, 0, 0};
+ bool has_back = false;
+ bool has_front = false;
+ bool cycle = (g->is_orig_closed && !g->split) || g->is_even_split;
+ for (uint k = 0; k < g->edges_len; k++, edge_ptr++) {
+ if (!(k & 1) || (!cycle && k == g->edges_len - 1)) {
+ NewEdgeRef *edge = *edge_ptr;
+ for (uint l = 0; l < 2; l++) {
+ NewFaceRef *face = edge->faces[l];
+ if (face && (first_edge == NULL ||
+ (first_edge->faces[0] != face && first_edge->faces[1] != face))) {
+ float angle = 1.0f;
+ float ofs = face->reversed ? -max_ff(1.0e-5f, ofs_back) :
+ max_ff(1.0e-5f, ofs_front);
+ if (smd->nonmanifold_offset_mode ==
+ MOD_SOLIDIFY_NONMANIFOLD_OFFSET_MODE_EVEN) {
+ MLoop *ml_next = orig_mloop + face->face->loopstart;
+ ml = ml_next + (face->face->totloop - 1);
+ MLoop *ml_prev = ml - 1;
+ for (int m = 0; m < face->face->totloop && vm[ml->v] != i;
+ m++, ml_next++) {
+ ml_prev = ml;
+ ml = ml_next;
+ }
+ angle = angle_v3v3v3(
+ orig_mvert[vm[ml_prev->v]].co, mv->co, orig_mvert[vm[ml_next->v]].co);
+ if (face->reversed) {
+ total_angle_back += angle * ofs * ofs;
+ }
+ else {
+ total_angle += angle * ofs * ofs;
+ }
+ }
+ else {
+ if (face->reversed) {
+ total_angle_back++;
+ }
+ else {
+ total_angle++;
+ }
+ }
+ mul_v3_v3fl(face_nor, poly_nors[face->index], angle * ofs);
+ if (face->reversed) {
+ add_v3_v3(nor_back, face_nor);
+ has_back = true;
+ }
+ else {
+ add_v3_v3(nor, face_nor);
+ has_front = true;
+ }
+ }
+ }
+ if ((cycle && k == 0) || (!cycle && k + 3 >= g->edges_len)) {
+ first_edge = edge;
+ }
+ }
+ }
+
+ /* Set normal length with selected method. */
+ if (smd->nonmanifold_offset_mode == MOD_SOLIDIFY_NONMANIFOLD_OFFSET_MODE_EVEN) {
+ float d = dot_v3v3(nor, nor_back);
+ if (has_front) {
+ float length = len_squared_v3(nor);
+ if (LIKELY(length > FLT_EPSILON)) {
+ mul_v3_fl(nor, total_angle / length);
+ }
+ }
+ if (has_back) {
+ float length = len_squared_v3(nor_back);
+ if (LIKELY(length > FLT_EPSILON)) {
+ mul_v3_fl(nor_back, total_angle_back / length);
+ }
+ if (!has_front) {
+ copy_v3_v3(nor, nor_back);
+ }
+ }
+ if (has_front && has_back) {
+ float nor_length = len_v3(nor);
+ float nor_back_length = len_v3(nor_back);
+ float q = dot_v3v3(nor, nor_back);
+ if (LIKELY(fabsf(q) > FLT_EPSILON)) {
+ q /= nor_length * nor_back_length;
+ }
+ d = 1.0f - q * q;
+ if (LIKELY(d > FLT_EPSILON)) {
+ d = 1.0f / d;
+ if (LIKELY(nor_length > FLT_EPSILON)) {
+ mul_v3_fl(nor, (1 - nor_back_length * q / nor_length) * d);
+ }
+ if (LIKELY(nor_back_length > FLT_EPSILON)) {
+ mul_v3_fl(nor_back, (1 - nor_length * q / nor_back_length) * d);
+ }
+ add_v3_v3(nor, nor_back);
+ }
+ else {
+ mul_v3_fl(nor, 0.5f);
+ mul_v3_fl(nor_back, 0.5f);
+ add_v3_v3(nor, nor_back);
+ }
+ }
+ }
+ else {
+ if (has_front && total_angle > FLT_EPSILON) {
+ mul_v3_fl(nor, 1.0f / total_angle);
+ }
+ if (has_back && total_angle_back > FLT_EPSILON) {
+ mul_v3_fl(nor_back, 1.0f / total_angle_back);
+ add_v3_v3(nor, nor_back);
+ }
+ }
+ /* Set move_nor for boundary fix. */
+ if (!disable_boundary_fix && g->edges_len > 2) {
+ edge_ptr = g->edges + 1;
+ float tmp[3];
+ uint k;
+ for (k = 1; k + 1 < g->edges_len; k++, edge_ptr++) {
+ MEdge *e = orig_medge + (*edge_ptr)->old_edge;
+ sub_v3_v3v3(tmp, orig_mvert[vm[e->v1] == i ? e->v2 : e->v1].co, mv->co);
+ add_v3_v3(move_nor, tmp);
+ }
+ if (k == 1) {
+ disable_boundary_fix = true;
+ }
+ else {
+ disable_boundary_fix = normalize_v3(move_nor) == 0.0f;
+ }
+ }
+ else {
+ disable_boundary_fix = true;
+ }
+ }
+ /* Fix boundary verts. */
+ if (!disable_boundary_fix) {
+ /* Constraint normal, nor * constr_nor == 0 after this fix. */
+ float constr_nor[3];
+ MEdge *e0_edge = orig_medge + g->edges[0]->old_edge;
+ MEdge *e1_edge = orig_medge + g->edges[g->edges_len - 1]->old_edge;
+ float e0[3];
+ float e1[3];
+ sub_v3_v3v3(
+ e0, orig_mvert[vm[e0_edge->v1] == i ? e0_edge->v2 : e0_edge->v1].co, mv->co);
+ sub_v3_v3v3(
+ e1, orig_mvert[vm[e1_edge->v1] == i ? e1_edge->v2 : e1_edge->v1].co, mv->co);
+ if (smd->nonmanifold_boundary_mode == MOD_SOLIDIFY_NONMANIFOLD_BOUNDARY_MODE_FLAT) {
+ cross_v3_v3v3(constr_nor, e0, e1);
+ }
+ else {
+ float f0[3];
+ float f1[3];
+ if (g->edges[0]->faces[0]->reversed) {
+ negate_v3_v3(f0, poly_nors[g->edges[0]->faces[0]->index]);
+ }
+ else {
+ copy_v3_v3(f0, poly_nors[g->edges[0]->faces[0]->index]);
+ }
+ if (g->edges[g->edges_len - 1]->faces[0]->reversed) {
+ negate_v3_v3(f1, poly_nors[g->edges[g->edges_len - 1]->faces[0]->index]);
+ }
+ else {
+ copy_v3_v3(f1, poly_nors[g->edges[g->edges_len - 1]->faces[0]->index]);
+ }
+ float n0[3];
+ float n1[3];
+ cross_v3_v3v3(n0, e0, f0);
+ cross_v3_v3v3(n1, f1, e1);
+ normalize_v3(n0);
+ normalize_v3(n1);
+ add_v3_v3v3(constr_nor, n0, n1);
+ }
+ float d = dot_v3v3(constr_nor, move_nor);
+ if (LIKELY(fabsf(d) > FLT_EPSILON)) {
+ mul_v3_fl(move_nor, dot_v3v3(constr_nor, nor) / d);
+ sub_v3_v3(nor, move_nor);
+ }
+ }
+ float scalar_vgroup = 1;
+ /* Use vertex group. */
+ if (dvert) {
+ MDeformVert *dv = &dvert[i];
+ if (defgrp_invert) {
+ scalar_vgroup = 1.0f - defvert_find_weight(dv, defgrp_index);
+ }
+ else {
+ scalar_vgroup = defvert_find_weight(dv, defgrp_index);
+ }
+ scalar_vgroup = offset_fac_vg + (scalar_vgroup * offset_fac_vg_inv);
+ }
+ /* Do clamping. */
+ if (do_clamp) {
+ if (do_angle_clamp) {
+ float min_length = 0;
+ float angle = 0.5f * M_PI;
+ uint k = 0;
+ for (NewEdgeRef **p = g->edges; k < g->edges_len; k++, p++) {
+ float length = orig_edge_lengths[(*p)->old_edge];
+ float e_ang = (*p)->angle;
+ if (e_ang > angle) {
+ angle = e_ang;
+ }
+ if (length < min_length || k == 0) {
+ min_length = length;
+ }
+ }
+ float cos_ang = cosf(angle * 0.5f);
+ if (cos_ang > 0) {
+ float max_off = min_length * 0.5f / cos_ang;
+ if (max_off < offset * 0.5f) {
+ scalar_vgroup *= max_off / offset * 2;
+ }
+ }
+ }
+ else {
+ float min_length = 0;
+ uint k = 0;
+ for (NewEdgeRef **p = g->edges; k < g->edges_len; k++, p++) {
+ float length = orig_edge_lengths[(*p)->old_edge];
+ if (length < min_length || k == 0) {
+ min_length = length;
+ }
+ }
+ if (min_length < offset) {
+ scalar_vgroup *= min_length / offset;
+ }
+ }
+ }
+ mul_v3_fl(nor, scalar_vgroup);
+ add_v3_v3v3(g->co, nor, mv->co);
+ }
+ else {
+ copy_v3_v3(g->co, mv->co);
+ }
+ }
+ }
+ }
+ }
+
+ if (null_faces) {
+ MEM_freeN(null_faces);
+ }
+
+ /* TODO create vertdata for intersection fixes (intersection fixing per topology region). */
+
+ /* Correction for adjacent one sided groups around a vert to
+ * prevent edge duplicates and null polys. */
+ uint(*singularity_edges)[2] = NULL;
+ uint totsingularity = 0;
+ if (has_singularities) {
+ has_singularities = false;
+ uint i = 0;
+ uint singularity_edges_len = 1;
+ singularity_edges = MEM_malloc_arrayN(
+ singularity_edges_len, sizeof(*singularity_edges), "singularity_edges in solidify");
+ for (NewEdgeRef ***new_edges = orig_edge_data_arr; i < numEdges; i++, new_edges++) {
+ if (*new_edges && (do_shell || edge_adj_faces_len[i] == 1) && (**new_edges)->old_edge == i) {
+ for (NewEdgeRef **l = *new_edges; *l; l++) {
+ if ((*l)->link_edge_groups[0]->is_singularity &&
+ (*l)->link_edge_groups[1]->is_singularity) {
+ const uint v1 = (*l)->link_edge_groups[0]->new_vert;
+ const uint v2 = (*l)->link_edge_groups[1]->new_vert;
+ bool exists_already = false;
+ uint j = 0;
+ for (uint(*p)[2] = singularity_edges; j < totsingularity; p++, j++) {
+ if (((*p)[0] == v1 && (*p)[1] == v2) || ((*p)[0] == v2 && (*p)[1] == v1)) {
+ exists_already = true;
+ break;
+ }
+ }
+ if (!exists_already) {
+ has_singularities = true;
+ if (singularity_edges_len <= totsingularity) {
+ singularity_edges_len = totsingularity + 1;
+ singularity_edges = MEM_reallocN_id(singularity_edges,
+ singularity_edges_len *
+ sizeof(*singularity_edges),
+ "singularity_edges in solidify");
+ }
+ singularity_edges[totsingularity][0] = v1;
+ singularity_edges[totsingularity][1] = v2;
+ totsingularity++;
+ if (edge_adj_faces_len[i] == 1 && do_rim) {
+ numNewLoops -= 2;
+ numNewPolys--;
+ }
+ }
+ else {
+ numNewEdges--;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* Create Mesh *result with proper capacity. */
+ result = BKE_mesh_new_nomain_from_template(
+ mesh, (int)(numNewVerts), (int)(numNewEdges), 0, (int)(numNewLoops), (int)(numNewPolys));
+
+ mpoly = result->mpoly;
+ mloop = result->mloop;
+ medge = result->medge;
+ mvert = result->mvert;
+
+ int *origindex_edge = CustomData_get_layer(&result->edata, CD_ORIGINDEX);
+ int *origindex_poly = CustomData_get_layer(&result->pdata, CD_ORIGINDEX);
+
+ /* Make_new_verts. */
+ {
+ gs_ptr = orig_vert_groups_arr;
+ for (uint i = 0; i < numVerts; i++, gs_ptr++) {
+ EdgeGroup *gs = *gs_ptr;
+ if (gs) {
+ EdgeGroup *g = gs;
+ for (uint j = 0; g->valid; j++, g++) {
+ if (g->new_vert != MOD_SOLIDIFY_EMPTY_TAG) {
+ CustomData_copy_data(&mesh->vdata, &result->vdata, (int)i, (int)g->new_vert, 1);
+ copy_v3_v3(mvert[g->new_vert].co, g->co);
+ mvert[g->new_vert].flag = orig_mvert[i].flag;
+ }
+ }
+ }
+ }
+ }
+
+ result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+
+ /* Make edges. */
+ {
+ uint i = 0;
+ edge_index += totsingularity;
+ for (NewEdgeRef ***new_edges = orig_edge_data_arr; i < numEdges; i++, new_edges++) {
+ if (*new_edges && (do_shell || edge_adj_faces_len[i] == 1) && (**new_edges)->old_edge == i) {
+ for (NewEdgeRef **l = *new_edges; *l; l++) {
+ if ((*l)->new_edge != MOD_SOLIDIFY_EMPTY_TAG) {
+ const uint v1 = (*l)->link_edge_groups[0]->new_vert;
+ const uint v2 = (*l)->link_edge_groups[1]->new_vert;
+ uint insert = edge_index;
+ if (has_singularities && ((*l)->link_edge_groups[0]->is_singularity &&
+ (*l)->link_edge_groups[1]->is_singularity)) {
+ uint j = 0;
+ for (uint(*p)[2] = singularity_edges; j < totsingularity; p++, j++) {
+ if (((*p)[0] == v1 && (*p)[1] == v2) || ((*p)[0] == v2 && (*p)[1] == v1)) {
+ insert = j;
+ break;
+ }
+ }
+ BLI_assert(insert == j);
+ }
+ else {
+ edge_index++;
+ }
+ CustomData_copy_data(&mesh->edata, &result->edata, (int)i, (int)insert, 1);
+ BLI_assert(v1 != MOD_SOLIDIFY_EMPTY_TAG);
+ BLI_assert(v2 != MOD_SOLIDIFY_EMPTY_TAG);
+ medge[insert].v1 = v1;
+ medge[insert].v2 = v2;
+ medge[insert].flag = orig_medge[(*l)->old_edge].flag | ME_EDGEDRAW | ME_EDGERENDER;
+ medge[insert].crease = orig_medge[(*l)->old_edge].crease;
+ medge[insert].bweight = orig_medge[(*l)->old_edge].bweight;
+ (*l)->new_edge = insert;
+ }
+ }
+ }
+ }
+ }
+ if (singularity_edges) {
+ MEM_freeN(singularity_edges);
+ }
+
+ /* DEBUG CODE FOR BUGFIXING (can not be removed because every bugfix needs this badly!). */
+#if 0
+ {
+ gs_ptr = orig_vert_groups_arr;
+ for (uint i = 0; i < numVerts; i++, gs_ptr++) {
+ EdgeGroup *gs = *gs_ptr;
+ if (gs) {
+ for (EdgeGroup *g = gs; g->valid; g++) {
+ NewEdgeRef **e = g->edges;
+ for (uint j = 0; j < g->edges_len; j++, e++) {
+ printf("%u/%d, ", (*e)->old_edge, (int)(*e)->new_edge);
+ }
+ printf("(tg:%u)(s:%u,c:%d)\n", g->topo_group, g->split, g->is_orig_closed);
+ }
+ printf("\n");
+ }
+ }
+ }
+#endif
+
+ /* Make boundary edges/faces. */
+ {
+ gs_ptr = orig_vert_groups_arr;
+ for (uint i = 0; i < numVerts; i++, gs_ptr++) {
+ EdgeGroup *gs = *gs_ptr;
+ if (gs) {
+ EdgeGroup *g = gs;
+ EdgeGroup *g2 = gs;
+ EdgeGroup *last_g = NULL;
+ EdgeGroup *first_g = NULL;
+ /* Data calculation cache. */
+ char max_crease;
+ char last_max_crease = 0;
+ char first_max_crease = 0;
+ char max_bweight;
+ char last_max_bweight = 0;
+ char first_max_bweight = 0;
+ short flag;
+ short last_flag = 0;
+ short first_flag = 0;
+ for (uint j = 0; g->valid; g++) {
+ if ((do_rim && !g->is_orig_closed) || (do_shell && g->split)) {
+ max_crease = 0;
+ max_bweight = 0;
+ flag = 0;
+ for (uint k = 1; k < g->edges_len - 1; k++) {
+ ed = orig_medge + g->edges[k]->old_edge;
+ if (ed->crease > max_crease) {
+ max_crease = ed->crease;
+ }
+ if (ed->bweight > max_bweight) {
+ max_bweight = ed->bweight;
+ }
+ flag |= ed->flag;
+ }
+ if (!first_g) {
+ first_g = g;
+ first_max_crease = max_crease;
+ first_max_bweight = max_bweight;
+ first_flag = flag;
+ }
+ else {
+ last_g->open_face_edge = edge_index;
+ CustomData_copy_data(&mesh->edata,
+ &result->edata,
+ (int)last_g->edges[0]->old_edge,
+ (int)edge_index,
+ 1);
+ if (origindex_edge) {
+ origindex_edge[edge_index] = ORIGINDEX_NONE;
+ }
+ medge[edge_index].v1 = last_g->new_vert;
+ medge[edge_index].v2 = g->new_vert;
+ medge[edge_index].flag = ME_EDGEDRAW | ME_EDGERENDER |
+ ((last_flag | flag) & (ME_SEAM | ME_SHARP));
+ medge[edge_index].crease = MAX2(last_max_crease, max_crease);
+ medge[edge_index++].bweight = MAX2(last_max_bweight, max_bweight);
+ }
+ last_g = g;
+ last_max_crease = max_crease;
+ last_max_bweight = max_bweight;
+ last_flag = flag;
+ j++;
+ }
+ if (!(g + 1)->valid || g->topo_group != (g + 1)->topo_group) {
+ if (j == 2) {
+ last_g->open_face_edge = edge_index - 1;
+ }
+ if (j > 2) {
+ CustomData_copy_data(&mesh->edata,
+ &result->edata,
+ (int)last_g->edges[0]->old_edge,
+ (int)edge_index,
+ 1);
+ if (origindex_edge) {
+ origindex_edge[edge_index] = ORIGINDEX_NONE;
+ }
+ last_g->open_face_edge = edge_index;
+ medge[edge_index].v1 = last_g->new_vert;
+ medge[edge_index].v2 = first_g->new_vert;
+ medge[edge_index].flag = ME_EDGEDRAW | ME_EDGERENDER |
+ ((last_flag | first_flag) & (ME_SEAM | ME_SHARP));
+ medge[edge_index].crease = MAX2(last_max_crease, first_max_crease);
+ medge[edge_index++].bweight = MAX2(last_max_bweight, first_max_bweight);
+
+ /* Loop data. */
+ int *loops = MEM_malloc_arrayN(j, sizeof(*loops), "loops in solidify");
+ /* The #mat_nr is from consensus. */
+ short most_mat_nr = 0;
+ uint most_mat_nr_face = 0;
+ uint most_mat_nr_count = 0;
+ for (short l = 0; l < mat_nrs; l++) {
+ uint count = 0;
+ uint face = 0;
+ uint k = 0;
+ for (EdgeGroup *g3 = g2; g3->valid && k < j; g3++) {
+ if ((do_rim && !g3->is_orig_closed) || (do_shell && g3->split)) {
+ /* Check both far ends in terms of faces of an edge group. */
+ if (g3->edges[0]->faces[0]->face->mat_nr == l) {
+ face = g3->edges[0]->faces[0]->index;
+ count++;
+ }
+ NewEdgeRef *le = g3->edges[g3->edges_len - 1];
+ if (le->faces[1] && le->faces[1]->face->mat_nr == l) {
+ face = le->faces[1]->index;
+ count++;
+ }
+ else if (!le->faces[1] && le->faces[0]->face->mat_nr == l) {
+ face = le->faces[0]->index;
+ count++;
+ }
+ k++;
+ }
+ }
+ if (count > most_mat_nr_count) {
+ most_mat_nr = l;
+ most_mat_nr_face = face;
+ most_mat_nr_count = count;
+ }
+ }
+ CustomData_copy_data(
+ &mesh->pdata, &result->pdata, (int)most_mat_nr_face, (int)poly_index, 1);
+ if (origindex_poly) {
+ origindex_poly[poly_index] = ORIGINDEX_NONE;
+ }
+ mpoly[poly_index].loopstart = (int)loop_index;
+ mpoly[poly_index].totloop = (int)j;
+ mpoly[poly_index].mat_nr = most_mat_nr +
+ (g->is_orig_closed || !do_rim ? 0 : mat_ofs_rim);
+ CLAMP(mpoly[poly_index].mat_nr, 0, mat_nr_max);
+ mpoly[poly_index].flag = orig_mpoly[most_mat_nr_face].flag;
+ poly_index++;
+
+ for (uint k = 0; g2->valid && k < j; g2++) {
+ if ((do_rim && !g2->is_orig_closed) || (do_shell && g2->split)) {
+ MPoly *face = g2->edges[0]->faces[0]->face;
+ ml = orig_mloop + face->loopstart;
+ for (int l = 0; l < face->totloop; l++, ml++) {
+ if (vm[ml->v] == i) {
+ loops[k] = face->loopstart + l;
+ break;
+ }
+ }
+ k++;
+ }
+ }
+
+ if (!do_flip) {
+ for (uint k = 0; k < j; k++) {
+ CustomData_copy_data(&mesh->ldata, &result->ldata, loops[k], (int)loop_index, 1);
+ mloop[loop_index].v = medge[edge_index - j + k].v1;
+ mloop[loop_index++].e = edge_index - j + k;
+ }
+ }
+ else {
+ for (uint k = 1; k <= j; k++) {
+ CustomData_copy_data(
+ &mesh->ldata, &result->ldata, loops[j - k], (int)loop_index, 1);
+ mloop[loop_index].v = medge[edge_index - k].v2;
+ mloop[loop_index++].e = edge_index - k;
+ }
+ }
+ MEM_freeN(loops);
+ }
+ /* Reset everything for the next poly. */
+ j = 0;
+ last_g = NULL;
+ first_g = NULL;
+ last_max_crease = 0;
+ first_max_crease = 0;
+ last_max_bweight = 0;
+ first_max_bweight = 0;
+ last_flag = 0;
+ first_flag = 0;
+ }
+ }
+ }
+ }
+ }
+
+ /* Make boundary faces. */
+ if (do_rim) {
+ for (uint i = 0; i < numEdges; i++) {
+ if (edge_adj_faces_len[i] == 1 && orig_edge_data_arr[i] &&
+ (*orig_edge_data_arr[i])->old_edge == i) {
+ NewEdgeRef **new_edges = orig_edge_data_arr[i];
+
+ NewEdgeRef *edge1 = new_edges[0];
+ NewEdgeRef *edge2 = new_edges[1];
+ const bool v1_singularity = edge1->link_edge_groups[0]->is_singularity;
+ const bool v2_singularity = edge1->link_edge_groups[1]->is_singularity;
+ if (v1_singularity && v2_singularity) {
+ continue;
+ }
+
+ MPoly *face = (*new_edges)->faces[0]->face;
+ CustomData_copy_data(
+ &mesh->pdata, &result->pdata, (int)(*new_edges)->faces[0]->index, (int)poly_index, 1);
+ mpoly[poly_index].loopstart = (int)loop_index;
+ mpoly[poly_index].totloop = 4 - (int)(v1_singularity || v2_singularity);
+ mpoly[poly_index].mat_nr = face->mat_nr + mat_ofs_rim;
+ CLAMP(mpoly[poly_index].mat_nr, 0, mat_nr_max);
+ mpoly[poly_index].flag = face->flag;
+ poly_index++;
+
+ int loop1 = -1;
+ int loop2 = -1;
+ ml = orig_mloop + face->loopstart;
+ const uint old_v1 = vm[orig_medge[edge1->old_edge].v1];
+ const uint old_v2 = vm[orig_medge[edge1->old_edge].v2];
+ for (uint j = 0; j < face->totloop; j++, ml++) {
+ if (vm[ml->v] == old_v1) {
+ loop1 = face->loopstart + (int)j;
+ }
+ else if (vm[ml->v] == old_v2) {
+ loop2 = face->loopstart + (int)j;
+ }
+ }
+ BLI_assert(loop1 != -1 && loop2 != -1);
+ MEdge *open_face_edge;
+ uint open_face_edge_index;
+ if (!do_flip) {
+ CustomData_copy_data(&mesh->ldata, &result->ldata, loop1, (int)loop_index, 1);
+ mloop[loop_index].v = medge[edge1->new_edge].v1;
+ mloop[loop_index++].e = edge1->new_edge;
+
+ if (!v2_singularity) {
+ open_face_edge_index = edge1->link_edge_groups[1]->open_face_edge;
+ CustomData_copy_data(&mesh->ldata, &result->ldata, loop2, (int)loop_index, 1);
+ mloop[loop_index].v = medge[edge1->new_edge].v2;
+ open_face_edge = medge + open_face_edge_index;
+ if (ELEM(medge[edge2->new_edge].v2, open_face_edge->v1, open_face_edge->v2)) {
+ mloop[loop_index++].e = open_face_edge_index;
+ }
+ else {
+ mloop[loop_index++].e = edge2->link_edge_groups[1]->open_face_edge;
+ }
+ }
+
+ CustomData_copy_data(&mesh->ldata, &result->ldata, loop2, (int)loop_index, 1);
+ mloop[loop_index].v = medge[edge2->new_edge].v2;
+ mloop[loop_index++].e = edge2->new_edge;
+
+ if (!v1_singularity) {
+ open_face_edge_index = edge2->link_edge_groups[0]->open_face_edge;
+ CustomData_copy_data(&mesh->ldata, &result->ldata, loop1, (int)loop_index, 1);
+ mloop[loop_index].v = medge[edge2->new_edge].v1;
+ open_face_edge = medge + open_face_edge_index;
+ if (ELEM(medge[edge1->new_edge].v1, open_face_edge->v1, open_face_edge->v2)) {
+ mloop[loop_index++].e = open_face_edge_index;
+ }
+ else {
+ mloop[loop_index++].e = edge1->link_edge_groups[0]->open_face_edge;
+ }
+ }
+ }
+ else {
+ if (!v1_singularity) {
+ open_face_edge_index = edge1->link_edge_groups[0]->open_face_edge;
+ CustomData_copy_data(&mesh->ldata, &result->ldata, loop1, (int)loop_index, 1);
+ mloop[loop_index].v = medge[edge1->new_edge].v1;
+ open_face_edge = medge + open_face_edge_index;
+ if (ELEM(medge[edge2->new_edge].v1, open_face_edge->v1, open_face_edge->v2)) {
+ mloop[loop_index++].e = open_face_edge_index;
+ }
+ else {
+ mloop[loop_index++].e = edge2->link_edge_groups[0]->open_face_edge;
+ }
+ }
+
+ CustomData_copy_data(&mesh->ldata, &result->ldata, loop1, (int)loop_index, 1);
+ mloop[loop_index].v = medge[edge2->new_edge].v1;
+ mloop[loop_index++].e = edge2->new_edge;
+
+ if (!v2_singularity) {
+ open_face_edge_index = edge2->link_edge_groups[1]->open_face_edge;
+ CustomData_copy_data(&mesh->ldata, &result->ldata, loop2, (int)loop_index, 1);
+ mloop[loop_index].v = medge[edge2->new_edge].v2;
+ open_face_edge = medge + open_face_edge_index;
+ if (ELEM(medge[edge1->new_edge].v2, open_face_edge->v1, open_face_edge->v2)) {
+ mloop[loop_index++].e = open_face_edge_index;
+ }
+ else {
+ mloop[loop_index++].e = edge1->link_edge_groups[1]->open_face_edge;
+ }
+ }
+
+ CustomData_copy_data(&mesh->ldata, &result->ldata, loop2, (int)loop_index, 1);
+ mloop[loop_index].v = medge[edge1->new_edge].v2;
+ mloop[loop_index++].e = edge1->new_edge;
+ }
+ }
+ }
+ }
+
+ /* Make faces. */
+ if (do_shell) {
+ NewFaceRef *fr = face_sides_arr;
+ uint *face_loops = MEM_malloc_arrayN(
+ largest_ngon * 2, sizeof(*face_loops), "face_loops in solidify");
+ uint *face_verts = MEM_malloc_arrayN(
+ largest_ngon * 2, sizeof(*face_verts), "face_verts in solidify");
+ uint *face_edges = MEM_malloc_arrayN(
+ largest_ngon * 2, sizeof(*face_edges), "face_edges in solidify");
+ for (uint i = 0; i < numPolys * 2; i++, fr++) {
+ const uint loopstart = (uint)fr->face->loopstart;
+ uint totloop = (uint)fr->face->totloop;
+ uint valid_edges = 0;
+ uint k = 0;
+ while (totloop > 0 && (!fr->link_edges[totloop - 1] ||
+ fr->link_edges[totloop - 1]->new_edge == MOD_SOLIDIFY_EMPTY_TAG)) {
+ totloop--;
+ }
+ if (totloop > 0) {
+ NewEdgeRef *prior_edge = fr->link_edges[totloop - 1];
+ uint prior_flip = (uint)(vm[orig_medge[prior_edge->old_edge].v1] ==
+ vm[orig_mloop[loopstart + (totloop - 1)].v]);
+ for (uint j = 0; j < totloop; j++) {
+ NewEdgeRef *new_edge = fr->link_edges[j];
+ if (new_edge && new_edge->new_edge != MOD_SOLIDIFY_EMPTY_TAG) {
+ valid_edges++;
+ const uint flip = (uint)(vm[orig_medge[new_edge->old_edge].v2] ==
+ vm[orig_mloop[loopstart + j].v]);
+ BLI_assert(flip ||
+ vm[orig_medge[new_edge->old_edge].v1] == vm[orig_mloop[loopstart + j].v]);
+ /* The vert thats in the current loop. */
+ const uint new_v1 = new_edge->link_edge_groups[flip]->new_vert;
+ /* The vert thats in the next loop. */
+ const uint new_v2 = new_edge->link_edge_groups[1 - flip]->new_vert;
+ if (k == 0 || face_verts[k - 1] != new_v1) {
+ face_loops[k] = loopstart + j;
+ if (fr->reversed) {
+ face_edges[k] = prior_edge->link_edge_groups[prior_flip]->open_face_edge;
+ }
+ else {
+ face_edges[k] = new_edge->link_edge_groups[flip]->open_face_edge;
+ }
+ BLI_assert(k == 0 || medge[face_edges[k]].v2 == face_verts[k - 1] ||
+ medge[face_edges[k]].v1 == face_verts[k - 1]);
+ BLI_assert(face_edges[k] == MOD_SOLIDIFY_EMPTY_TAG ||
+ medge[face_edges[k]].v2 == new_v1 || medge[face_edges[k]].v1 == new_v1);
+ face_verts[k++] = new_v1;
+ }
+ prior_edge = new_edge;
+ prior_flip = 1 - flip;
+ if (j < totloop - 1 || face_verts[0] != new_v2) {
+ face_loops[k] = loopstart + (j + 1) % totloop;
+ face_edges[k] = new_edge->new_edge;
+ face_verts[k++] = new_v2;
+ }
+ else {
+ face_edges[0] = new_edge->new_edge;
+ }
+ }
+ }
+ if (k > 2 && valid_edges > 2) {
+ CustomData_copy_data(&mesh->pdata, &result->pdata, (int)(i / 2), (int)poly_index, 1);
+ mpoly[poly_index].loopstart = (int)loop_index;
+ mpoly[poly_index].totloop = (int)k;
+ mpoly[poly_index].mat_nr = fr->face->mat_nr + mat_ofs;
+ CLAMP(mpoly[poly_index].mat_nr, 0, mat_nr_max);
+ mpoly[poly_index].flag = fr->face->flag;
+ if (fr->reversed != do_flip) {
+ for (int l = (int)k - 1; l >= 0; l--) {
+ CustomData_copy_data(
+ &mesh->ldata, &result->ldata, (int)face_loops[l], (int)loop_index, 1);
+ mloop[loop_index].v = face_verts[l];
+ mloop[loop_index++].e = face_edges[l];
+ }
+ }
+ else {
+ uint l = k - 1;
+ for (uint next_l = 0; next_l < k; next_l++) {
+ CustomData_copy_data(
+ &mesh->ldata, &result->ldata, (int)face_loops[l], (int)loop_index, 1);
+ mloop[loop_index].v = face_verts[l];
+ mloop[loop_index++].e = face_edges[next_l];
+ l = next_l;
+ }
+ }
+ poly_index++;
+ }
+ }
+ }
+ MEM_freeN(face_loops);
+ MEM_freeN(face_verts);
+ MEM_freeN(face_edges);
+ }
+ if (edge_index != numNewEdges) {
+ modifier_setError(
+ md, "Internal Error: edges array wrong size: %u instead of %u", numNewEdges, edge_index);
+ }
+ if (poly_index != numNewPolys) {
+ modifier_setError(
+ md, "Internal Error: polys array wrong size: %u instead of %u", numNewPolys, poly_index);
+ }
+ if (loop_index != numNewLoops) {
+ modifier_setError(
+ md, "Internal Error: loops array wrong size: %u instead of %u", numNewLoops, loop_index);
+ }
+ BLI_assert(edge_index == numNewEdges);
+ BLI_assert(poly_index == numNewPolys);
+ BLI_assert(loop_index == numNewLoops);
+
+ /* Free remaining memory */
+ {
+ MEM_freeN(vm);
+ MEM_freeN(edge_adj_faces_len);
+ uint i = 0;
+ for (EdgeGroup **p = orig_vert_groups_arr; i < numVerts; i++, p++) {
+ if (*p) {
+ for (EdgeGroup *eg = *p; eg->valid; eg++) {
+ MEM_freeN(eg->edges);
+ }
+ MEM_freeN(*p);
+ }
+ }
+ MEM_freeN(orig_vert_groups_arr);
+ i = numEdges;
+ for (NewEdgeRef ***p = orig_edge_data_arr + (numEdges - 1); i > 0; i--, p--) {
+ if (*p && (**p)->old_edge == i - 1) {
+ for (NewEdgeRef **l = *p; *l; l++) {
+ MEM_freeN(*l);
+ }
+ MEM_freeN(*p);
+ }
+ }
+ MEM_freeN(orig_edge_data_arr);
+ MEM_freeN(orig_edge_lengths);
+ i = 0;
+ for (NewFaceRef *p = face_sides_arr; i < numPolys * 2; i++, p++) {
+ MEM_freeN(p->link_edges);
+ }
+ MEM_freeN(face_sides_arr);
+ MEM_freeN(poly_nors);
+ }
+
+#undef MOD_SOLIDIFY_EMPTY_TAG
+
+ return result;
+}
+
+/** \} */
diff --git a/source/blender/modifiers/intern/MOD_solidify_util.h b/source/blender/modifiers/intern/MOD_solidify_util.h
new file mode 100644
index 00000000000..dba360dc1ce
--- /dev/null
+++ b/source/blender/modifiers/intern/MOD_solidify_util.h
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+/** \file
+ * \ingroup modifiers
+ */
+
+#ifndef __MOD_MESHCACHE_UTIL_H__
+#define __MOD_MESHCACHE_UTIL_H__
+
+/* MOD_solidify_extrude.c */
+Mesh *MOD_solidify_extrude_applyModifier(ModifierData *md,
+ const ModifierEvalContext *ctx,
+ Mesh *mesh);
+
+/* MOD_solidify_nonmanifold.c */
+Mesh *MOD_solidify_nonmanifold_applyModifier(ModifierData *md,
+ const ModifierEvalContext *ctx,
+ Mesh *mesh);
+
+#endif /* __MOD_MESHCACHE_UTIL_H__ */