diff options
author | YimingWu <xp8110@outlook.com> | 2019-07-01 04:49:08 +0300 |
---|---|---|
committer | YimingWu <xp8110@outlook.com> | 2019-07-01 04:49:08 +0300 |
commit | 27ca5cdfeee638226126822191b7e69cf5b90e79 (patch) | |
tree | 8bd4ebdc2dfcdaab35d93b05be67d4f2963ec21a /source | |
parent | 37c3aa8eabbb3ba5f5718070744c0c60b67f0f21 (diff) | |
parent | bbb3500c97167c070a76373e023bdd8820d3ca41 (diff) |
Merge branch 'master' into soc-2019-npr
Diffstat (limited to 'source')
53 files changed, 928 insertions, 559 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 * \{ */ diff --git a/source/creator/creator_args.c b/source/creator/creator_args.c index 6bf22f87781..f3550034a2f 100644 --- a/source/creator/creator_args.c +++ b/source/creator/creator_args.c @@ -1481,7 +1481,7 @@ static int arg_handle_threads_set(int argc, const char **argv, void *UNUSED(data static const char arg_handle_verbosity_set_doc[] = "<verbose>\n" - "\tSet logging verbosity level."; + "\tSet logging verbosity level for debug messages which supports it."; static int arg_handle_verbosity_set(int argc, const char **argv, void *UNUSED(data)) { const char *arg_id = "--verbose"; |