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
diff options
context:
space:
mode:
authorYimingWu <xp8110@outlook.com>2019-07-01 04:49:08 +0300
committerYimingWu <xp8110@outlook.com>2019-07-01 04:49:08 +0300
commit27ca5cdfeee638226126822191b7e69cf5b90e79 (patch)
tree8bd4ebdc2dfcdaab35d93b05be67d4f2963ec21a /source/blender
parent37c3aa8eabbb3ba5f5718070744c0c60b67f0f21 (diff)
parentbbb3500c97167c070a76373e023bdd8820d3ca41 (diff)
Merge branch 'master' into soc-2019-npr
Diffstat (limited to 'source/blender')
-rw-r--r--source/blender/blenkernel/BKE_gpencil.h1
-rw-r--r--source/blender/blenkernel/intern/constraint.c13
-rw-r--r--source/blender/blenkernel/intern/gpencil.c80
-rw-r--r--source/blender/blenkernel/intern/writeffmpeg.c16
-rw-r--r--source/blender/blenloader/intern/versioning_legacy.c21
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_nodes.cc2
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations.cc7
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc2
-rw-r--r--source/blender/depsgraph/intern/builder/deg_builder_rna.cc2
-rw-r--r--source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc1
-rw-r--r--source/blender/depsgraph/intern/node/deg_node.cc2
-rw-r--r--source/blender/depsgraph/intern/node/deg_node.h1
-rw-r--r--source/blender/depsgraph/intern/node/deg_node_component.cc2
-rw-r--r--source/blender/depsgraph/intern/node/deg_node_component.h1
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_draw_utils.c2
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_engine.c6
-rw-r--r--source/blender/draw/engines/gpencil/gpencil_engine.h4
-rw-r--r--source/blender/draw/engines/gpencil/shaders/gpencil_blend_frag.glsl4
-rw-r--r--source/blender/draw/modes/edit_mesh_mode_text.c2
-rw-r--r--source/blender/editors/animation/keyframing.c6
-rw-r--r--source/blender/editors/animation/keyingsets.c10
-rw-r--r--source/blender/editors/gpencil/gpencil_edit.c102
-rw-r--r--source/blender/editors/include/ED_gpencil.h1
-rw-r--r--source/blender/editors/interface/interface_widgets.c117
-rw-r--r--source/blender/editors/mesh/editmesh_bevel.c4
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c702
-rw-r--r--source/blender/editors/object/object_add.c20
-rw-r--r--source/blender/editors/object/object_intern.h2
-rw-r--r--source/blender/editors/object/object_modes.c7
-rw-r--r--source/blender/editors/object/object_ops.c2
-rw-r--r--source/blender/editors/render/render_preview.c14
-rw-r--r--source/blender/editors/screen/screendump.c50
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.c2
-rw-r--r--source/blender/editors/space_outliner/outliner_tree.c43
-rw-r--r--source/blender/editors/space_sequencer/sequencer_edit.c1
-rw-r--r--source/blender/editors/space_view3d/view3d_edit.c2
-rw-r--r--source/blender/editors/util/gizmo_utils.c7
-rw-r--r--source/blender/makesdna/DNA_constraint_types.h9
-rw-r--r--source/blender/makesdna/DNA_object_enums.h6
-rw-r--r--source/blender/makesrna/intern/rna_armature.c2
-rw-r--r--source/blender/makesrna/intern/rna_constraint.c5
-rw-r--r--source/blender/makesrna/intern/rna_gpencil.c4
-rw-r--r--source/blender/makesrna/intern/rna_object.c2
-rw-r--r--source/blender/makesrna/intern/rna_screen.c7
-rw-r--r--source/blender/windowmanager/WM_api.h2
-rw-r--r--source/blender/windowmanager/gizmo/WM_gizmo_api.h9
-rw-r--r--source/blender/windowmanager/gizmo/WM_gizmo_types.h8
-rw-r--r--source/blender/windowmanager/gizmo/intern/wm_gizmo_group.c32
-rw-r--r--source/blender/windowmanager/gizmo/intern/wm_gizmo_intern.h3
-rw-r--r--source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c38
-rw-r--r--source/blender/windowmanager/intern/wm_toolsystem.c53
-rw-r--r--source/blender/windowmanager/intern/wm_window.c44
52 files changed, 927 insertions, 558 deletions
diff --git a/source/blender/blenkernel/BKE_gpencil.h b/source/blender/blenkernel/BKE_gpencil.h
index 25d44ffca55..ecb22b02610 100644
--- a/source/blender/blenkernel/BKE_gpencil.h
+++ b/source/blender/blenkernel/BKE_gpencil.h
@@ -221,6 +221,7 @@ bool BKE_gpencil_smooth_stroke(struct bGPDstroke *gps, int i, float inf);
bool BKE_gpencil_smooth_stroke_strength(struct bGPDstroke *gps, int point_index, float influence);
bool BKE_gpencil_smooth_stroke_thickness(struct bGPDstroke *gps, int point_index, float influence);
bool BKE_gpencil_smooth_stroke_uv(struct bGPDstroke *gps, int point_index, float influence);
+bool BKE_gpencil_close_stroke(struct bGPDstroke *gps);
void BKE_gpencil_get_range_selected(struct bGPDlayer *gpl, int *r_initframe, int *r_endframe);
float BKE_gpencil_multiframe_falloff_calc(
diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c
index 5766e84f960..793dc910394 100644
--- a/source/blender/blenkernel/intern/constraint.c
+++ b/source/blender/blenkernel/intern/constraint.c
@@ -3329,7 +3329,6 @@ static void minmax_new_data(void *cdata)
data->minmaxflag = TRACK_Z;
data->offset = 0.0f;
- zero_v3(data->cache);
data->flag = 0;
}
@@ -3426,15 +3425,6 @@ static void minmax_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *targ
if (val1 > val2) {
obmat[3][index] = tarmat[3][index] + data->offset;
- if (data->flag & MINMAX_STICKY) {
- if (data->flag & MINMAX_STUCK) {
- copy_v3_v3(obmat[3], data->cache);
- }
- else {
- copy_v3_v3(data->cache, obmat[3]);
- data->flag |= MINMAX_STUCK;
- }
- }
if (data->flag & MINMAX_USEROT) {
/* get out of localspace */
mul_m4_m4m4(tmat, ct->matrix, obmat);
@@ -3444,9 +3434,6 @@ static void minmax_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *targ
copy_v3_v3(cob->matrix[3], obmat[3]);
}
}
- else {
- data->flag &= ~MINMAX_STUCK;
- }
}
}
diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c
index 8f9a740cba4..43eee8ec2de 100644
--- a/source/blender/blenkernel/intern/gpencil.c
+++ b/source/blender/blenkernel/intern/gpencil.c
@@ -2270,3 +2270,83 @@ bool BKE_gpencil_trim_stroke(bGPDstroke *gps)
}
return intersect;
}
+
+/**
+ * Close stroke
+ * \param gps: Stroke to close
+ */
+bool BKE_gpencil_close_stroke(bGPDstroke *gps)
+{
+ bGPDspoint *pt1 = NULL;
+ bGPDspoint *pt2 = NULL;
+
+ /* Only can close a stroke with 3 points or more. */
+ if (gps->totpoints < 3) {
+ return false;
+ }
+
+ /* Calc average distance between points to get same level of sampling. */
+ float dist_tot = 0.0f;
+ for (int i = 0; i < gps->totpoints - 1; i++) {
+ pt1 = &gps->points[i];
+ pt2 = &gps->points[i + 1];
+ dist_tot += len_v3v3(&pt1->x, &pt2->x);
+ }
+ /* Calc the average distance. */
+ float dist_avg = dist_tot / (gps->totpoints - 1);
+
+ /* Calc distance between last and first point. */
+ pt1 = &gps->points[gps->totpoints - 1];
+ pt2 = &gps->points[0];
+ float dist_close = len_v3v3(&pt1->x, &pt2->x);
+
+ /* Calc number of points required using the average distance. */
+ int tot_newpoints = MAX2(dist_close / dist_avg, 1);
+
+ /* Resize stroke array. */
+ int old_tot = gps->totpoints;
+ gps->totpoints += tot_newpoints;
+ gps->points = MEM_recallocN(gps->points, sizeof(*gps->points) * gps->totpoints);
+ if (gps->dvert != NULL) {
+ gps->dvert = MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * gps->totpoints);
+ }
+
+ /* Generate new points */
+ pt1 = &gps->points[old_tot - 1];
+ pt2 = &gps->points[0];
+ bGPDspoint *pt = &gps->points[old_tot];
+ for (int i = 1; i < tot_newpoints + 1; i++, pt++) {
+ float step = ((float)i / (float)tot_newpoints);
+ /* Clamp last point to be near, but not on top of first point. */
+ CLAMP(step, 0.0f, 0.99f);
+
+ /* Average point. */
+ interp_v3_v3v3(&pt->x, &pt1->x, &pt2->x, step);
+ pt->pressure = interpf(pt2->pressure, pt1->pressure, step);
+ pt->strength = interpf(pt2->strength, pt1->strength, step);
+ pt->flag = 0;
+
+ /* Set weights. */
+ if (gps->dvert != NULL) {
+ MDeformVert *dvert1 = &gps->dvert[old_tot - 1];
+ MDeformWeight *dw1 = defvert_verify_index(dvert1, 0);
+ float weight_1 = dw1 ? dw1->weight : 0.0f;
+
+ MDeformVert *dvert2 = &gps->dvert[0];
+ MDeformWeight *dw2 = defvert_verify_index(dvert2, 0);
+ float weight_2 = dw2 ? dw2->weight : 0.0f;
+
+ MDeformVert *dvert_final = &gps->dvert[old_tot + i - 1];
+ dvert_final->totweight = 0;
+ MDeformWeight *dw = defvert_verify_index(dvert_final, 0);
+ if (dvert_final->dw) {
+ dw->weight = interpf(weight_2, weight_1, step);
+ }
+ }
+ }
+
+ /* Enable cyclic flag. */
+ gps->flag |= GP_STROKE_CYCLIC;
+
+ return true;
+}
diff --git a/source/blender/blenkernel/intern/writeffmpeg.c b/source/blender/blenkernel/intern/writeffmpeg.c
index e31e7fb5b63..681c03e25b6 100644
--- a/source/blender/blenkernel/intern/writeffmpeg.c
+++ b/source/blender/blenkernel/intern/writeffmpeg.c
@@ -25,12 +25,6 @@
# include <stdlib.h>
-# include <libavformat/avformat.h>
-# include <libavcodec/avcodec.h>
-# include <libavutil/rational.h>
-# include <libavutil/samplefmt.h>
-# include <libswscale/swscale.h>
-
# include "MEM_guardedalloc.h"
# include "DNA_scene_types.h"
@@ -56,6 +50,14 @@
# include "IMB_imbuf.h"
+/* This needs to be included after BLI_math_base.h otherwise it will redefine some math defines
+ * like M_SQRT1_2 leading to warnings with MSVC */
+# include <libavformat/avformat.h>
+# include <libavcodec/avcodec.h>
+# include <libavutil/rational.h>
+# include <libavutil/samplefmt.h>
+# include <libswscale/swscale.h>
+
# include "ffmpeg_compat.h"
struct StampData;
@@ -599,7 +601,7 @@ static AVStream *alloc_video_stream(FFMpegContext *context,
/* This calculates a fraction (DENUM_MAX / num) which approximates the scene frame rate
* (frs_sec / frs_sec_base). It uses the maximum denominator allowed by FFmpeg.
*/
- const double DENUM_MAX = (codec_id == AV_CODEC_ID_MPEG4) ? (1L << 16) - 1 : (1L << 31) - 1;
+ const double DENUM_MAX = (codec_id == AV_CODEC_ID_MPEG4) ? (1UL << 16) - 1 : (1UL << 31) - 1;
const double num = (DENUM_MAX / (double)rd->frs_sec) * rd->frs_sec_base;
c->time_base.den = (int)DENUM_MAX;
diff --git a/source/blender/blenloader/intern/versioning_legacy.c b/source/blender/blenloader/intern/versioning_legacy.c
index df26ca37826..69802b35ff9 100644
--- a/source/blender/blenloader/intern/versioning_legacy.c
+++ b/source/blender/blenloader/intern/versioning_legacy.c
@@ -1738,17 +1738,6 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
bConstraint *curcon;
for (curcon = list->first; curcon; curcon = curcon->next) {
switch (curcon->type) {
- case CONSTRAINT_TYPE_MINMAX: {
- bMinMaxConstraint *data = curcon->data;
- if (data->sticky == 1) {
- data->flag |= MINMAX_STICKY;
- }
- else {
- data->flag &= ~MINMAX_STICKY;
- }
-
- break;
- }
case CONSTRAINT_TYPE_ROTLIKE: {
bRotateLikeConstraint *data = curcon->data;
@@ -1770,16 +1759,6 @@ void blo_do_versions_pre250(FileData *fd, Library *lib, Main *bmain)
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
for (curcon = pchan->constraints.first; curcon; curcon = curcon->next) {
switch (curcon->type) {
- case CONSTRAINT_TYPE_MINMAX: {
- bMinMaxConstraint *data = curcon->data;
- if (data->sticky == 1) {
- data->flag |= MINMAX_STICKY;
- }
- else {
- data->flag &= ~MINMAX_STICKY;
- }
- break;
- }
case CONSTRAINT_TYPE_KINEMATIC: {
bKinematicConstraint *data = curcon->data;
if (!(data->flag & CONSTRAINT_IK_POS)) {
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
index ae72720c267..e65dd3b4560 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc
@@ -1306,7 +1306,7 @@ void DepsgraphNodeBuilder::build_armature(bArmature *armature)
build_animdata(&armature->id);
build_parameters(&armature->id);
/* Make sure pose is up-to-date with armature updates. */
- add_operation_node(&armature->id, NodeType::PARAMETERS, OperationCode::ARMATURE_EVAL);
+ add_operation_node(&armature->id, NodeType::ARMATURE, OperationCode::ARMATURE_EVAL);
}
void DepsgraphNodeBuilder::build_camera(Camera *camera)
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
index 60233ecd304..c7f6116e81d 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc
@@ -898,6 +898,13 @@ void DepsgraphRelationBuilder::build_object_pointcache(Object *object)
OperationKey transform_key(
&object->id, NodeType::TRANSFORM, OperationCode::TRANSFORM_SIMULATION_INIT);
add_relation(point_cache_key, transform_key, "Point Cache -> Rigid Body");
+ /* Manual changes to effectors need to invalidate simulation. */
+ OperationKey rigidbody_rebuild_key(
+ &scene_->id, NodeType::TRANSFORM, OperationCode::RIGIDBODY_REBUILD);
+ add_relation(rigidbody_rebuild_key,
+ point_cache_key,
+ "Rigid Body Rebuild -> Point Cache Reset",
+ RELATION_FLAG_FLUSH_USER_EDIT_ONLY);
}
else {
flag = FLAG_GEOMETRY;
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc
index f8313dc854b..e254f8df0d2 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_relations_rig.cc
@@ -263,7 +263,7 @@ void DepsgraphRelationBuilder::build_rig(Object *object)
add_relation(pose_init_ik_key, pose_done_key, "Pose Init IK -> Pose Cleanup");
/* Make sure pose is up-to-date with armature updates. */
build_armature(armature);
- OperationKey armature_key(&armature->id, NodeType::PARAMETERS, OperationCode::ARMATURE_EVAL);
+ OperationKey armature_key(&armature->id, NodeType::ARMATURE, OperationCode::ARMATURE_EVAL);
add_relation(armature_key, pose_init_key, "Data dependency");
/* Run cleanup even when there are no bones. */
add_relation(pose_init_key, pose_cleanup_key, "Init -> Cleanup");
diff --git a/source/blender/depsgraph/intern/builder/deg_builder_rna.cc b/source/blender/depsgraph/intern/builder/deg_builder_rna.cc
index 3c3342fd3c0..a8d357cd5bd 100644
--- a/source/blender/depsgraph/intern/builder/deg_builder_rna.cc
+++ b/source/blender/depsgraph/intern/builder/deg_builder_rna.cc
@@ -228,7 +228,7 @@ RNANodeIdentifier RNANodeQuery::construct_node_identifier(const PointerRNA *ptr,
/* Armature-level bone mapped to Armature Eval, and thus Pose Init.
* Drivers have special code elsewhere that links them to the pose
* bone components, instead of using this generic code. */
- node_identifier.type = NodeType::PARAMETERS;
+ node_identifier.type = NodeType::ARMATURE;
node_identifier.operation_code = OperationCode::ARMATURE_EVAL;
/* If trying to look up via an Object, e.g. due to lookup via
* obj.pose.bones[].bone in a driver attached to the Object,
diff --git a/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc b/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc
index c4455a6e59f..9c4a672b805 100644
--- a/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc
+++ b/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc
@@ -435,6 +435,7 @@ static void deg_debug_graphviz_node(const DebugContext &ctx, const Node *node)
case NodeType::DUPLI:
case NodeType::SYNCHRONIZATION:
case NodeType::AUDIO:
+ case NodeType::ARMATURE:
case NodeType::GENERIC_DATABLOCK: {
ComponentNode *comp_node = (ComponentNode *)node;
if (!comp_node->operations.empty()) {
diff --git a/source/blender/depsgraph/intern/node/deg_node.cc b/source/blender/depsgraph/intern/node/deg_node.cc
index 7df96330ef0..289c9a76cc7 100644
--- a/source/blender/depsgraph/intern/node/deg_node.cc
+++ b/source/blender/depsgraph/intern/node/deg_node.cc
@@ -107,6 +107,8 @@ const char *nodeTypeAsString(NodeType type)
return "SYNCHRONIZATION";
case NodeType::AUDIO:
return "AUDIO";
+ case NodeType::ARMATURE:
+ return "ARMATURE";
case NodeType::GENERIC_DATABLOCK:
return "GENERIC_DATABLOCK";
diff --git a/source/blender/depsgraph/intern/node/deg_node.h b/source/blender/depsgraph/intern/node/deg_node.h
index e350cc9a6f4..705dae41470 100644
--- a/source/blender/depsgraph/intern/node/deg_node.h
+++ b/source/blender/depsgraph/intern/node/deg_node.h
@@ -94,6 +94,7 @@ enum class NodeType {
OBJECT_FROM_LAYER,
/* Audio-related evaluation. */
AUDIO,
+ ARMATURE,
/* Un-interestying datablock, which is a part of dependency graph, but does
* not have very distinctive update procedure. */
GENERIC_DATABLOCK,
diff --git a/source/blender/depsgraph/intern/node/deg_node_component.cc b/source/blender/depsgraph/intern/node/deg_node_component.cc
index f67a81f594f..830c53cfc76 100644
--- a/source/blender/depsgraph/intern/node/deg_node_component.cc
+++ b/source/blender/depsgraph/intern/node/deg_node_component.cc
@@ -365,6 +365,7 @@ DEG_COMPONENT_NODE_DEFINE(ObjectFromLayer, OBJECT_FROM_LAYER, 0);
DEG_COMPONENT_NODE_DEFINE(Dupli, DUPLI, 0);
DEG_COMPONENT_NODE_DEFINE(Synchronization, SYNCHRONIZATION, 0);
DEG_COMPONENT_NODE_DEFINE(Audio, AUDIO, 0);
+DEG_COMPONENT_NODE_DEFINE(Armature, ARMATURE, 0);
DEG_COMPONENT_NODE_DEFINE(GenericDatablock, GENERIC_DATABLOCK, 0);
/* Node Types Register =================================== */
@@ -392,6 +393,7 @@ void deg_register_component_depsnodes()
register_node_typeinfo(&DNTI_DUPLI);
register_node_typeinfo(&DNTI_SYNCHRONIZATION);
register_node_typeinfo(&DNTI_AUDIO);
+ register_node_typeinfo(&DNTI_ARMATURE);
register_node_typeinfo(&DNTI_GENERIC_DATABLOCK);
}
diff --git a/source/blender/depsgraph/intern/node/deg_node_component.h b/source/blender/depsgraph/intern/node/deg_node_component.h
index 733d32e9c2d..53fbc6e617c 100644
--- a/source/blender/depsgraph/intern/node/deg_node_component.h
+++ b/source/blender/depsgraph/intern/node/deg_node_component.h
@@ -187,6 +187,7 @@ DEG_COMPONENT_NODE_DECLARE_NO_COW_TAG_ON_UPDATE(ObjectFromLayer);
DEG_COMPONENT_NODE_DECLARE_GENERIC(Dupli);
DEG_COMPONENT_NODE_DECLARE_GENERIC(Synchronization);
DEG_COMPONENT_NODE_DECLARE_GENERIC(Audio);
+DEG_COMPONENT_NODE_DECLARE_GENERIC(Armature);
DEG_COMPONENT_NODE_DECLARE_GENERIC(GenericDatablock);
/* Bone Component */
diff --git a/source/blender/draw/engines/gpencil/gpencil_draw_utils.c b/source/blender/draw/engines/gpencil/gpencil_draw_utils.c
index 13b17af8f76..97d2d3393a9 100644
--- a/source/blender/draw/engines/gpencil/gpencil_draw_utils.c
+++ b/source/blender/draw/engines/gpencil/gpencil_draw_utils.c
@@ -1827,7 +1827,7 @@ static void gpencil_shgroups_create(GPENCIL_e_data *e_data,
if ((shgrp != NULL) && (tag_first)) {
array_elm = &cache_ob->shgrp_array[idx];
array_elm->mode = idx == 0 ? eGplBlendMode_Regular : gpl->blend_mode;
- array_elm->clamp_layer = gpl->flag & GP_LAYER_USE_MASK;
+ array_elm->mask_layer = gpl->flag & GP_LAYER_USE_MASK;
array_elm->blend_opacity = gpl->opacity;
array_elm->init_shgrp = shgrp;
cache_ob->tot_layers++;
diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.c b/source/blender/draw/engines/gpencil/gpencil_engine.c
index 967694f082b..55d408a42d8 100644
--- a/source/blender/draw/engines/gpencil/gpencil_engine.c
+++ b/source/blender/draw/engines/gpencil/gpencil_engine.c
@@ -549,7 +549,7 @@ void GPENCIL_cache_init(void *vedata)
DRW_shgroup_uniform_texture_ref(blend_shgrp, "blendColor", &stl->g_data->temp_color_tx_fx);
DRW_shgroup_uniform_texture_ref(blend_shgrp, "blendDepth", &stl->g_data->temp_depth_tx_fx);
DRW_shgroup_uniform_int(blend_shgrp, "mode", &stl->storage->blend_mode, 1);
- DRW_shgroup_uniform_int(blend_shgrp, "clamp_layer", &stl->storage->clamp_layer, 1);
+ DRW_shgroup_uniform_int(blend_shgrp, "mask_layer", &stl->storage->mask_layer, 1);
DRW_shgroup_uniform_int(mix_shgrp, "tonemapping", &stl->storage->tonemapping, 1);
/* create effects passes */
@@ -1043,7 +1043,7 @@ void GPENCIL_draw_scene(void *ved)
array_elm = &cache_ob->shgrp_array[e];
if (((array_elm->mode == eGplBlendMode_Regular) && (!use_blend) &&
- (!array_elm->clamp_layer)) ||
+ (!array_elm->mask_layer)) ||
(e == 0)) {
if (init_shgrp == NULL) {
init_shgrp = array_elm->init_shgrp;
@@ -1069,7 +1069,7 @@ void GPENCIL_draw_scene(void *ved)
GPU_framebuffer_bind(fbl->temp_fb_b);
GPU_framebuffer_clear_color_depth_stencil(fbl->temp_fb_b, clearcol, 1.0f, 0x0);
stl->storage->blend_mode = array_elm->mode;
- stl->storage->clamp_layer = (int)array_elm->clamp_layer;
+ stl->storage->mask_layer = (int)array_elm->mask_layer;
stl->storage->tonemapping = DRW_state_do_color_management() ? 0 : 1;
DRW_draw_pass(psl->blend_pass);
stl->storage->tonemapping = 0;
diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.h b/source/blender/draw/engines/gpencil/gpencil_engine.h
index 416331e7aeb..d84bdfd8f2c 100644
--- a/source/blender/draw/engines/gpencil/gpencil_engine.h
+++ b/source/blender/draw/engines/gpencil/gpencil_engine.h
@@ -70,7 +70,7 @@ typedef struct tGPencilObjectCache_shgrp {
/** type of blend (regular, add, mult, etc...) */
int mode;
/** flag to enable the layer clamping */
- bool clamp_layer;
+ bool mask_layer;
/** factor to define the opacity of the layer */
float blend_opacity;
DRWShadingGroup *init_shgrp;
@@ -171,7 +171,7 @@ typedef struct GPENCIL_Storage {
short framebuffer_flag; /* flag what framebuffer need to create */
int blend_mode;
- int clamp_layer;
+ int mask_layer;
/* simplify settings*/
bool simplify_fill;
diff --git a/source/blender/draw/engines/gpencil/shaders/gpencil_blend_frag.glsl b/source/blender/draw/engines/gpencil/shaders/gpencil_blend_frag.glsl
index b70a55b51fa..85dee4390a5 100644
--- a/source/blender/draw/engines/gpencil/shaders/gpencil_blend_frag.glsl
+++ b/source/blender/draw/engines/gpencil/shaders/gpencil_blend_frag.glsl
@@ -7,7 +7,7 @@ uniform sampler2D strokeDepth;
uniform sampler2D blendColor;
uniform sampler2D blendDepth;
uniform int mode;
-uniform int clamp_layer;
+uniform int mask_layer;
uniform int tonemapping;
#define ON 1
@@ -142,7 +142,7 @@ void main()
gl_FragDepth = min(stroke_depth, mix_depth);
}
else {
- if (clamp_layer == ON) {
+ if (mask_layer == ON) {
discard;
}
else {
diff --git a/source/blender/draw/modes/edit_mesh_mode_text.c b/source/blender/draw/modes/edit_mesh_mode_text.c
index f3630a77e9a..7c7a9a586fa 100644
--- a/source/blender/draw/modes/edit_mesh_mode_text.c
+++ b/source/blender/draw/modes/edit_mesh_mode_text.c
@@ -66,7 +66,7 @@ void DRW_edit_mesh_mode_text_measure_stats(ARegion *ar,
/* when 2 edge-info options are enabled, space apart */
const bool do_edge_textpair = (v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_EDGE_LEN) &&
(v3d->overlay.edit_flag & V3D_OVERLAY_EDIT_EDGE_ANG);
- const short edge_texpair_sep = (short)(5.0f * U.ui_scale);
+ const short edge_texpair_sep = (short)(5.0f * U.dpi_fac);
float clip_planes[4][4];
/* allow for displaying shape keys and deform mods */
BMIter iter;
diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c
index 89d85388981..31f7a337d57 100644
--- a/source/blender/editors/animation/keyframing.c
+++ b/source/blender/editors/animation/keyframing.c
@@ -2034,7 +2034,7 @@ static int delete_key_exec(bContext *C, wmOperator *op)
int type = RNA_property_enum_get(op->ptr, op->type->prop);
ks = ANIM_keyingset_get_from_enum_type(scene, type);
if (ks == NULL) {
- BKE_report(op->reports, RPT_ERROR, "No active keying set");
+ BKE_report(op->reports, RPT_ERROR, "No active Keying Set");
return OPERATOR_CANCELLED;
}
}
@@ -2044,7 +2044,7 @@ static int delete_key_exec(bContext *C, wmOperator *op)
ks = ANIM_keyingset_get_from_idname(scene, type_id);
if (ks == NULL) {
- BKE_reportf(op->reports, RPT_ERROR, "No active keying set '%s' not found", type_id);
+ BKE_reportf(op->reports, RPT_ERROR, "Active Keying Set '%s' not found", type_id);
return OPERATOR_CANCELLED;
}
}
@@ -3000,7 +3000,7 @@ static KeyingSet *keyingset_get_from_op_with_error(wmOperator *op, PropertyRNA *
int type = RNA_property_enum_get(op->ptr, prop);
ks = ANIM_keyingset_get_from_enum_type(scene, type);
if (ks == NULL) {
- BKE_report(op->reports, RPT_ERROR, "No active keying set");
+ BKE_report(op->reports, RPT_ERROR, "No active Keying Set");
}
}
else if (prop_type == PROP_STRING) {
diff --git a/source/blender/editors/animation/keyingsets.c b/source/blender/editors/animation/keyingsets.c
index ab5e3186c47..0cb83c79c85 100644
--- a/source/blender/editors/animation/keyingsets.c
+++ b/source/blender/editors/animation/keyingsets.c
@@ -154,7 +154,7 @@ static int remove_active_keyingset_exec(bContext *C, wmOperator *op)
* - return error if it doesn't exist
*/
if (scene->active_keyingset == 0) {
- BKE_report(op->reports, RPT_ERROR, "No active keying set to remove");
+ BKE_report(op->reports, RPT_ERROR, "No active Keying Set to remove");
return OPERATOR_CANCELLED;
}
else if (scene->active_keyingset < 0) {
@@ -203,7 +203,7 @@ static int add_empty_ks_path_exec(bContext *C, wmOperator *op)
* - return error if it doesn't exist
*/
if (scene->active_keyingset == 0) {
- BKE_report(op->reports, RPT_ERROR, "No active keying set to add empty path to");
+ BKE_report(op->reports, RPT_ERROR, "No active Keying Set to add empty path to");
return OPERATOR_CANCELLED;
}
else {
@@ -253,12 +253,12 @@ static int remove_active_ks_path_exec(bContext *C, wmOperator *op)
ks->active_path--;
}
else {
- BKE_report(op->reports, RPT_ERROR, "No active keying set path to remove");
+ BKE_report(op->reports, RPT_ERROR, "No active Keying Set path to remove");
return OPERATOR_CANCELLED;
}
}
else {
- BKE_report(op->reports, RPT_ERROR, "No active keying set to remove a path from");
+ BKE_report(op->reports, RPT_ERROR, "No active Keying Set to remove a path from");
return OPERATOR_CANCELLED;
}
@@ -409,7 +409,7 @@ static int remove_keyingset_button_exec(bContext *C, wmOperator *op)
* - return error if it doesn't exist
*/
if (scene->active_keyingset == 0) {
- BKE_report(op->reports, RPT_ERROR, "No active keying set to remove property from");
+ BKE_report(op->reports, RPT_ERROR, "No active Keying Set to remove property from");
return OPERATOR_CANCELLED;
}
else if (scene->active_keyingset < 0) {
diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c
index 9588d4bb570..44f4728adcd 100644
--- a/source/blender/editors/gpencil/gpencil_edit.c
+++ b/source/blender/editors/gpencil/gpencil_edit.c
@@ -2804,6 +2804,9 @@ static int gp_stroke_cyclical_set_exec(bContext *C, wmOperator *op)
Object *ob = CTX_data_active_object(C);
const int type = RNA_enum_get(op->ptr, "type");
+ const bool geometry = RNA_boolean_get(op->ptr, "geometry");
+ const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
+ bGPDstroke *gps = NULL;
/* sanity checks */
if (ELEM(NULL, gpd)) {
@@ -2812,39 +2815,55 @@ static int gp_stroke_cyclical_set_exec(bContext *C, wmOperator *op)
/* loop all selected strokes */
CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
- if (gpl->actframe == NULL) {
- continue;
- }
+ bGPDframe *init_gpf = (is_multiedit) ? gpl->frames.first : gpl->actframe;
- for (bGPDstroke *gps = gpl->actframe->strokes.last; gps; gps = gps->prev) {
- MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, gps->mat_nr + 1);
+ for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
+ if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
+ if (gpf == NULL) {
+ continue;
+ }
- /* skip strokes that are not selected or invalid for current view */
- if (((gps->flag & GP_STROKE_SELECT) == 0) || ED_gpencil_stroke_can_use(C, gps) == false) {
- continue;
- }
- /* skip hidden or locked colors */
- if (!gp_style || (gp_style->flag & GP_STYLE_COLOR_HIDE) ||
- (gp_style->flag & GP_STYLE_COLOR_LOCKED)) {
- continue;
- }
+ for (gps = gpf->strokes.first; gps; gps = gps->next) {
+ MaterialGPencilStyle *gp_style = BKE_material_gpencil_settings_get(ob, gps->mat_nr + 1);
+ /* skip strokes that are not selected or invalid for current view */
+ if (((gps->flag & GP_STROKE_SELECT) == 0) ||
+ ED_gpencil_stroke_can_use(C, gps) == false) {
+ continue;
+ }
+ /* skip hidden or locked colors */
+ if (!gp_style || (gp_style->flag & GP_STYLE_COLOR_HIDE) ||
+ (gp_style->flag & GP_STYLE_COLOR_LOCKED)) {
+ continue;
+ }
- switch (type) {
- case GP_STROKE_CYCLIC_CLOSE:
- /* Close all (enable) */
- gps->flag |= GP_STROKE_CYCLIC;
- break;
- case GP_STROKE_CYCLIC_OPEN:
- /* Open all (disable) */
- gps->flag &= ~GP_STROKE_CYCLIC;
- break;
- case GP_STROKE_CYCLIC_TOGGLE:
- /* Just toggle flag... */
- gps->flag ^= GP_STROKE_CYCLIC;
- break;
- default:
- BLI_assert(0);
+ switch (type) {
+ case GP_STROKE_CYCLIC_CLOSE:
+ /* Close all (enable) */
+ gps->flag |= GP_STROKE_CYCLIC;
+ break;
+ case GP_STROKE_CYCLIC_OPEN:
+ /* Open all (disable) */
+ gps->flag &= ~GP_STROKE_CYCLIC;
+ break;
+ case GP_STROKE_CYCLIC_TOGGLE:
+ /* Just toggle flag... */
+ gps->flag ^= GP_STROKE_CYCLIC;
+ break;
+ default:
+ BLI_assert(0);
+ break;
+ }
+
+ /* Create new geometry. */
+ if ((gps->flag & GP_STROKE_CYCLIC) && (geometry)) {
+ BKE_gpencil_close_stroke(gps);
+ }
+ }
+
+ /* if not multiedit, exit loop*/
+ if (!is_multiedit) {
break;
+ }
}
}
}
@@ -2863,6 +2882,8 @@ static int gp_stroke_cyclical_set_exec(bContext *C, wmOperator *op)
*/
void GPENCIL_OT_stroke_cyclical_set(wmOperatorType *ot)
{
+ PropertyRNA *prop;
+
static const EnumPropertyItem cyclic_type[] = {
{GP_STROKE_CYCLIC_CLOSE, "CLOSE", 0, "Close all", ""},
{GP_STROKE_CYCLIC_OPEN, "OPEN", 0, "Open all", ""},
@@ -2884,6 +2905,9 @@ void GPENCIL_OT_stroke_cyclical_set(wmOperatorType *ot)
/* properties */
ot->prop = RNA_def_enum(ot->srna, "type", cyclic_type, GP_STROKE_CYCLIC_TOGGLE, "Type", "");
+ prop = RNA_def_boolean(
+ ot->srna, "geometry", false, "Create Geometry", "Create new geometry for closing stroke");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
/* ******************* Flat Stroke Caps ************************** */
@@ -4515,3 +4539,23 @@ void GPENCIL_OT_stroke_cutter(wmOperatorType *ot)
/* properties */
WM_operator_properties_gesture_lasso(ot);
}
+
+bool ED_object_gpencil_exit(struct Main *bmain, Object *ob)
+{
+ bool ok = false;
+ if (ob) {
+ bGPdata *gpd = (bGPdata *)ob->data;
+
+ gpd->flag &= ~(GP_DATA_STROKE_PAINTMODE | GP_DATA_STROKE_EDITMODE | GP_DATA_STROKE_SCULPTMODE |
+ GP_DATA_STROKE_WEIGHTMODE);
+
+ ob->restore_mode = ob->mode;
+ ob->mode &= ~(OB_MODE_PAINT_GPENCIL | OB_MODE_EDIT_GPENCIL | OB_MODE_SCULPT_GPENCIL |
+ OB_MODE_WEIGHT_GPENCIL);
+
+ /* Inform all CoW versions that we changed the mode. */
+ DEG_id_tag_update_ex(bmain, &ob->id, ID_RECALC_COPY_ON_WRITE);
+ ok = true;
+ }
+ return ok;
+}
diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h
index 73e239f0d33..0e3204b30c7 100644
--- a/source/blender/editors/include/ED_gpencil.h
+++ b/source/blender/editors/include/ED_gpencil.h
@@ -226,6 +226,7 @@ struct Object *ED_gpencil_add_object(struct bContext *C,
void ED_gpencil_add_defaults(struct bContext *C, struct Object *ob);
/* set object modes */
void ED_gpencil_setup_modes(struct bContext *C, struct bGPdata *gpd, int newmode);
+bool ED_object_gpencil_exit(struct Main *bmain, struct Object *ob);
void ED_gp_project_stroke_to_plane(const struct Scene *scene,
const struct Object *ob,
diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c
index a6c8697ec2c..ec0b01d4341 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -2502,6 +2502,31 @@ static void ui_widget_color_disabled(uiWidgetType *wt)
wt->wcol_theme = &wcol_theme_s;
}
+static void rgb_tint(char cp[3], int tint)
+{
+ cp[0] = clamp_i(cp[0] + tint, 0, 255);
+ cp[1] = clamp_i(cp[1] + tint, 0, 255);
+ cp[2] = clamp_i(cp[2] + tint, 0, 255);
+}
+
+static void rgb_ensure_contrast(char cp[3], const char cp_other[3], int contrast)
+{
+ BLI_assert(contrast > 0);
+ const int item_value = rgb_to_grayscale_byte((const uchar *)cp);
+ const int inner_value = rgb_to_grayscale_byte((const uchar *)cp_other);
+ const int delta = item_value - inner_value;
+ if (delta >= 0) {
+ if (contrast > delta) {
+ rgb_tint(cp, contrast - delta);
+ }
+ }
+ else {
+ if (contrast > -delta) {
+ rgb_tint(cp, -contrast - delta);
+ }
+ }
+}
+
static void widget_active_color(char cp[3])
{
cp[0] = cp[0] >= 240 ? 255 : cp[0] + 15;
@@ -2509,6 +2534,28 @@ static void widget_active_color(char cp[3])
cp[2] = cp[2] >= 240 ? 255 : cp[2] + 15;
}
+static const char *widget_color_blend_from_flags(const uiWidgetStateColors *wcol_state,
+ int state,
+ int drawflag)
+{
+ if (drawflag & UI_BUT_ANIMATED_CHANGED) {
+ return wcol_state->inner_changed_sel;
+ }
+ if (state & UI_BUT_ANIMATED_KEY) {
+ return wcol_state->inner_key_sel;
+ }
+ if (state & UI_BUT_ANIMATED) {
+ return wcol_state->inner_anim_sel;
+ }
+ if (state & UI_BUT_DRIVEN) {
+ return wcol_state->inner_driven_sel;
+ }
+ if (state & UI_BUT_OVERRIDEN) {
+ return wcol_state->inner_overridden_sel;
+ }
+ return NULL;
+}
+
/* copy colors from theme, and set changes in it based on state */
static void widget_state(uiWidgetType *wt, int state, int drawflag)
{
@@ -2526,22 +2573,7 @@ static void widget_state(uiWidgetType *wt, int state, int drawflag)
wt->wcol = *(wt->wcol_theme);
- const char *color_blend = NULL;
- if (drawflag & UI_BUT_ANIMATED_CHANGED) {
- color_blend = wcol_state->inner_changed_sel;
- }
- else if (state & UI_BUT_ANIMATED_KEY) {
- color_blend = wcol_state->inner_key_sel;
- }
- else if (state & UI_BUT_ANIMATED) {
- color_blend = wcol_state->inner_anim_sel;
- }
- else if (state & UI_BUT_DRIVEN) {
- color_blend = wcol_state->inner_driven_sel;
- }
- else if (state & UI_BUT_OVERRIDEN) {
- color_blend = wcol_state->inner_overridden_sel;
- }
+ const char *color_blend = widget_color_blend_from_flags(wcol_state, state, drawflag);
if (state & UI_SELECT) {
copy_v4_v4_char(wt->wcol.inner, wt->wcol.inner_sel);
@@ -2592,52 +2624,23 @@ static void widget_state(uiWidgetType *wt, int state, int drawflag)
static void widget_state_numslider(uiWidgetType *wt, int state, int drawflag)
{
uiWidgetStateColors *wcol_state = wt->wcol_state;
- /* XXX special tweak to make sure that bar will still be visible */
- float blend = wcol_state->blend - 0.2f;
/* call this for option button */
widget_state(wt, state, drawflag);
- /* now, set the inner-part so that it reflects state settings too */
- /* TODO: maybe we should have separate settings for the blending colors used for this case? */
- if (state & UI_SELECT) {
-
- if (drawflag & UI_BUT_ANIMATED_CHANGED) {
- widget_state_blend(wt->wcol.item, wcol_state->inner_changed_sel, blend);
- }
- else if (state & UI_BUT_ANIMATED_KEY) {
- widget_state_blend(wt->wcol.item, wcol_state->inner_key_sel, blend);
- }
- else if (state & UI_BUT_ANIMATED) {
- widget_state_blend(wt->wcol.item, wcol_state->inner_anim_sel, blend);
- }
- else if (state & UI_BUT_DRIVEN) {
- widget_state_blend(wt->wcol.item, wcol_state->inner_driven_sel, blend);
- }
- else if (state & UI_BUT_OVERRIDEN) {
- widget_state_blend(wt->wcol.item, wcol_state->inner_overridden_sel, blend);
- }
-
- if (state & UI_SELECT) {
- SWAP(short, wt->wcol.shadetop, wt->wcol.shadedown);
- }
+ const char *color_blend = widget_color_blend_from_flags(wcol_state, state, drawflag);
+ if (color_blend != NULL) {
+ /* Set the slider 'item' so that it reflects state settings too.
+ * De-saturate so the color of the slider doesn't conflict with the blend color,
+ * which can make the color hard to see when the slider is set to full (see T66102). */
+ wt->wcol.item[0] = wt->wcol.item[1] = wt->wcol.item[2] = rgb_to_grayscale_byte(
+ (const uchar *)wt->wcol.item);
+ widget_state_blend(wt->wcol.item, color_blend, wcol_state->blend);
+ rgb_ensure_contrast(wt->wcol.item, wt->wcol.inner, 20);
}
- else {
- if (drawflag & UI_BUT_ANIMATED_CHANGED) {
- widget_state_blend(wt->wcol.item, wcol_state->inner_changed, blend);
- }
- else if (state & UI_BUT_ANIMATED_KEY) {
- widget_state_blend(wt->wcol.item, wcol_state->inner_key, blend);
- }
- else if (state & UI_BUT_ANIMATED) {
- widget_state_blend(wt->wcol.item, wcol_state->inner_anim, blend);
- }
- else if (state & UI_BUT_DRIVEN) {
- widget_state_blend(wt->wcol.item, wcol_state->inner_driven, blend);
- }
- else if (state & UI_BUT_OVERRIDEN) {
- widget_state_blend(wt->wcol.item, wcol_state->inner_overridden, blend);
- }
+
+ if (state & UI_SELECT) {
+ SWAP(short, wt->wcol.shadetop, wt->wcol.shadedown);
}
}
diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c
index 78b4cfe38d4..b4ef2620895 100644
--- a/source/blender/editors/mesh/editmesh_bevel.c
+++ b/source/blender/editors/mesh/editmesh_bevel.c
@@ -263,14 +263,14 @@ static bool edbm_bevel_init(bContext *C, wmOperator *op, const bool is_modal)
initNumInput(&opdata->num_input[i]);
opdata->num_input[i].idx_max = 0;
opdata->num_input[i].val_flag[0] |= NUM_NO_NEGATIVE;
+ opdata->num_input[i].unit_type[0] = B_UNIT_NONE;
if (i == SEGMENTS_VALUE) {
opdata->num_input[i].val_flag[0] |= NUM_NO_FRACTION | NUM_NO_ZERO;
}
if (i == OFFSET_VALUE) {
opdata->num_input[i].unit_sys = scene->unit.system;
+ opdata->num_input[i].unit_type[0] = B_UNIT_LENGTH;
}
- /* Not sure this is a factor or a unit? */
- opdata->num_input[i].unit_type[0] = B_UNIT_NONE;
}
/* avoid the cost of allocating a bm copy */
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c
index 94d097612ae..f98a3248e76 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/editors/mesh/editmesh_tools.c
@@ -8016,6 +8016,7 @@ static int edbm_point_normals_invoke(bContext *C, wmOperator *op, const wmEvent
return OPERATOR_RUNNING_MODAL;
}
+/* TODO: make this work on multiple objects at once */
static int edbm_point_normals_exec(bContext *C, wmOperator *op)
{
Object *obedit = CTX_data_edit_object(C);
@@ -8238,44 +8239,54 @@ static void normals_split(BMesh *bm)
static int normals_split_merge(bContext *C, const bool do_merge)
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMesh *bm = em->bm;
- BMEdge *e;
- BMIter eiter;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
+ view_layer, CTX_wm_view3d(C), &objects_len);
- BKE_editmesh_ensure_autosmooth(em);
- BKE_editmesh_lnorspace_update(em);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
+ BMEdge *e;
+ BMIter eiter;
- /* Note that we need temp lnor editing data for all loops of all affected vertices, since by
- * setting some faces/edges as smooth we are going to change clnors spaces... See also T65809. */
- BMLoopNorEditDataArray *lnors_ed_arr = do_merge ? BM_loop_normal_editdata_array_init(bm, true) :
- NULL;
+ BKE_editmesh_ensure_autosmooth(em);
+ BKE_editmesh_lnorspace_update(em);
- mesh_set_smooth_faces(em, do_merge);
+ /* Note that we need temp lnor editing data for all loops of all affected vertices, since by
+ * setting some faces/edges as smooth we are going to change clnors spaces... See also T65809.
+ */
+ BMLoopNorEditDataArray *lnors_ed_arr = do_merge ?
+ BM_loop_normal_editdata_array_init(bm, true) :
+ NULL;
- BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
- if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
- BM_elem_flag_set(e, BM_ELEM_SMOOTH, do_merge);
+ mesh_set_smooth_faces(em, do_merge);
+
+ BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
+ BM_elem_flag_set(e, BM_ELEM_SMOOTH, do_merge);
+ }
}
- }
- bm->spacearr_dirty |= BM_SPACEARR_DIRTY_ALL;
- BKE_editmesh_lnorspace_update(em);
+ bm->spacearr_dirty |= BM_SPACEARR_DIRTY_ALL;
+ BKE_editmesh_lnorspace_update(em);
- if (do_merge) {
- normals_merge(bm, lnors_ed_arr);
- }
- else {
- normals_split(bm);
- }
+ if (do_merge) {
+ normals_merge(bm, lnors_ed_arr);
+ }
+ else {
+ normals_split(bm);
+ }
- if (lnors_ed_arr) {
- BM_loop_normal_editdata_array_free(lnors_ed_arr);
- }
+ if (lnors_ed_arr) {
+ BM_loop_normal_editdata_array_free(lnors_ed_arr);
+ }
- EDBM_update_generic(em, true, false);
+ EDBM_update_generic(em, true, false);
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -8344,131 +8355,140 @@ static EnumPropertyItem average_method_items[] = {
static int edbm_average_normals_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMesh *bm = em->bm;
- BMFace *f;
- BMLoop *l, *l_curr, *l_first;
- BMIter fiter;
-
- BKE_editmesh_ensure_autosmooth(em);
- bm->spacearr_dirty |= BM_SPACEARR_DIRTY_ALL;
- BKE_editmesh_lnorspace_update(em);
-
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
+ view_layer, CTX_wm_view3d(C), &objects_len);
const int average_type = RNA_enum_get(op->ptr, "average_type");
- const int cd_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL);
const float absweight = (float)RNA_int_get(op->ptr, "weight");
const float threshold = RNA_float_get(op->ptr, "threshold");
- float weight = absweight / 50.0f;
- if (absweight == 100.0f) {
- weight = (float)SHRT_MAX;
- }
- else if (absweight == 1.0f) {
- weight = 1 / (float)SHRT_MAX;
- }
- else if ((weight - 1) * 25 > 1) {
- weight = (weight - 1) * 25;
- }
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
+ BMFace *f;
+ BMLoop *l, *l_curr, *l_first;
+ BMIter fiter;
- BM_normals_loops_edges_tag(bm, true);
+ BKE_editmesh_ensure_autosmooth(em);
+ bm->spacearr_dirty |= BM_SPACEARR_DIRTY_ALL;
+ BKE_editmesh_lnorspace_update(em);
- HeapSimple *loop_weight = BLI_heapsimple_new();
+ const int cd_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL);
- BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
- l_curr = l_first = BM_FACE_FIRST_LOOP(f);
- do {
- if (BM_elem_flag_test(l_curr->v, BM_ELEM_SELECT) &&
- (!BM_elem_flag_test(l_curr->e, BM_ELEM_TAG) ||
- (!BM_elem_flag_test(l_curr, BM_ELEM_TAG) && BM_loop_check_cyclic_smooth_fan(l_curr)))) {
- if (!BM_elem_flag_test(l_curr->e, BM_ELEM_TAG) &&
- !BM_elem_flag_test(l_curr->prev->e, BM_ELEM_TAG)) {
- const int loop_index = BM_elem_index_get(l_curr);
- short *clnors = BM_ELEM_CD_GET_VOID_P(l_curr, cd_clnors_offset);
- BKE_lnor_space_custom_normal_to_data(
- bm->lnor_spacearr->lspacearr[loop_index], f->no, clnors);
- }
- else {
- BMVert *v_pivot = l_curr->v;
- UNUSED_VARS_NDEBUG(v_pivot);
- BMEdge *e_next;
- const BMEdge *e_org = l_curr->e;
- BMLoop *lfan_pivot, *lfan_pivot_next;
+ float weight = absweight / 50.0f;
+ if (absweight == 100.0f) {
+ weight = (float)SHRT_MAX;
+ }
+ else if (absweight == 1.0f) {
+ weight = 1 / (float)SHRT_MAX;
+ }
+ else if ((weight - 1) * 25 > 1) {
+ weight = (weight - 1) * 25;
+ }
- lfan_pivot = l_curr;
- e_next = lfan_pivot->e;
+ BM_normals_loops_edges_tag(bm, true);
- while (true) {
- lfan_pivot_next = BM_vert_step_fan_loop(lfan_pivot, &e_next);
- if (lfan_pivot_next) {
- BLI_assert(lfan_pivot_next->v == v_pivot);
- }
- else {
- e_next = (lfan_pivot->e == e_next) ? lfan_pivot->prev->e : lfan_pivot->e;
- }
+ HeapSimple *loop_weight = BLI_heapsimple_new();
- float val = 1.0f;
- if (average_type == EDBM_CLNOR_AVERAGE_FACE_AREA) {
- val = 1.0f / BM_face_calc_area(lfan_pivot->f);
- }
- else if (average_type == EDBM_CLNOR_AVERAGE_ANGLE) {
- val = 1.0f / BM_loop_calc_face_angle(lfan_pivot);
- }
+ BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
+ l_curr = l_first = BM_FACE_FIRST_LOOP(f);
+ do {
+ if (BM_elem_flag_test(l_curr->v, BM_ELEM_SELECT) &&
+ (!BM_elem_flag_test(l_curr->e, BM_ELEM_TAG) ||
+ (!BM_elem_flag_test(l_curr, BM_ELEM_TAG) &&
+ BM_loop_check_cyclic_smooth_fan(l_curr)))) {
+ if (!BM_elem_flag_test(l_curr->e, BM_ELEM_TAG) &&
+ !BM_elem_flag_test(l_curr->prev->e, BM_ELEM_TAG)) {
+ const int loop_index = BM_elem_index_get(l_curr);
+ short *clnors = BM_ELEM_CD_GET_VOID_P(l_curr, cd_clnors_offset);
+ BKE_lnor_space_custom_normal_to_data(
+ bm->lnor_spacearr->lspacearr[loop_index], f->no, clnors);
+ }
+ else {
+ BMVert *v_pivot = l_curr->v;
+ UNUSED_VARS_NDEBUG(v_pivot);
+ BMEdge *e_next;
+ const BMEdge *e_org = l_curr->e;
+ BMLoop *lfan_pivot, *lfan_pivot_next;
+
+ lfan_pivot = l_curr;
+ e_next = lfan_pivot->e;
+
+ while (true) {
+ lfan_pivot_next = BM_vert_step_fan_loop(lfan_pivot, &e_next);
+ if (lfan_pivot_next) {
+ BLI_assert(lfan_pivot_next->v == v_pivot);
+ }
+ else {
+ e_next = (lfan_pivot->e == e_next) ? lfan_pivot->prev->e : lfan_pivot->e;
+ }
- BLI_heapsimple_insert(loop_weight, val, lfan_pivot);
+ float val = 1.0f;
+ if (average_type == EDBM_CLNOR_AVERAGE_FACE_AREA) {
+ val = 1.0f / BM_face_calc_area(lfan_pivot->f);
+ }
+ else if (average_type == EDBM_CLNOR_AVERAGE_ANGLE) {
+ val = 1.0f / BM_loop_calc_face_angle(lfan_pivot);
+ }
- if (!BM_elem_flag_test(e_next, BM_ELEM_TAG) || (e_next == e_org)) {
- break;
- }
- lfan_pivot = lfan_pivot_next;
- }
+ BLI_heapsimple_insert(loop_weight, val, lfan_pivot);
- BLI_SMALLSTACK_DECLARE(loops, BMLoop *);
- float wnor[3], avg_normal[3] = {0.0f}, count = 0;
- float val = BLI_heapsimple_top_value(loop_weight);
-
- while (!BLI_heapsimple_is_empty(loop_weight)) {
- const float cur_val = BLI_heapsimple_top_value(loop_weight);
- if (!compare_ff(val, cur_val, threshold)) {
- count++;
- val = cur_val;
+ if (!BM_elem_flag_test(e_next, BM_ELEM_TAG) || (e_next == e_org)) {
+ break;
+ }
+ lfan_pivot = lfan_pivot_next;
}
- l = BLI_heapsimple_pop_min(loop_weight);
- BLI_SMALLSTACK_PUSH(loops, l);
- const float n_weight = pow(weight, count);
+ BLI_SMALLSTACK_DECLARE(loops, BMLoop *);
+ float wnor[3], avg_normal[3] = {0.0f}, count = 0;
+ float val = BLI_heapsimple_top_value(loop_weight);
+
+ while (!BLI_heapsimple_is_empty(loop_weight)) {
+ const float cur_val = BLI_heapsimple_top_value(loop_weight);
+ if (!compare_ff(val, cur_val, threshold)) {
+ count++;
+ val = cur_val;
+ }
+ l = BLI_heapsimple_pop_min(loop_weight);
+ BLI_SMALLSTACK_PUSH(loops, l);
+
+ const float n_weight = pow(weight, count);
+
+ if (average_type == EDBM_CLNOR_AVERAGE_LOOP) {
+ const int l_index = BM_elem_index_get(l);
+ short *clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset);
+ BKE_lnor_space_custom_data_to_normal(
+ bm->lnor_spacearr->lspacearr[l_index], clnors, wnor);
+ }
+ else {
+ copy_v3_v3(wnor, l->f->no);
+ }
+ mul_v3_fl(wnor, (1.0f / cur_val) * (1.0f / n_weight));
+ add_v3_v3(avg_normal, wnor);
+ }
- if (average_type == EDBM_CLNOR_AVERAGE_LOOP) {
+ if (normalize_v3(avg_normal) < CLNORS_VALID_VEC_LEN) {
+ /* If avg normal is nearly 0, set clnor to default value. */
+ zero_v3(avg_normal);
+ }
+ while ((l = BLI_SMALLSTACK_POP(loops))) {
const int l_index = BM_elem_index_get(l);
short *clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset);
- BKE_lnor_space_custom_data_to_normal(
- bm->lnor_spacearr->lspacearr[l_index], clnors, wnor);
- }
- else {
- copy_v3_v3(wnor, l->f->no);
+ BKE_lnor_space_custom_normal_to_data(
+ bm->lnor_spacearr->lspacearr[l_index], avg_normal, clnors);
}
- mul_v3_fl(wnor, (1.0f / cur_val) * (1.0f / n_weight));
- add_v3_v3(avg_normal, wnor);
- }
-
- if (normalize_v3(avg_normal) < CLNORS_VALID_VEC_LEN) {
- /* If avg normal is nearly 0, set clnor to default value. */
- zero_v3(avg_normal);
- }
- while ((l = BLI_SMALLSTACK_POP(loops))) {
- const int l_index = BM_elem_index_get(l);
- short *clnors = BM_ELEM_CD_GET_VOID_P(l, cd_clnors_offset);
- BKE_lnor_space_custom_normal_to_data(
- bm->lnor_spacearr->lspacearr[l_index], avg_normal, clnors);
}
}
- }
- } while ((l_curr = l_curr->next) != l_first);
- }
+ } while ((l_curr = l_curr->next) != l_first);
+ }
- BLI_heapsimple_free(loop_weight, NULL);
- EDBM_update_generic(em, true, false);
+ BLI_heapsimple_free(loop_weight, NULL);
+ EDBM_update_generic(em, true, false);
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -8567,135 +8587,151 @@ static EnumPropertyItem normal_vector_tool_items[] = {
static int edbm_normals_tools_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
Scene *scene = CTX_data_scene(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMesh *bm = em->bm;
-
- if (bm->totloop == 0) {
- return OPERATOR_CANCELLED;
- }
-
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
+ view_layer, CTX_wm_view3d(C), &objects_len);
const int mode = RNA_enum_get(op->ptr, "mode");
const bool absolute = RNA_boolean_get(op->ptr, "absolute");
+ float *normal_vector = scene->toolsettings->normal_vector;
+ bool done_copy = false;
- BKE_editmesh_ensure_autosmooth(em);
- BKE_editmesh_lnorspace_update(em);
- BMLoopNorEditDataArray *lnors_ed_arr = BM_loop_normal_editdata_array_init(bm, false);
- BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata;
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
- float *normal_vector = scene->toolsettings->normal_vector;
+ if (bm->totloop == 0) {
+ continue;
+ }
- switch (mode) {
- case EDBM_CLNOR_TOOLS_COPY:
- if (bm->totfacesel != 1 && lnors_ed_arr->totloop != 1 && bm->totvertsel != 1) {
- BKE_report(op->reports,
- RPT_ERROR,
- "Can only copy one custom normal, vertex normal or face normal");
- BM_loop_normal_editdata_array_free(lnors_ed_arr);
- return OPERATOR_CANCELLED;
- }
- if (lnors_ed_arr->totloop == 1) {
- copy_v3_v3(scene->toolsettings->normal_vector, lnors_ed_arr->lnor_editdata->nloc);
- }
- else if (bm->totfacesel == 1) {
- BMFace *f;
- BMIter fiter;
- BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
- if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
- copy_v3_v3(scene->toolsettings->normal_vector, f->no);
- }
+ BKE_editmesh_ensure_autosmooth(em);
+ BKE_editmesh_lnorspace_update(em);
+ BMLoopNorEditDataArray *lnors_ed_arr = BM_loop_normal_editdata_array_init(bm, false);
+ BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata;
+
+ switch (mode) {
+ case EDBM_CLNOR_TOOLS_COPY:
+ if (bm->totfacesel == 0 || bm->totvertsel == 0) {
+ BM_loop_normal_editdata_array_free(lnors_ed_arr);
+ continue;
}
- }
- else {
- /* 'Vertex' normal, i.e. common set of loop normals on the same vertex,
- * only if they are all the same. */
- bool are_same_lnors = true;
- for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) {
- if (!compare_v3v3(lnors_ed_arr->lnor_editdata->nloc, lnor_ed->nloc, 1e-4f)) {
- are_same_lnors = false;
- }
+
+ if (done_copy ||
+ (bm->totfacesel != 1 && lnors_ed_arr->totloop != 1 && bm->totvertsel != 1)) {
+ BKE_report(op->reports,
+ RPT_ERROR,
+ "Can only copy one custom normal, vertex normal or face normal");
+ BM_loop_normal_editdata_array_free(lnors_ed_arr);
+ continue;
}
- if (are_same_lnors) {
+ if (lnors_ed_arr->totloop == 1) {
copy_v3_v3(scene->toolsettings->normal_vector, lnors_ed_arr->lnor_editdata->nloc);
}
- }
- break;
+ else if (bm->totfacesel == 1) {
+ BMFace *f;
+ BMIter fiter;
+ BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
+ if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
+ copy_v3_v3(scene->toolsettings->normal_vector, f->no);
+ }
+ }
+ }
+ else {
+ /* 'Vertex' normal, i.e. common set of loop normals on the same vertex,
+ * only if they are all the same. */
+ bool are_same_lnors = true;
+ for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) {
+ if (!compare_v3v3(lnors_ed_arr->lnor_editdata->nloc, lnor_ed->nloc, 1e-4f)) {
+ are_same_lnors = false;
+ }
+ }
+ if (are_same_lnors) {
+ copy_v3_v3(scene->toolsettings->normal_vector, lnors_ed_arr->lnor_editdata->nloc);
+ }
+ }
+ done_copy = true;
+ break;
- case EDBM_CLNOR_TOOLS_PASTE:
- if (!absolute) {
- if (normalize_v3(normal_vector) < CLNORS_VALID_VEC_LEN) {
- /* If normal is nearly 0, do nothing. */
- break;
+ case EDBM_CLNOR_TOOLS_PASTE:
+ if (!absolute) {
+ if (normalize_v3(normal_vector) < CLNORS_VALID_VEC_LEN) {
+ /* If normal is nearly 0, do nothing. */
+ break;
+ }
}
- }
- for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) {
- if (absolute) {
- float abs_normal[3];
- copy_v3_v3(abs_normal, lnor_ed->loc);
- negate_v3(abs_normal);
- add_v3_v3(abs_normal, normal_vector);
+ for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) {
+ if (absolute) {
+ float abs_normal[3];
+ copy_v3_v3(abs_normal, lnor_ed->loc);
+ negate_v3(abs_normal);
+ add_v3_v3(abs_normal, normal_vector);
+
+ if (normalize_v3(abs_normal) < CLNORS_VALID_VEC_LEN) {
+ /* If abs normal is nearly 0, set clnor to initial value. */
+ copy_v3_v3(abs_normal, lnor_ed->niloc);
+ }
+ BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[lnor_ed->loop_index],
+ abs_normal,
+ lnor_ed->clnors_data);
+ }
+ else {
+ BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[lnor_ed->loop_index],
+ normal_vector,
+ lnor_ed->clnors_data);
+ }
+ }
+ break;
- if (normalize_v3(abs_normal) < CLNORS_VALID_VEC_LEN) {
+ case EDBM_CLNOR_TOOLS_MULTIPLY:
+ for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) {
+ mul_v3_v3(lnor_ed->nloc, normal_vector);
+
+ if (normalize_v3(lnor_ed->nloc) < CLNORS_VALID_VEC_LEN) {
/* If abs normal is nearly 0, set clnor to initial value. */
- copy_v3_v3(abs_normal, lnor_ed->niloc);
+ copy_v3_v3(lnor_ed->nloc, lnor_ed->niloc);
}
- BKE_lnor_space_custom_normal_to_data(
- bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], abs_normal, lnor_ed->clnors_data);
- }
- else {
BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[lnor_ed->loop_index],
- normal_vector,
+ lnor_ed->nloc,
lnor_ed->clnors_data);
}
- }
- break;
+ break;
- case EDBM_CLNOR_TOOLS_MULTIPLY:
- for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) {
- mul_v3_v3(lnor_ed->nloc, normal_vector);
+ case EDBM_CLNOR_TOOLS_ADD:
+ for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) {
+ add_v3_v3(lnor_ed->nloc, normal_vector);
- if (normalize_v3(lnor_ed->nloc) < CLNORS_VALID_VEC_LEN) {
- /* If abs normal is nearly 0, set clnor to initial value. */
- copy_v3_v3(lnor_ed->nloc, lnor_ed->niloc);
+ if (normalize_v3(lnor_ed->nloc) < CLNORS_VALID_VEC_LEN) {
+ /* If abs normal is nearly 0, set clnor to initial value. */
+ copy_v3_v3(lnor_ed->nloc, lnor_ed->niloc);
+ }
+ BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[lnor_ed->loop_index],
+ lnor_ed->nloc,
+ lnor_ed->clnors_data);
}
- BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[lnor_ed->loop_index],
- lnor_ed->nloc,
- lnor_ed->clnors_data);
- }
- break;
-
- case EDBM_CLNOR_TOOLS_ADD:
- for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) {
- add_v3_v3(lnor_ed->nloc, normal_vector);
+ break;
- if (normalize_v3(lnor_ed->nloc) < CLNORS_VALID_VEC_LEN) {
- /* If abs normal is nearly 0, set clnor to initial value. */
- copy_v3_v3(lnor_ed->nloc, lnor_ed->niloc);
+ case EDBM_CLNOR_TOOLS_RESET:
+ zero_v3(normal_vector);
+ for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) {
+ BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[lnor_ed->loop_index],
+ normal_vector,
+ lnor_ed->clnors_data);
}
- BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[lnor_ed->loop_index],
- lnor_ed->nloc,
- lnor_ed->clnors_data);
- }
- break;
+ break;
- case EDBM_CLNOR_TOOLS_RESET:
- zero_v3(normal_vector);
- for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) {
- BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[lnor_ed->loop_index],
- normal_vector,
- lnor_ed->clnors_data);
- }
- break;
+ default:
+ BLI_assert(0);
+ break;
+ }
- default:
- BLI_assert(0);
- break;
- }
+ BM_loop_normal_editdata_array_free(lnors_ed_arr);
- BM_loop_normal_editdata_array_free(lnors_ed_arr);
+ EDBM_update_generic(em, true, false);
+ }
- EDBM_update_generic(em, true, false);
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -8842,8 +8878,8 @@ static int edbm_set_normals_from_faces_exec(bContext *C, wmOperator *op)
MEM_freeN(vnors);
EDBM_update_generic(em, true, false);
}
- MEM_freeN(objects);
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -8866,77 +8902,86 @@ void MESH_OT_set_normals_from_faces(struct wmOperatorType *ot)
static int edbm_smoothen_normals_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMesh *bm = em->bm;
- BMFace *f;
- BMLoop *l;
- BMIter fiter, liter;
-
- BKE_editmesh_ensure_autosmooth(em);
- BKE_editmesh_lnorspace_update(em);
- BMLoopNorEditDataArray *lnors_ed_arr = BM_loop_normal_editdata_array_init(bm, false);
-
- float(*smooth_normal)[3] = MEM_callocN(sizeof(*smooth_normal) * lnors_ed_arr->totloop, __func__);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
+ view_layer, CTX_wm_view3d(C), &objects_len);
- /* This is weird choice of operation, taking all loops of faces of current vertex.
- * Could lead to some rather far away loops weighting as much as very close ones
- * (topologically speaking), with complex polygons.
- * Using topological distance here (rather than geometrical one)
- * makes sense imho, but would rather go with a more consistent and flexible code,
- * we could even add max topological distance to take into account, * and a weighting curve.
- * Would do that later though, think for now we can live with that choice. --mont29. */
- BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata;
- for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) {
- l = lnor_ed->loop;
- float loop_normal[3];
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
+ BMFace *f;
+ BMLoop *l;
+ BMIter fiter, liter;
- BM_ITER_ELEM (f, &fiter, l->v, BM_FACES_OF_VERT) {
- BMLoop *l_other;
- BM_ITER_ELEM (l_other, &liter, f, BM_LOOPS_OF_FACE) {
- const int l_index_other = BM_elem_index_get(l_other);
- short *clnors = BM_ELEM_CD_GET_VOID_P(l_other, lnors_ed_arr->cd_custom_normal_offset);
- BKE_lnor_space_custom_data_to_normal(
- bm->lnor_spacearr->lspacearr[l_index_other], clnors, loop_normal);
- add_v3_v3(smooth_normal[i], loop_normal);
+ BKE_editmesh_ensure_autosmooth(em);
+ BKE_editmesh_lnorspace_update(em);
+ BMLoopNorEditDataArray *lnors_ed_arr = BM_loop_normal_editdata_array_init(bm, false);
+
+ float(*smooth_normal)[3] = MEM_callocN(sizeof(*smooth_normal) * lnors_ed_arr->totloop,
+ __func__);
+
+ /* This is weird choice of operation, taking all loops of faces of current vertex.
+ * Could lead to some rather far away loops weighting as much as very close ones
+ * (topologically speaking), with complex polygons.
+ * Using topological distance here (rather than geometrical one)
+ * makes sense imho, but would rather go with a more consistent and flexible code,
+ * we could even add max topological distance to take into account, * and a weighting curve.
+ * Would do that later though, think for now we can live with that choice. --mont29. */
+ BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata;
+ for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) {
+ l = lnor_ed->loop;
+ float loop_normal[3];
+
+ BM_ITER_ELEM (f, &fiter, l->v, BM_FACES_OF_VERT) {
+ BMLoop *l_other;
+ BM_ITER_ELEM (l_other, &liter, f, BM_LOOPS_OF_FACE) {
+ const int l_index_other = BM_elem_index_get(l_other);
+ short *clnors = BM_ELEM_CD_GET_VOID_P(l_other, lnors_ed_arr->cd_custom_normal_offset);
+ BKE_lnor_space_custom_data_to_normal(
+ bm->lnor_spacearr->lspacearr[l_index_other], clnors, loop_normal);
+ add_v3_v3(smooth_normal[i], loop_normal);
+ }
}
}
- }
- const float factor = RNA_float_get(op->ptr, "factor");
+ const float factor = RNA_float_get(op->ptr, "factor");
- lnor_ed = lnors_ed_arr->lnor_editdata;
- for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) {
- float current_normal[3];
+ lnor_ed = lnors_ed_arr->lnor_editdata;
+ for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) {
+ float current_normal[3];
- if (normalize_v3(smooth_normal[i]) < CLNORS_VALID_VEC_LEN) {
- /* Skip in case smoothen normal is invalid... */
- continue;
- }
+ if (normalize_v3(smooth_normal[i]) < CLNORS_VALID_VEC_LEN) {
+ /* Skip in case smoothen normal is invalid... */
+ continue;
+ }
- BKE_lnor_space_custom_data_to_normal(
- bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], lnor_ed->clnors_data, current_normal);
+ BKE_lnor_space_custom_data_to_normal(
+ bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], lnor_ed->clnors_data, current_normal);
- /* Note: again, this is not true spherical interpolation that normals would need...
- * But it's probably good enough for now. */
- mul_v3_fl(current_normal, 1.0f - factor);
- mul_v3_fl(smooth_normal[i], factor);
- add_v3_v3(current_normal, smooth_normal[i]);
+ /* Note: again, this is not true spherical interpolation that normals would need...
+ * But it's probably good enough for now. */
+ mul_v3_fl(current_normal, 1.0f - factor);
+ mul_v3_fl(smooth_normal[i], factor);
+ add_v3_v3(current_normal, smooth_normal[i]);
- if (normalize_v3(current_normal) < CLNORS_VALID_VEC_LEN) {
- /* Skip in case smoothen normal is invalid... */
- continue;
- }
+ if (normalize_v3(current_normal) < CLNORS_VALID_VEC_LEN) {
+ /* Skip in case smoothen normal is invalid... */
+ continue;
+ }
- BKE_lnor_space_custom_normal_to_data(
- bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], current_normal, lnor_ed->clnors_data);
- }
+ BKE_lnor_space_custom_normal_to_data(
+ bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], current_normal, lnor_ed->clnors_data);
+ }
- BM_loop_normal_editdata_array_free(lnors_ed_arr);
- MEM_freeN(smooth_normal);
+ BM_loop_normal_editdata_array_free(lnors_ed_arr);
+ MEM_freeN(smooth_normal);
- EDBM_update_generic(em, true, false);
+ EDBM_update_generic(em, true, false);
+ }
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
@@ -8969,50 +9014,59 @@ void MESH_OT_smoothen_normals(struct wmOperatorType *ot)
static int edbm_mod_weighted_strength_exec(bContext *C, wmOperator *op)
{
- Object *obedit = CTX_data_edit_object(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMesh *bm = em->bm;
- BMFace *f;
- BMIter fiter;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
+ view_layer, CTX_wm_view3d(C), &objects_len);
- BM_select_history_clear(bm);
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
+ BMFace *f;
+ BMIter fiter;
+ const int face_strength = RNA_enum_get(op->ptr, "face_strength");
+ const bool set = RNA_boolean_get(op->ptr, "set");
- const char *layer_id = MOD_WEIGHTEDNORMALS_FACEWEIGHT_CDLAYER_ID;
- int cd_prop_int_index = CustomData_get_named_layer_index(&bm->pdata, CD_PROP_INT, layer_id);
- if (cd_prop_int_index == -1) {
- BM_data_layer_add_named(bm, &bm->pdata, CD_PROP_INT, layer_id);
- cd_prop_int_index = CustomData_get_named_layer_index(&bm->pdata, CD_PROP_INT, layer_id);
- }
- cd_prop_int_index -= CustomData_get_layer_index(&bm->pdata, CD_PROP_INT);
- const int cd_prop_int_offset = CustomData_get_n_offset(
- &bm->pdata, CD_PROP_INT, cd_prop_int_index);
+ BM_select_history_clear(bm);
- const int face_strength = RNA_enum_get(op->ptr, "face_strength");
- const bool set = RNA_boolean_get(op->ptr, "set");
- BM_mesh_elem_index_ensure(bm, BM_FACE);
+ const char *layer_id = MOD_WEIGHTEDNORMALS_FACEWEIGHT_CDLAYER_ID;
+ int cd_prop_int_index = CustomData_get_named_layer_index(&bm->pdata, CD_PROP_INT, layer_id);
+ if (cd_prop_int_index == -1) {
+ BM_data_layer_add_named(bm, &bm->pdata, CD_PROP_INT, layer_id);
+ cd_prop_int_index = CustomData_get_named_layer_index(&bm->pdata, CD_PROP_INT, layer_id);
+ }
+ cd_prop_int_index -= CustomData_get_layer_index(&bm->pdata, CD_PROP_INT);
+ const int cd_prop_int_offset = CustomData_get_n_offset(
+ &bm->pdata, CD_PROP_INT, cd_prop_int_index);
- if (set) {
- BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
- if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
- int *strength = BM_ELEM_CD_GET_VOID_P(f, cd_prop_int_offset);
- *strength = face_strength;
+ BM_mesh_elem_index_ensure(bm, BM_FACE);
+
+ if (set) {
+ BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
+ if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
+ int *strength = BM_ELEM_CD_GET_VOID_P(f, cd_prop_int_offset);
+ *strength = face_strength;
+ }
}
}
- }
- else {
- BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
- int *strength = BM_ELEM_CD_GET_VOID_P(f, cd_prop_int_offset);
- if (*strength == face_strength) {
- BM_face_select_set(bm, f, true);
- BM_select_history_store(bm, f);
- }
- else {
- BM_face_select_set(bm, f, false);
+ else {
+ BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
+ int *strength = BM_ELEM_CD_GET_VOID_P(f, cd_prop_int_offset);
+ if (*strength == face_strength) {
+ BM_face_select_set(bm, f, true);
+ BM_select_history_store(bm, f);
+ }
+ else {
+ BM_face_select_set(bm, f, false);
+ }
}
}
+
+ EDBM_update_generic(em, false, false);
}
- EDBM_update_generic(em, false, false);
+ MEM_freeN(objects);
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c
index 0fdb1cec16f..468efc0c9d9 100644
--- a/source/blender/editors/object/object_add.c
+++ b/source/blender/editors/object/object_add.c
@@ -2782,10 +2782,10 @@ void OBJECT_OT_join(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
-/** \name Join as Shape Key Operator
+/** \name Transfer Mix Operator for Shape Keys
* \{ */
-static bool join_shapes_poll(bContext *C)
+static bool shape_key_transfer_mix_poll(bContext *C)
{
Object *ob = CTX_data_active_object(C);
@@ -2802,12 +2802,12 @@ static bool join_shapes_poll(bContext *C)
}
}
-static int join_shapes_exec(bContext *C, wmOperator *op)
+static int shape_key_transfer_mix_exec(bContext *C, wmOperator *op)
{
Object *ob = CTX_data_active_object(C);
if (ob->mode & OB_MODE_EDIT) {
- BKE_report(op->reports, RPT_ERROR, "This data does not support joining in edit mode");
+ BKE_report(op->reports, RPT_ERROR, "Shape Keys cannot be transfered in edit mode");
return OPERATOR_CANCELLED;
}
else if (BKE_object_obdata_is_libdata(ob)) {
@@ -2822,16 +2822,16 @@ static int join_shapes_exec(bContext *C, wmOperator *op)
return OPERATOR_CANCELLED;
}
-void OBJECT_OT_join_shapes(wmOperatorType *ot)
+void OBJECT_OT_shape_key_transfer_mix(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "Join as Shapes";
- ot->description = "Merge selected objects to shapes of active object";
- ot->idname = "OBJECT_OT_join_shapes";
+ ot->name = "Transfer Mix";
+ ot->description = "Copy the current resulting shape of another selected object to this one";
+ ot->idname = "OBJECT_OT_shape_key_transfer_mix";
/* api callbacks */
- ot->exec = join_shapes_exec;
- ot->poll = join_shapes_poll;
+ ot->exec = shape_key_transfer_mix_exec;
+ ot->poll = shape_key_transfer_mix_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h
index b9350052093..f97a9c1b5b8 100644
--- a/source/blender/editors/object/object_intern.h
+++ b/source/blender/editors/object/object_intern.h
@@ -117,7 +117,7 @@ void OBJECT_OT_duplicates_make_real(struct wmOperatorType *ot);
void OBJECT_OT_duplicate(struct wmOperatorType *ot);
void OBJECT_OT_delete(struct wmOperatorType *ot);
void OBJECT_OT_join(struct wmOperatorType *ot);
-void OBJECT_OT_join_shapes(struct wmOperatorType *ot);
+void OBJECT_OT_shape_key_transfer_mix(struct wmOperatorType *ot);
void OBJECT_OT_convert(struct wmOperatorType *ot);
/* object_hook.c */
diff --git a/source/blender/editors/object/object_modes.c b/source/blender/editors/object/object_modes.c
index 0f0d09c610b..0ec98e089a2 100644
--- a/source/blender/editors/object/object_modes.c
+++ b/source/blender/editors/object/object_modes.c
@@ -43,6 +43,7 @@
#include "DEG_depsgraph.h"
#include "ED_armature.h"
+#include "ED_gpencil.h"
#include "ED_screen.h"
#include "ED_object.h" /* own include */
@@ -287,6 +288,12 @@ static bool ed_object_mode_generic_exit_ex(struct Main *bmain,
ED_object_posemode_exit_ex(bmain, ob);
}
}
+ else if ((ob->type == OB_GPENCIL) && ((ob->mode & OB_MODE_OBJECT) == 0)) {
+ if (only_test) {
+ return true;
+ }
+ ED_object_gpencil_exit(bmain, ob);
+ }
else {
if (only_test) {
return false;
diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c
index b653c7fa70c..217a2e5a54d 100644
--- a/source/blender/editors/object/object_ops.c
+++ b/source/blender/editors/object/object_ops.c
@@ -117,7 +117,7 @@ void ED_operatortypes_object(void)
WM_operatortype_append(OBJECT_OT_duplicates_make_real);
WM_operatortype_append(OBJECT_OT_duplicate);
WM_operatortype_append(OBJECT_OT_join);
- WM_operatortype_append(OBJECT_OT_join_shapes);
+ WM_operatortype_append(OBJECT_OT_shape_key_transfer_mix);
WM_operatortype_append(OBJECT_OT_convert);
WM_operatortype_append(OBJECT_OT_modifier_add);
diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c
index 76b88b8df22..c6b1acfbd94 100644
--- a/source/blender/editors/render/render_preview.c
+++ b/source/blender/editors/render/render_preview.c
@@ -38,6 +38,8 @@
#include "BLI_blenlib.h"
#include "BLI_utildefines.h"
+#include "PIL_time.h"
+
#include "BLO_readfile.h"
#include "DNA_world_types.h"
@@ -1209,6 +1211,10 @@ static void icon_preview_startjob_all_sizes(void *customdata,
for (cur_size = ip->sizes.first; cur_size; cur_size = cur_size->next) {
PreviewImage *prv = ip->owner;
+ if (*stop) {
+ break;
+ }
+
if (prv->tag & PRV_TAG_DEFFERED_DELETE) {
/* Non-thread-protected reading is not an issue here. */
continue;
@@ -1379,7 +1385,10 @@ void ED_preview_icon_job(
/* setup job */
WM_jobs_customdata_set(wm_job, ip, icon_preview_free);
- WM_jobs_timer(wm_job, 0.1, NC_WINDOW, NC_WINDOW);
+ /* Wait 2s to start rendering icon previews, to not bog down user interaction.
+ * Particularly important for heavy scenes and Eevee using OpenGL that blocks
+ * the user interface drawing. */
+ WM_jobs_timer(wm_job, 2.0, NC_WINDOW, NC_WINDOW);
WM_jobs_callbacks(wm_job, icon_preview_startjob_all_sizes, NULL, NULL, icon_preview_endjob);
WM_jobs_start(CTX_wm_manager(C), wm_job);
@@ -1470,6 +1479,9 @@ void ED_preview_shader_job(const bContext *C,
void ED_preview_kill_jobs(wmWindowManager *wm, Main *UNUSED(bmain))
{
if (wm) {
+ /* This is called to stop all preview jobs before scene data changes, to
+ * avoid invalid memory access. */
WM_jobs_kill(wm, NULL, common_preview_startjob);
+ WM_jobs_kill(wm, NULL, icon_preview_startjob_all_sizes);
}
}
diff --git a/source/blender/editors/screen/screendump.c b/source/blender/editors/screen/screendump.c
index 3b763c7d47a..e5552314a6e 100644
--- a/source/blender/editors/screen/screendump.c
+++ b/source/blender/editors/screen/screendump.c
@@ -43,8 +43,6 @@
#include "BKE_main.h"
#include "BKE_report.h"
-#include "BIF_gl.h"
-
#include "RNA_access.h"
#include "RNA_define.h"
@@ -63,59 +61,25 @@ typedef struct ScreenshotData {
ImageFormatData im_format;
} ScreenshotData;
-static void screenshot_read_pixels(int x, int y, int w, int h, unsigned char *rect)
-{
- int i;
-
- glReadPixels(x, y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, rect);
- glFinish();
-
- /* clear alpha, it is not set to a meaningful value in opengl */
- for (i = 0, rect += 3; i < w * h; i++, rect += 4) {
- *rect = 255;
- }
-}
-
-/* get shot from frontbuffer */
-static unsigned int *screenshot(bContext *C, int *dumpsx, int *dumpsy)
-{
- wmWindow *win = CTX_wm_window(C);
- int x = 0, y = 0;
- unsigned int *dumprect = NULL;
-
- x = 0;
- y = 0;
- *dumpsx = WM_window_pixels_x(win);
- *dumpsy = WM_window_pixels_y(win);
-
- if (*dumpsx && *dumpsy) {
-
- dumprect = MEM_mallocN(sizeof(int) * (*dumpsx) * (*dumpsy), "dumprect");
- glReadBuffer(GL_FRONT);
- screenshot_read_pixels(x, y, *dumpsx, *dumpsy, (unsigned char *)dumprect);
- glReadBuffer(GL_BACK);
- }
-
- return dumprect;
-}
-
/* call from both exec and invoke */
static int screenshot_data_create(bContext *C, wmOperator *op)
{
- unsigned int *dumprect;
- int dumpsx, dumpsy;
+ int dumprect_size[2];
+
+ wmWindowManager *wm = CTX_wm_manager(C);
+ wmWindow *win = CTX_wm_window(C);
/* do redraw so we don't show popups/menus */
WM_redraw_windows(C);
- dumprect = screenshot(C, &dumpsx, &dumpsy);
+ uint *dumprect = WM_window_pixels_read(wm, win, dumprect_size);
if (dumprect) {
ScreenshotData *scd = MEM_callocN(sizeof(ScreenshotData), "screenshot");
ScrArea *sa = CTX_wm_area(C);
- scd->dumpsx = dumpsx;
- scd->dumpsy = dumpsy;
+ scd->dumpsx = dumprect_size[0];
+ scd->dumpsy = dumprect_size[1];
scd->dumprect = dumprect;
if (sa) {
scd->crop = sa->totrct;
diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c
index a151061ae64..86f99555e12 100644
--- a/source/blender/editors/space_outliner/outliner_draw.c
+++ b/source/blender/editors/space_outliner/outliner_draw.c
@@ -1057,7 +1057,7 @@ static void outliner_draw_restrictbuts(uiBlock *block,
0,
0,
0,
- TIP_("Temporarly hide in viewport\n"
+ TIP_("Temporarily hide in viewport\n"
"* Shift to set children"));
UI_but_func_set(
bt, outliner__base_set_flag_recursive_cb, base, (void *)"hide_viewport");
diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c
index 2a0bc470bcb..d428a190549 100644
--- a/source/blender/editors/space_outliner/outliner_tree.c
+++ b/source/blender/editors/space_outliner/outliner_tree.c
@@ -2126,6 +2126,45 @@ static bool outliner_filter_has_name(TreeElement *te, const char *name, int flag
return fnmatch(name, te->name, fn_flag) == 0;
}
+static bool outliner_element_is_collection_or_object(TreeElement *te)
+{
+ TreeStoreElem *tselem = TREESTORE(te);
+
+ if ((tselem->type == 0) && (te->idcode == ID_OB)) {
+ return true;
+ }
+ else if (outliner_is_collection_tree_element(te)) {
+ return true;
+ }
+
+ return false;
+}
+
+static TreeElement *outliner_extract_children_from_subtree(TreeElement *element,
+ ListBase *parent_subtree)
+{
+ TreeElement *te_next = element->next;
+
+ if (outliner_element_is_collection_or_object(element)) {
+ TreeElement *te_prev = NULL;
+ for (TreeElement *te = element->subtree.last; te; te = te_prev) {
+ te_prev = te->prev;
+
+ if (!outliner_element_is_collection_or_object(te)) {
+ continue;
+ }
+
+ te_next = te;
+ BLI_remlink(&element->subtree, te);
+ BLI_insertlinkafter(parent_subtree, element->prev, te);
+ te->parent = element->parent;
+ }
+ }
+
+ outliner_free_tree_element(element, parent_subtree);
+ return te_next;
+}
+
static int outliner_filter_subtree(SpaceOutliner *soops,
ViewLayer *view_layer,
ListBase *lb,
@@ -2137,9 +2176,9 @@ static int outliner_filter_subtree(SpaceOutliner *soops,
for (te = lb->first; te; te = te_next) {
te_next = te->next;
-
if ((outliner_element_visible_get(view_layer, te, exclude_filter) == false)) {
- outliner_free_tree_element(te, lb);
+ /* Don't free the tree, but extract the children from the parent and add to this tree. */
+ te_next = outliner_extract_children_from_subtree(te, lb);
continue;
}
else if ((exclude_filter & SO_FILTER_SEARCH) == 0) {
diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c
index c3e683b5f59..ff0ab9285db 100644
--- a/source/blender/editors/space_sequencer/sequencer_edit.c
+++ b/source/blender/editors/space_sequencer/sequencer_edit.c
@@ -1320,6 +1320,7 @@ static int sequencer_snap_exec(bContext *C, wmOperator *op)
/* as last: */
BKE_sequencer_sort(scene);
+ DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS);
WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
return OPERATOR_FINISHED;
diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c
index 6e12091cf75..b6eb57a3c81 100644
--- a/source/blender/editors/space_view3d/view3d_edit.c
+++ b/source/blender/editors/space_view3d/view3d_edit.c
@@ -4607,7 +4607,7 @@ static int view3d_navigate_invoke(bContext *C,
void VIEW3D_OT_navigate(wmOperatorType *ot)
{
/* identifiers */
- ot->name = "View Navigation";
+ ot->name = "View Navigation (Walk/Fly)";
ot->description =
"Interactively navigate around the scene (uses the mode (walk/fly) preference)";
ot->idname = "VIEW3D_OT_navigate";
diff --git a/source/blender/editors/util/gizmo_utils.c b/source/blender/editors/util/gizmo_utils.c
index d330019c816..b856c831424 100644
--- a/source/blender/editors/util/gizmo_utils.c
+++ b/source/blender/editors/util/gizmo_utils.c
@@ -59,7 +59,12 @@ bool ED_gizmo_poll_or_unlink_delayed_from_tool_ex(const bContext *C,
{
bToolRef_Runtime *tref_rt = WM_toolsystem_runtime_from_context((bContext *)C);
if ((tref_rt == NULL) || !STREQ(gzgt_idname, tref_rt->gizmo_group)) {
- WM_gizmo_group_type_unlink_delayed_ptr(gzgt);
+ ScrArea *sa = CTX_wm_area(C);
+ wmGizmoMapType *gzmap_type = WM_gizmomaptype_ensure(&gzgt->gzmap_params);
+ WM_gizmo_group_unlink_delayed_ptr_from_space(gzgt, gzmap_type, sa);
+ if (gzgt->users == 0) {
+ WM_gizmo_group_type_unlink_delayed_ptr(gzgt);
+ }
return false;
}
return true;
diff --git a/source/blender/makesdna/DNA_constraint_types.h b/source/blender/makesdna/DNA_constraint_types.h
index 396030445f3..b613c661f29 100644
--- a/source/blender/makesdna/DNA_constraint_types.h
+++ b/source/blender/makesdna/DNA_constraint_types.h
@@ -315,12 +315,9 @@ typedef struct bMinMaxConstraint {
int minmaxflag;
float offset;
int flag;
- /** For backward compatibility. */
- short sticky, stuck;
- char _pad[4];
- float cache[3];
/** MAX_ID_NAME-2. */
char subtarget[64];
+ int _pad;
} bMinMaxConstraint;
/* Action Constraint */
@@ -945,8 +942,8 @@ typedef enum eArmature_Flags {
/* MinMax (floor) flags */
typedef enum eFloor_Flags {
- MINMAX_STICKY = (1 << 0),
- MINMAX_STUCK = (1 << 1),
+ /* MINMAX_STICKY = (1 << 0), */ /* Deprecated. */
+ /* MINMAX_STUCK = (1 << 1), */ /* Deprecated. */
MINMAX_USEROT = (1 << 2),
} eFloor_Flags;
diff --git a/source/blender/makesdna/DNA_object_enums.h b/source/blender/makesdna/DNA_object_enums.h
index 44aeb5feaff..75fca117b06 100644
--- a/source/blender/makesdna/DNA_object_enums.h
+++ b/source/blender/makesdna/DNA_object_enums.h
@@ -49,9 +49,11 @@ typedef enum eObjectMode {
/** Any mode that uses Object.sculpt. */
#define OB_MODE_ALL_SCULPT (OB_MODE_SCULPT | OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT)
-/** Any mode that has data we need to free when switching modes,
+/** Any mode that has data or for Grease Pencil modes, we need to free when switching modes,
* see: #ED_object_mode_generic_exit */
#define OB_MODE_ALL_MODE_DATA \
- (OB_MODE_EDIT | OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | OB_MODE_SCULPT | OB_MODE_POSE)
+ (OB_MODE_EDIT | OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | OB_MODE_SCULPT | OB_MODE_POSE | \
+ OB_MODE_PAINT_GPENCIL | OB_MODE_EDIT_GPENCIL | OB_MODE_SCULPT_GPENCIL | \
+ OB_MODE_WEIGHT_GPENCIL)
#endif /* __DNA_OBJECT_ENUMS_H__ */
diff --git a/source/blender/makesrna/intern/rna_armature.c b/source/blender/makesrna/intern/rna_armature.c
index 99b2c423b44..aef35684ff7 100644
--- a/source/blender/makesrna/intern/rna_armature.c
+++ b/source/blender/makesrna/intern/rna_armature.c
@@ -1355,7 +1355,7 @@ static void rna_def_armature(BlenderRNA *brna)
prop = RNA_def_property(srna, "display_type", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "drawtype");
RNA_def_property_enum_items(prop, prop_drawtype_items);
- RNA_def_property_ui_text(prop, "Display Type Type", "");
+ RNA_def_property_ui_text(prop, "Display Type", "");
RNA_def_property_update(prop, 0, "rna_Armature_redraw_data");
RNA_def_property_flag(prop, PROP_LIB_EXCEPTION);
diff --git a/source/blender/makesrna/intern/rna_constraint.c b/source/blender/makesrna/intern/rna_constraint.c
index 1724bf1652b..6e57d16df27 100644
--- a/source/blender/makesrna/intern/rna_constraint.c
+++ b/source/blender/makesrna/intern/rna_constraint.c
@@ -1483,11 +1483,6 @@ static void rna_def_constraint_minmax(BlenderRNA *brna)
prop, "Floor Location", "Location of target that object will not pass through");
RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
- prop = RNA_def_property(srna, "use_sticky", PROP_BOOLEAN, PROP_NONE);
- RNA_def_property_boolean_sdna(prop, NULL, "flag", MINMAX_STICKY);
- RNA_def_property_ui_text(prop, "Sticky", "Immobilize object while constrained");
- RNA_def_property_update(prop, NC_OBJECT | ND_CONSTRAINT, "rna_Constraint_update");
-
prop = RNA_def_property(srna, "use_rotation", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", MINMAX_USEROT);
RNA_def_property_ui_text(prop, "Use Rotation", "Use the target's rotation to determine floor");
diff --git a/source/blender/makesrna/intern/rna_gpencil.c b/source/blender/makesrna/intern/rna_gpencil.c
index a3ef539d0d5..b59e97f1991 100644
--- a/source/blender/makesrna/intern/rna_gpencil.c
+++ b/source/blender/makesrna/intern/rna_gpencil.c
@@ -1435,11 +1435,11 @@ static void rna_def_gpencil_layer(BlenderRNA *brna)
prop, "Disallow Locked Materials Editing", "Avoids editing locked materials in the layer");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, NULL);
- prop = RNA_def_property(srna, "clamp_layer", PROP_BOOLEAN, PROP_NONE);
+ prop = RNA_def_property(srna, "mask_layer", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", GP_LAYER_USE_MASK);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
RNA_def_property_ui_text(
- prop, "Clamp Layer", "Clamp any pixel outside underlying layers drawing");
+ prop, "Mask Layer", "Remove any pixel outside underlying layers drawing");
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_GPencil_update");
/* solo mode: Only display frames with keyframe */
diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c
index 3468e220e1c..1fa03ec87d8 100644
--- a/source/blender/makesrna/intern/rna_object.c
+++ b/source/blender/makesrna/intern/rna_object.c
@@ -444,7 +444,7 @@ static void rna_Object_data_set(PointerRNA *ptr, PointerRNA value, struct Report
if ((id->tag & LIB_TAG_NO_MAIN) != (ob->id.tag & LIB_TAG_NO_MAIN)) {
BKE_report(reports,
RPT_ERROR,
- "Can only assign evaluated data to to evaluated object, or original data to "
+ "Can only assign evaluated data to evaluated object, or original data to "
"original object");
return;
}
diff --git a/source/blender/makesrna/intern/rna_screen.c b/source/blender/makesrna/intern/rna_screen.c
index 6856d877fff..853017e6daf 100644
--- a/source/blender/makesrna/intern/rna_screen.c
+++ b/source/blender/makesrna/intern/rna_screen.c
@@ -553,6 +553,11 @@ static void rna_def_screen(BlenderRNA *brna)
RNA_def_property_boolean_funcs(prop, "rna_Screen_is_animation_playing_get", NULL);
RNA_def_property_ui_text(prop, "Animation Playing", "Animation playback is active");
+ prop = RNA_def_property(srna, "is_temporary", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_boolean_sdna(prop, NULL, "temp", 1);
+ RNA_def_property_ui_text(prop, "Temporary", "");
+
prop = RNA_def_property(srna, "show_fullscreen", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_boolean_funcs(prop, "rna_Screen_fullscreen_get", NULL);
@@ -571,7 +576,7 @@ static void rna_def_screen(BlenderRNA *brna)
prop = RNA_def_property(srna, "use_play_3d_editors", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "redraws_flag", TIME_ALL_3D_WIN);
- RNA_def_property_ui_text(prop, "All 3D View Editors", "");
+ RNA_def_property_ui_text(prop, "All 3D Viewports", "");
RNA_def_property_update(prop, NC_SPACE | ND_SPACE_TIME, "rna_Screen_redraw_update");
prop = RNA_def_property(srna, "use_follow", PROP_BOOLEAN, PROP_NONE);
diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h
index 61b3b8aa2a2..d4fbbd1ecff 100644
--- a/source/blender/windowmanager/WM_api.h
+++ b/source/blender/windowmanager/WM_api.h
@@ -105,6 +105,8 @@ void WM_init_opengl(struct Main *bmain);
void WM_check(struct bContext *C);
void WM_reinit_gizmomap_all(struct Main *bmain);
+uint *WM_window_pixels_read(struct wmWindowManager *wm, struct wmWindow *win, int r_size[2]);
+
int WM_window_pixels_x(const struct wmWindow *win);
int WM_window_pixels_y(const struct wmWindow *win);
void WM_window_rect_calc(const struct wmWindow *win, struct rcti *r_rect);
diff --git a/source/blender/windowmanager/gizmo/WM_gizmo_api.h b/source/blender/windowmanager/gizmo/WM_gizmo_api.h
index 293b0cd91dc..5896424d5fe 100644
--- a/source/blender/windowmanager/gizmo/WM_gizmo_api.h
+++ b/source/blender/windowmanager/gizmo/WM_gizmo_api.h
@@ -34,6 +34,7 @@ struct GHashIterator;
struct IDProperty;
struct Main;
struct PropertyRNA;
+struct ScrArea;
struct bToolRef;
struct wmGizmo;
struct wmGizmoGroup;
@@ -166,6 +167,8 @@ void WM_gizmoconfig_update_tag_group_type_remove(struct wmGizmoMapType *gzmap_ty
struct wmGizmoGroupType *gzgt);
void WM_gizmoconfig_update(struct Main *bmain);
+void WM_gizmoconfig_update_tag_group_remove(struct wmGizmoMap *gzmap);
+
/* wm_maniulator_target_props.c */
struct wmGizmoProperty *WM_gizmo_target_property_array(struct wmGizmo *gz);
struct wmGizmoProperty *WM_gizmo_target_property_at_index(struct wmGizmo *gz, int index);
@@ -354,6 +357,10 @@ void WM_gizmo_group_type_unlink_delayed_ptr_ex(struct wmGizmoGroupType *gzgt,
void WM_gizmo_group_type_unlink_delayed_ptr(struct wmGizmoGroupType *gzgt);
void WM_gizmo_group_type_unlink_delayed(const char *idname);
+void WM_gizmo_group_unlink_delayed_ptr_from_space(struct wmGizmoGroupType *gzgt,
+ struct wmGizmoMapType *gzmap_type,
+ struct ScrArea *sa);
+
/* Has the result of unlinking and linking (re-initializes gizmo's). */
void WM_gizmo_group_type_reinit_ptr_ex(struct Main *bmain,
struct wmGizmoGroupType *gzgt,
@@ -370,4 +377,6 @@ void WM_gizmo_group_remove_by_tool(struct bContext *C,
const struct wmGizmoGroupType *gzgt,
const struct bToolRef *tref);
+void WM_gizmo_group_tag_remove(struct wmGizmoGroup *gzgroup);
+
#endif /* __WM_GIZMO_API_H__ */
diff --git a/source/blender/windowmanager/gizmo/WM_gizmo_types.h b/source/blender/windowmanager/gizmo/WM_gizmo_types.h
index 7afd2908b8e..68ecdeea936 100644
--- a/source/blender/windowmanager/gizmo/WM_gizmo_types.h
+++ b/source/blender/windowmanager/gizmo/WM_gizmo_types.h
@@ -417,6 +417,12 @@ typedef struct wmGizmoGroupType {
/** Same as gizmo-maps, so registering/unregistering goes to the correct region. */
struct wmGizmoMapType_Params gzmap_params;
+ /**
+ * Number of #wmGizmoGroup instances.
+ * Decremented when 'tag_remove' is set, or when removed.
+ */
+ int users;
+
} wmGizmoGroupType;
typedef struct wmGizmoGroup {
@@ -432,6 +438,8 @@ typedef struct wmGizmoGroup {
/** Errors and warnings storage. */
struct ReportList *reports;
+ bool tag_remove;
+
void *customdata;
/** For freeing customdata from above. */
void (*customdata_free)(void *);
diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_group.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_group.c
index f996d938dd7..40d99ce8ba6 100644
--- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_group.c
+++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_group.c
@@ -70,7 +70,9 @@
wmGizmoGroup *wm_gizmogroup_new_from_type(wmGizmoMap *gzmap, wmGizmoGroupType *gzgt)
{
wmGizmoGroup *gzgroup = MEM_callocN(sizeof(*gzgroup), "gizmo-group");
+
gzgroup->type = gzgt;
+ gzgroup->type->users += 1;
/* keep back-link */
gzgroup->parent_gzmap = gzmap;
@@ -130,9 +132,23 @@ void wm_gizmogroup_free(bContext *C, wmGizmoGroup *gzgroup)
BLI_remlink(&gzmap->groups, gzgroup);
+ if (gzgroup->tag_remove == false) {
+ gzgroup->type->users -= 1;
+ }
+
MEM_freeN(gzgroup);
}
+void WM_gizmo_group_tag_remove(wmGizmoGroup *gzgroup)
+{
+ if (gzgroup->tag_remove == false) {
+ gzgroup->tag_remove = true;
+ gzgroup->type->users -= 1;
+ BLI_assert(gzgroup->type->users >= 0);
+ WM_gizmoconfig_update_tag_group_remove(gzgroup->parent_gzmap);
+ }
+}
+
/**
* Add \a gizmo to \a gzgroup and make sure its name is unique within the group.
*/
@@ -1099,4 +1115,20 @@ void WM_gizmo_group_type_unlink_delayed(const char *idname)
WM_gizmo_group_type_unlink_delayed_ptr(gzgt);
}
+void WM_gizmo_group_unlink_delayed_ptr_from_space(wmGizmoGroupType *gzgt,
+ wmGizmoMapType *gzmap_type,
+ ScrArea *sa)
+{
+ for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) {
+ wmGizmoMap *gzmap = ar->gizmo_map;
+ if (gzmap && gzmap->type == gzmap_type) {
+ for (wmGizmoGroup *gzgroup = gzmap->groups.first; gzgroup; gzgroup = gzgroup->next) {
+ if (gzgroup->type == gzgt) {
+ WM_gizmo_group_tag_remove(gzgroup);
+ }
+ }
+ }
+ }
+}
+
/** \} */
diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_intern.h b/source/blender/windowmanager/gizmo/intern/wm_gizmo_intern.h
index 98c3ad8295c..f0771437518 100644
--- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_intern.h
+++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_intern.h
@@ -99,6 +99,9 @@ struct wmGizmoMap {
/** Private, true when not yet used. */
bool is_init;
+ /** When set, one of of the items in 'groups' has #wmGizmoGroup.tag_remove set. */
+ bool tag_remove_group;
+
/**
* \brief Gizmo map runtime context
*
diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c
index edf376b1259..be123bee5df 100644
--- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c
+++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c
@@ -69,8 +69,13 @@ static ListBase gizmomaptypes = {NULL, NULL};
*/
/* so operator removal can trigger update */
typedef enum eWM_GizmoFlagGroupTypeGlobalFlag {
+ /** Initialize by #wmGroupType.type_update_flag. */
WM_GIZMOMAPTYPE_GLOBAL_UPDATE_INIT = (1 << 0),
+ /** Remove by #wmGroupType.type_update_flag. */
WM_GIZMOMAPTYPE_GLOBAL_UPDATE_REMOVE = (1 << 1),
+
+ /** Remove by #wmGroup.tag_remove. */
+ WM_GIZMOTYPE_GLOBAL_UPDATE_REMOVE = (1 << 2),
} eWM_GizmoFlagGroupTypeGlobalFlag;
static eWM_GizmoFlagGroupTypeGlobalFlag wm_gzmap_type_update_flag = 0;
@@ -1257,6 +1262,13 @@ void WM_gizmoconfig_update_tag_group_type_remove(wmGizmoMapType *gzmap_type,
wm_gzmap_type_update_flag |= WM_GIZMOMAPTYPE_GLOBAL_UPDATE_REMOVE;
}
+void WM_gizmoconfig_update_tag_group_remove(wmGizmoMap *gzmap)
+{
+ gzmap->tag_remove_group = true;
+
+ wm_gzmap_type_update_flag |= WM_GIZMOTYPE_GLOBAL_UPDATE_REMOVE;
+}
+
/**
* Run in case new types have been added (runs often, early exit where possible).
* Follows #WM_keyconfig_update conventions.
@@ -1271,6 +1283,32 @@ void WM_gizmoconfig_update(struct Main *bmain)
return;
}
+ if (wm_gzmap_type_update_flag & WM_GIZMOTYPE_GLOBAL_UPDATE_REMOVE) {
+ for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) {
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ for (SpaceLink *sl = sa->spacedata.first; sl; sl = sl->next) {
+ ListBase *regionbase = (sl == sa->spacedata.first) ? &sa->regionbase : &sl->regionbase;
+ for (ARegion *ar = regionbase->first; ar; ar = ar->next) {
+ wmGizmoMap *gzmap = ar->gizmo_map;
+ if (gzmap != NULL && gzmap->tag_remove_group) {
+ gzmap->tag_remove_group = false;
+
+ for (wmGizmoGroup *gzgroup = gzmap->groups.first, *gzgroup_next; gzgroup;
+ gzgroup = gzgroup_next) {
+ gzgroup_next = gzgroup->next;
+ if (gzgroup->tag_remove) {
+ wm_gizmogroup_free(NULL, gzgroup);
+ ED_region_tag_redraw(ar);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ wm_gzmap_type_update_flag &= ~WM_GIZMOTYPE_GLOBAL_UPDATE_REMOVE;
+ }
+
if (wm_gzmap_type_update_flag & WM_GIZMOMAPTYPE_GLOBAL_UPDATE_REMOVE) {
for (wmGizmoMapType *gzmap_type = gizmomaptypes.first; gzmap_type;
gzmap_type = gzmap_type->next) {
diff --git a/source/blender/windowmanager/intern/wm_toolsystem.c b/source/blender/windowmanager/intern/wm_toolsystem.c
index ae9c6e267e2..11286a822a7 100644
--- a/source/blender/windowmanager/intern/wm_toolsystem.c
+++ b/source/blender/windowmanager/intern/wm_toolsystem.c
@@ -729,9 +729,8 @@ static bToolRef *toolsystem_reinit_ensure_toolref(bContext *C,
return tref;
}
-void WM_toolsystem_update_from_context_view3d(bContext *C)
+static void wm_toolsystem_update_from_context_view3d_impl(bContext *C, WorkSpace *workspace)
{
- WorkSpace *workspace = CTX_wm_workspace(C);
ViewLayer *view_layer = CTX_data_view_layer(C);
int space_type = SPACE_VIEW3D;
const bToolKey tkey = {
@@ -741,6 +740,37 @@ void WM_toolsystem_update_from_context_view3d(bContext *C)
toolsystem_reinit_ensure_toolref(C, workspace, &tkey, NULL);
}
+void WM_toolsystem_update_from_context_view3d(bContext *C)
+{
+ WorkSpace *workspace = CTX_wm_workspace(C);
+ wm_toolsystem_update_from_context_view3d_impl(C, workspace);
+
+ /* Multi window support. */
+ Main *bmain = CTX_data_main(C);
+ wmWindowManager *wm = bmain->wm.first;
+ if (!BLI_listbase_is_single(&wm->windows)) {
+ wmWindow *win_prev = CTX_wm_window(C);
+ ScrArea *area_prev = CTX_wm_area(C);
+ ARegion *ar_prev = CTX_wm_region(C);
+
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ if (win != win_prev) {
+ WorkSpace *workspace_iter = WM_window_get_active_workspace(win);
+ if (workspace_iter != workspace) {
+
+ CTX_wm_window_set(C, win);
+
+ wm_toolsystem_update_from_context_view3d_impl(C, workspace_iter);
+
+ CTX_wm_window_set(C, win_prev);
+ CTX_wm_area_set(C, area_prev);
+ CTX_wm_region_set(C, ar_prev);
+ }
+ }
+ }
+ }
+}
+
void WM_toolsystem_update_from_context(bContext *C,
WorkSpace *workspace,
ViewLayer *view_layer,
@@ -769,12 +799,23 @@ void WM_toolsystem_do_msg_notify_tag_refresh(bContext *C,
wmMsgSubscribeKey *UNUSED(msg_key),
wmMsgSubscribeValue *msg_val)
{
- WorkSpace *workspace = CTX_wm_workspace(C);
- ViewLayer *view_layer = CTX_data_view_layer(C);
ScrArea *sa = msg_val->user_data;
- int space_type = sa->spacetype;
+ Main *bmain = CTX_data_main(C);
+ wmWindow *win = ((wmWindowManager *)bmain->wm.first)->windows.first;
+ if (win->next != NULL) {
+ do {
+ bScreen *screen = WM_window_get_active_screen(win);
+ if (BLI_findindex(&screen->areabase, sa) != -1) {
+ break;
+ }
+ } while ((win = win->next));
+ }
+
+ WorkSpace *workspace = WM_window_get_active_workspace(win);
+ ViewLayer *view_layer = WM_window_get_active_view_layer(win);
+
const bToolKey tkey = {
- .space_type = space_type,
+ .space_type = sa->spacetype,
.mode = WM_toolsystem_mode_from_spacetype(view_layer, sa, sa->spacetype),
};
WM_toolsystem_refresh(C, workspace, &tkey);
diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c
index 7558468c3b5..ea3596a2143 100644
--- a/source/blender/windowmanager/intern/wm_window.c
+++ b/source/blender/windowmanager/intern/wm_window.c
@@ -1937,6 +1937,50 @@ bool wm_window_get_swap_interval(wmWindow *win, int *intervalOut)
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Window Screen Shot Utility
+ *
+ * Include here since it can involve low level buffer switching.
+ *
+ * \{ */
+
+uint *WM_window_pixels_read(wmWindowManager *wm, wmWindow *win, int r_size[2])
+{
+ bool setup_context = wm->windrawable != win;
+
+ if (setup_context) {
+ GHOST_ActivateWindowDrawingContext(win->ghostwin);
+ GPU_context_active_set(win->gpuctx);
+ }
+
+ r_size[0] = WM_window_pixels_x(win);
+ r_size[1] = WM_window_pixels_y(win);
+ const uint rect_len = r_size[0] * r_size[1];
+ uint *rect = MEM_mallocN(sizeof(*rect) * rect_len, __func__);
+
+ glReadBuffer(GL_FRONT);
+ glReadPixels(0, 0, r_size[0], r_size[1], GL_RGBA, GL_UNSIGNED_BYTE, rect);
+ glFinish();
+ glReadBuffer(GL_BACK);
+
+ if (setup_context) {
+ if (wm->windrawable) {
+ GHOST_ActivateWindowDrawingContext(wm->windrawable->ghostwin);
+ GPU_context_active_set(wm->windrawable->gpuctx);
+ }
+ }
+
+ /* Clear alpha, it is not set to a meaningful value in OpenGL. */
+ uchar *cp = (uchar *)rect;
+ uint i;
+ for (i = 0, cp += 3; i < rect_len; i++, cp += 4) {
+ *cp = 0xff;
+ }
+ return (uint *)rect;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Initial Window State API
* \{ */