diff options
Diffstat (limited to 'source/blender/editors')
205 files changed, 10807 insertions, 7421 deletions
diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c index d48e09e0504..cd17a490240 100644 --- a/source/blender/editors/animation/anim_channels_defines.c +++ b/source/blender/editors/animation/anim_channels_defines.c @@ -51,6 +51,7 @@ #include "DNA_pointcloud_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" +#include "DNA_simulation_types.h" #include "DNA_space_types.h" #include "DNA_speaker_types.h" #include "DNA_volume_types.h" @@ -3033,6 +3034,83 @@ static bAnimChannelType ACF_DSVOLUME = { acf_dsvolume_setting_ptr /* pointer for setting */ }; +/* Simulation Expander ----------------------------------------- */ + +static int acf_dssimulation_icon(bAnimListElem *UNUSED(ale)) +{ + /* TODO: Use correct icon. */ + return ICON_PHYSICS; +} + +static int acf_dssimulation_setting_flag(bAnimContext *UNUSED(ac), + eAnimChannel_Settings setting, + bool *neg) +{ + /* clear extra return data first */ + *neg = false; + + switch (setting) { + case ACHANNEL_SETTING_EXPAND: /* expanded */ + return SIM_DS_EXPAND; + + case ACHANNEL_SETTING_MUTE: /* mute (only in NLA) */ + return ADT_NLA_EVAL_OFF; + + case ACHANNEL_SETTING_VISIBLE: /* visible (only in Graph Editor) */ + *neg = true; + return ADT_CURVES_NOT_VISIBLE; + + case ACHANNEL_SETTING_SELECT: /* selected */ + return ADT_UI_SELECTED; + + default: /* unsupported */ + return 0; + } +} + +static void *acf_dssimulation_setting_ptr(bAnimListElem *ale, + eAnimChannel_Settings setting, + short *type) +{ + Simulation *simulation = (Simulation *)ale->data; + + /* clear extra return data first */ + *type = 0; + + switch (setting) { + case ACHANNEL_SETTING_EXPAND: /* expanded */ + return GET_ACF_FLAG_PTR(simulation->flag, type); + + case ACHANNEL_SETTING_SELECT: /* selected */ + case ACHANNEL_SETTING_MUTE: /* muted (for NLA only) */ + case ACHANNEL_SETTING_VISIBLE: /* visible (for Graph Editor only) */ + if (simulation->adt) + return GET_ACF_FLAG_PTR(simulation->adt->flag, type); + return NULL; + + default: /* unsupported */ + return NULL; + } +} + +static bAnimChannelType ACF_DSSIMULATION = { + "Simulation Expander", /* type name */ + ACHANNEL_ROLE_EXPANDER, /* role */ + + acf_generic_dataexpand_color, /* backdrop color */ + acf_generic_dataexpand_backdrop, /* backdrop */ + acf_generic_indention_1, /* indent level */ + acf_generic_basic_offset, /* offset */ + + acf_generic_idblock_name, /* name */ + acf_generic_idblock_name_prop, /* name prop */ + acf_dssimulation_icon, /* icon */ + + acf_generic_dataexpand_setting_valid, /* has setting */ + acf_dssimulation_setting_flag, /* flag for setting */ + acf_dssimulation_setting_ptr /* pointer for setting */ +}; + /* GPencil Expander ------------------------------------------- */ // TODO: just get this from RNA? @@ -4049,6 +4127,7 @@ static void ANIM_init_channel_typeinfo_data(void) animchannelTypeInfo[type++] = &ACF_DSHAIR; /* Hair Channel */ animchannelTypeInfo[type++] = &ACF_DSPOINTCLOUD; /* PointCloud Channel */ animchannelTypeInfo[type++] = &ACF_DSVOLUME; /* Volume Channel */ + animchannelTypeInfo[type++] = &ACF_DSSIMULATION; /* Simulation Channel */ animchannelTypeInfo[type++] = &ACF_SHAPEKEY; /* ShapeKey */ diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c index 4e3dc3cb220..a7ca84eb6c6 100644 --- a/source/blender/editors/animation/anim_channels_edit.c +++ b/source/blender/editors/animation/anim_channels_edit.c @@ -138,7 +138,8 @@ void ANIM_set_active_channel(bAnimContext *ac, case ANIMTYPE_DSMCLIP: case ANIMTYPE_DSHAIR: case ANIMTYPE_DSPOINTCLOUD: - case ANIMTYPE_DSVOLUME: { + case ANIMTYPE_DSVOLUME: + case ANIMTYPE_DSSIMULATION: { /* need to verify that this data is valid for now */ if (ale->adt) { ACHANNEL_SET_FLAG(ale->adt, ACHANNEL_SETFLAG_CLEAR, ADT_UI_ACTIVE); @@ -194,7 +195,8 @@ void ANIM_set_active_channel(bAnimContext *ac, case ANIMTYPE_DSMCLIP: case ANIMTYPE_DSHAIR: case ANIMTYPE_DSPOINTCLOUD: - case ANIMTYPE_DSVOLUME: { + case ANIMTYPE_DSVOLUME: + case ANIMTYPE_DSSIMULATION: { /* need to verify that this data is valid for now */ if (ale && ale->adt) { ale->adt->flag |= ADT_UI_ACTIVE; @@ -332,7 +334,8 @@ void ANIM_deselect_anim_channels( case ANIMTYPE_DSMCLIP: case ANIMTYPE_DSHAIR: case ANIMTYPE_DSPOINTCLOUD: - case ANIMTYPE_DSVOLUME: { + case ANIMTYPE_DSVOLUME: + case ANIMTYPE_DSSIMULATION: { if ((ale->adt) && (ale->adt->flag & ADT_UI_SELECTED)) { sel = ACHANNEL_SETFLAG_CLEAR; } @@ -428,7 +431,8 @@ void ANIM_deselect_anim_channels( case ANIMTYPE_DSMCLIP: case ANIMTYPE_DSHAIR: case ANIMTYPE_DSPOINTCLOUD: - case ANIMTYPE_DSVOLUME: { + case ANIMTYPE_DSVOLUME: + case ANIMTYPE_DSSIMULATION: { /* need to verify that this data is valid for now */ if (ale->adt) { ACHANNEL_SET_FLAG(ale->adt, sel, ADT_UI_SELECTED); @@ -2965,7 +2969,8 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index, case ANIMTYPE_DSMCLIP: case ANIMTYPE_DSHAIR: case ANIMTYPE_DSPOINTCLOUD: - case ANIMTYPE_DSVOLUME: { + case ANIMTYPE_DSVOLUME: + case ANIMTYPE_DSSIMULATION: { /* sanity checking... */ if (ale->adt) { /* select/deselect */ diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c index 4dc0bef3a1b..2b9dfe105bc 100644 --- a/source/blender/editors/animation/anim_filter.c +++ b/source/blender/editors/animation/anim_filter.c @@ -67,6 +67,7 @@ #include "DNA_scene_types.h" #include "DNA_screen_types.h" #include "DNA_sequence_types.h" +#include "DNA_simulation_types.h" #include "DNA_space_types.h" #include "DNA_speaker_types.h" #include "DNA_userdef_types.h" @@ -86,6 +87,7 @@ #include "BKE_collection.h" #include "BKE_context.h" #include "BKE_fcurve.h" +#include "BKE_fcurve_driver.h" #include "BKE_global.h" #include "BKE_key.h" #include "BKE_layer.h" @@ -826,6 +828,18 @@ static bAnimListElem *make_new_animlistelem(void *data, ale->adt = BKE_animdata_from_id(data); break; } + case ANIMTYPE_DSSIMULATION: { + Simulation *simulation = (Simulation *)data; + AnimData *adt = simulation->adt; + + ale->flag = FILTER_SIMULATION_OBJD(simulation); + + ale->key_data = (adt) ? adt->action : NULL; + ale->datatype = ALE_ACT; + + ale->adt = BKE_animdata_from_id(data); + break; + } case ANIMTYPE_DSSKEY: { Key *key = (Key *)data; AnimData *adt = key->adt; @@ -2414,7 +2428,7 @@ static size_t animdata_filter_ds_modifiers( afm.filter_mode = filter_mode; /* 2) walk over dependencies */ - modifiers_foreachIDLink(ob, animfilter_modifier_idpoin_cb, &afm); + BKE_modifiers_foreach_ID_link(ob, animfilter_modifier_idpoin_cb, &afm); /* 3) extract data from the context, merging it back into the standard list */ if (afm.items) { diff --git a/source/blender/editors/animation/anim_ops.c b/source/blender/editors/animation/anim_ops.c index 2db381dfc69..40cd368e02b 100644 --- a/source/blender/editors/animation/anim_ops.c +++ b/source/blender/editors/animation/anim_ops.c @@ -73,15 +73,9 @@ static bool change_frame_poll(bContext *C) * this shouldn't show up in 3D editor (or others without 2D timeline view) via search */ if (area) { - if (ELEM(area->spacetype, SPACE_ACTION, SPACE_NLA, SPACE_SEQ, SPACE_CLIP)) { + if (ELEM(area->spacetype, SPACE_ACTION, SPACE_NLA, SPACE_SEQ, SPACE_CLIP, SPACE_GRAPH)) { return true; } - else if (area->spacetype == SPACE_GRAPH) { - /* NOTE: Graph Editor has special version which does some extra stuff. - * No need to show the generic error message for that case though! - */ - return false; - } } CTX_wm_operator_poll_msg_set(C, "Expected an animation area to be active"); diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c index 3ae4e3bf998..82e24eaa6e3 100644 --- a/source/blender/editors/animation/drivers.c +++ b/source/blender/editors/animation/drivers.c @@ -40,6 +40,7 @@ #include "BKE_animsys.h" #include "BKE_context.h" #include "BKE_fcurve.h" +#include "BKE_fcurve_driver.h" #include "BKE_report.h" #include "DEG_depsgraph.h" diff --git a/source/blender/editors/animation/keyframes_edit.c b/source/blender/editors/animation/keyframes_edit.c index e22fddc6d67..2dae4e8b4c5 100644 --- a/source/blender/editors/animation/keyframes_edit.c +++ b/source/blender/editors/animation/keyframes_edit.c @@ -633,7 +633,7 @@ bool keyframe_region_lasso_test(const KeyframeEdit_LassoData *data_lasso, const BLI_rctf_transform_pt_v(data_lasso->rectf_view, data_lasso->rectf_scaled, xy_view, xy); if (BLI_lasso_is_point_inside( - data_lasso->mcords, data_lasso->mcords_tot, xy_view[0], xy_view[1], INT_MAX)) { + data_lasso->mcoords, data_lasso->mcoords_len, xy_view[0], xy_view[1], INT_MAX)) { return true; } } diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c index 49e936d22aa..04061ceea51 100644 --- a/source/blender/editors/animation/keyframing.c +++ b/source/blender/editors/animation/keyframing.c @@ -50,6 +50,7 @@ #include "BKE_armature.h" #include "BKE_context.h" #include "BKE_fcurve.h" +#include "BKE_fcurve_driver.h" #include "BKE_global.h" #include "BKE_idtype.h" #include "BKE_key.h" diff --git a/source/blender/editors/armature/armature_naming.c b/source/blender/editors/armature/armature_naming.c index aa1bceb2674..544d86d4c47 100644 --- a/source/blender/editors/armature/armature_naming.c +++ b/source/blender/editors/armature/armature_naming.c @@ -265,7 +265,7 @@ void ED_armature_bone_rename(Main *bmain, } } - if (modifiers_usesArmature(ob, arm)) { + if (BKE_modifiers_uses_armature(ob, arm)) { bDeformGroup *dg = BKE_object_defgroup_find_name(ob, oldname); if (dg) { BLI_strncpy(dg->name, newname, MAXBONENAME); diff --git a/source/blender/editors/armature/armature_relations.c b/source/blender/editors/armature/armature_relations.c index d544aed5481..d3d00fc44f2 100644 --- a/source/blender/editors/armature/armature_relations.c +++ b/source/blender/editors/armature/armature_relations.c @@ -42,7 +42,7 @@ #include "BKE_armature.h" #include "BKE_constraint.h" #include "BKE_context.h" -#include "BKE_fcurve.h" +#include "BKE_fcurve_driver.h" #include "BKE_layer.h" #include "BKE_main.h" #include "BKE_report.h" diff --git a/source/blender/editors/armature/armature_skinning.c b/source/blender/editors/armature/armature_skinning.c index b637a57f7c0..61d8856afbc 100644 --- a/source/blender/editors/armature/armature_skinning.c +++ b/source/blender/editors/armature/armature_skinning.c @@ -418,7 +418,7 @@ static void add_verts_to_dgroups(ReportList *reports, BKE_mesh_foreach_mapped_vert_coords_get(me_eval, verts, mesh->totvert); vertsfilled = 1; } - else if (modifiers_findByType(ob, eModifierType_Subsurf)) { + else if (BKE_modifiers_findby_type(ob, eModifierType_Subsurf)) { /* is subsurf on? Lets use the verts on the limit surface then. * = same amount of vertices as mesh, but vertices moved to the * subsurfed position, like for 'optimal'. */ diff --git a/source/blender/editors/armature/meshlaplacian.c b/source/blender/editors/armature/meshlaplacian.c index 6028ddb216f..d8a6a22a7df 100644 --- a/source/blender/editors/armature/meshlaplacian.c +++ b/source/blender/editors/armature/meshlaplacian.c @@ -1549,7 +1549,7 @@ static void meshdeform_matrix_solve(MeshDeformModifierData *mmd, MeshDeformBind } } else { - modifier_setError(&mmd->modifier, "Failed to find bind solution (increase precision?)"); + BKE_modifier_set_error(&mmd->modifier, "Failed to find bind solution (increase precision?)"); error("Mesh Deform: failed to find bind solution."); break; } @@ -1753,7 +1753,7 @@ void ED_mesh_deform_bind_callback(MeshDeformModifierData *mmd, int totvert, float cagemat[4][4]) { - MeshDeformModifierData *mmd_orig = (MeshDeformModifierData *)modifier_get_original( + MeshDeformModifierData *mmd_orig = (MeshDeformModifierData *)BKE_modifier_get_original( &mmd->modifier); MeshDeformBind mdb; MVert *mvert; @@ -1799,7 +1799,7 @@ void ED_mesh_deform_bind_callback(MeshDeformModifierData *mmd, MEM_freeN(mdb.vertexcos); /* compact weights */ - modifier_mdef_compact_influences((ModifierData *)mmd_orig); + BKE_modifier_mdef_compact_influences((ModifierData *)mmd_orig); end_progress_bar(); waitcursor(0); diff --git a/source/blender/editors/armature/pose_select.c b/source/blender/editors/armature/pose_select.c index ce652b0eaf4..9525fcf2154 100644 --- a/source/blender/editors/armature/pose_select.c +++ b/source/blender/editors/armature/pose_select.c @@ -263,7 +263,7 @@ void ED_armature_pose_select_in_wpaint_mode(ViewLayer *view_layer, Base *base_se Object *ob_active = OBACT(view_layer); BLI_assert(ob_active && (ob_active->mode & OB_MODE_WEIGHT_PAINT)); VirtualModifierData virtualModifierData; - ModifierData *md = modifiers_getVirtualModifierList(ob_active, &virtualModifierData); + ModifierData *md = BKE_modifiers_get_virtual_modifierlist(ob_active, &virtualModifierData); for (; md; md = md->next) { if (md->type == eModifierType_Armature) { ArmatureModifierData *amd = (ArmatureModifierData *)md; diff --git a/source/blender/editors/armature/pose_transform.c b/source/blender/editors/armature/pose_transform.c index 31c89ca9f43..1d2bf152777 100644 --- a/source/blender/editors/armature/pose_transform.c +++ b/source/blender/editors/armature/pose_transform.c @@ -1240,7 +1240,7 @@ static int pose_clear_user_transforms_exec(bContext *C, wmOperator *op) workob.adt = ob->adt; workob.pose = dummyPose; - BKE_animsys_evaluate_animdata(scene, &workob.id, workob.adt, cframe, ADT_RECALC_ANIM, false); + BKE_animsys_evaluate_animdata(&workob.id, workob.adt, cframe, ADT_RECALC_ANIM, false); /* copy back values, but on selected bones only */ for (pchan = dummyPose->chanbase.first; pchan; pchan = pchan->next) { diff --git a/source/blender/editors/datafiles/CMakeLists.txt b/source/blender/editors/datafiles/CMakeLists.txt index 3e9d2def78e..1a5b3d6ac45 100644 --- a/source/blender/editors/datafiles/CMakeLists.txt +++ b/source/blender/editors/datafiles/CMakeLists.txt @@ -336,7 +336,7 @@ set(ICON_NAMES force_boid force_turbulence force_drag - force_smokeflow + force_fluidflow image_plane image_background image_reference diff --git a/source/blender/editors/gpencil/annotate_draw.c b/source/blender/editors/gpencil/annotate_draw.c index adaf4ab2459..22df7bbbf31 100644 --- a/source/blender/editors/gpencil/annotate_draw.c +++ b/source/blender/editors/gpencil/annotate_draw.c @@ -90,14 +90,54 @@ typedef enum eDrawStrokeFlags { /* ----- Tool Buffer Drawing ------ */ +static void annotation_draw_stroke_arrow_buffer(uint pos, + const float *corner_point, + const float *arrow_coords, + const int arrow_style) +{ + immBeginAtMost(GPU_PRIM_LINE_STRIP, arrow_style); + + switch (arrow_style) { + case GP_STROKE_ARROWSTYLE_SEGMENT: + immVertex2f(pos, arrow_coords[0], arrow_coords[1]); + immVertex2f(pos, arrow_coords[2], arrow_coords[3]); + break; + case GP_STROKE_ARROWSTYLE_CLOSED: + immVertex2f(pos, arrow_coords[0], arrow_coords[1]); + immVertex2f(pos, arrow_coords[2], arrow_coords[3]); + immVertex2f(pos, arrow_coords[4], arrow_coords[5]); + immVertex2f(pos, arrow_coords[0], arrow_coords[1]); + break; + case GP_STROKE_ARROWSTYLE_OPEN: + immVertex2f(pos, arrow_coords[0], arrow_coords[1]); + immVertex2f(pos, corner_point[0], corner_point[1]); + immVertex2f(pos, arrow_coords[2], arrow_coords[3]); + break; + case GP_STROKE_ARROWSTYLE_SQUARE: + immVertex2f(pos, corner_point[0], corner_point[1]); + immVertex2f(pos, arrow_coords[0], arrow_coords[1]); + immVertex2f(pos, arrow_coords[4], arrow_coords[5]); + immVertex2f(pos, arrow_coords[6], arrow_coords[7]); + immVertex2f(pos, arrow_coords[2], arrow_coords[3]); + immVertex2f(pos, corner_point[0], corner_point[1]); + break; + default: + break; + } + immEnd(); +} + /* draw stroke defined in buffer (simple ogl lines/points for now, as dotted lines) */ -static void annotation_draw_stroke_buffer(const tGPspoint *points, - int totpoints, +static void annotation_draw_stroke_buffer(bGPdata *gps, short thickness, short dflag, - short sflag, const float ink[4]) { + bGPdata_Runtime runtime = gps->runtime; + const tGPspoint *points = runtime.sbuffer; + int totpoints = runtime.sbuffer_used; + short sflag = runtime.sbuffer_sflag; + int draw_points = 0; /* error checking */ @@ -176,6 +216,26 @@ static void annotation_draw_stroke_buffer(const tGPspoint *points, } immEnd(); + + /* Draw arrow stroke. */ + if (totpoints > 1) { + /* Draw ending arrow stroke. */ + if ((sflag & GP_STROKE_USE_ARROW_END) && + (runtime.arrow_end_style != GP_STROKE_ARROWSTYLE_NONE)) { + float end[2]; + copy_v2_fl2(end, points[1].x, points[1].y); + annotation_draw_stroke_arrow_buffer(pos, end, runtime.arrow_end, runtime.arrow_end_style); + } + /* Draw starting arrow stroke. */ + if ((sflag & GP_STROKE_USE_ARROW_START) && + (runtime.arrow_start_style != GP_STROKE_ARROWSTYLE_NONE)) { + float start[2]; + copy_v2_fl2(start, points[0].x, points[0].y); + annotation_draw_stroke_arrow_buffer( + pos, start, runtime.arrow_start, runtime.arrow_start_style); + } + } + immUnbindProgram(); } @@ -524,131 +584,6 @@ static void annotation_draw_strokes(const bGPDframe *gpf, GPU_program_point_size(false); } -/* Draw selected verts for strokes being edited */ -static void annotation_draw_strokes_edit(bGPDlayer *gpl, - const bGPDframe *gpf, - int offsx, - int offsy, - int winx, - int winy, - short dflag, - float alpha) -{ - /* if alpha 0 do not draw */ - if (alpha == 0.0f) { - return; - } - - const bool no_xray = (dflag & GP_DRAWDATA_NO_XRAY) != 0; - int mask_orig = 0; - - /* set up depth masks... */ - if (dflag & GP_DRAWDATA_ONLY3D) { - if (no_xray) { - glGetIntegerv(GL_DEPTH_WRITEMASK, &mask_orig); - glDepthMask(0); - GPU_depth_test(true); - - /* first arg is normally rv3d->dist, but this isn't - * available here and seems to work quite well without */ - bglPolygonOffset(1.0f, 1.0f); - } - } - - GPU_program_point_size(true); - - /* draw stroke verts */ - LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { - /* check if stroke can be drawn */ - if (annotation_can_draw_stroke(gps, dflag) == false) { - continue; - } - - /* Optimization: only draw points for selected strokes - * We assume that selected points can only occur in - * strokes that are selected too. - */ - if ((gps->flag & GP_STROKE_SELECT) == 0) { - continue; - } - - /* Get size of verts: - * - The selected state needs to be larger than the unselected state so that - * they stand out more. - * - We use the theme setting for size of the unselected verts - */ - float bsize = UI_GetThemeValuef(TH_GP_VERTEX_SIZE); - float vsize; - if ((int)bsize > 8) { - vsize = 10.0f; - bsize = 8.0f; - } - else { - vsize = bsize + 2; - } - - /* Why? */ - UNUSED_VARS(vsize); - - float selectColor[4]; - UI_GetThemeColor3fv(TH_GP_VERTEX_SELECT, selectColor); - selectColor[3] = alpha; - - GPUVertFormat *format = immVertexFormat(); - uint pos; /* specified later */ - uint size = GPU_vertformat_attr_add(format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); - uint color = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); - - if (gps->flag & GP_STROKE_3DSPACE) { - pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_3D_POINT_VARYING_SIZE_VARYING_COLOR); - } - else { - pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_2D_POINT_VARYING_SIZE_VARYING_COLOR); - } - - immBegin(GPU_PRIM_POINTS, gps->totpoints); - - /* Draw all the stroke points (selected or not) */ - bGPDspoint *pt = gps->points; - for (int i = 0; i < gps->totpoints; i++, pt++) { - /* size and color first */ - immAttr3fv(color, gpl->color); - immAttr1f(size, bsize); - - /* then position */ - if (gps->flag & GP_STROKE_3DSPACE) { - immVertex3fv(pos, &pt->x); - } - else { - float co[2]; - annotation_calc_2d_stroke_fxy(&pt->x, gps->flag, offsx, offsy, winx, winy, co); - immVertex2fv(pos, co); - } - } - - immEnd(); - immUnbindProgram(); - } - - GPU_program_point_size(false); - - /* clear depth mask */ - if (dflag & GP_DRAWDATA_ONLY3D) { - if (no_xray) { - glDepthMask(mask_orig); - GPU_depth_test(false); - - bglPolygonOffset(0.0, 0.0); -#if 0 - glDisable(GL_POLYGON_OFFSET_LINE); - glPolygonOffset(0, 0); -#endif - } - } -} - /* ----- General Drawing ------ */ /* draw onion-skinning for a layer */ static void annotation_draw_onionskins( @@ -724,7 +659,7 @@ static void annotation_draw_onionskins( /* loop over gpencil data layers, drawing them */ static void annotation_draw_data_layers( - bGPdata *gpd, int offsx, int offsy, int winx, int winy, int cfra, int dflag, float alpha) + bGPdata *gpd, int offsx, int offsy, int winx, int winy, int cfra, int dflag) { float ink[4]; @@ -767,21 +702,6 @@ static void annotation_draw_data_layers( /* draw the strokes already in active frame */ annotation_draw_strokes(gpf, offsx, offsy, winx, winy, dflag, lthick, ink); - /* Draw verts of selected strokes: - * - when doing OpenGL renders, we don't want to be showing these, as that ends up - * flickering - * - locked layers can't be edited, so there's no point showing these verts - * as they will have no bearings on what gets edited - * - only show when in editmode, since operators shouldn't work otherwise - * (NOTE: doing it this way means that the toggling editmode - * shows visible change immediately). - */ - /* XXX: perhaps we don't want to show these when users are drawing... */ - if ((G.f & G_FLAG_RENDER_VIEWPORT) == 0 && (gpl->flag & GP_LAYER_LOCKED) == 0 && - (gpd->flag & GP_DATA_STROKE_EDITMODE)) { - annotation_draw_strokes_edit(gpl, gpf, offsx, offsy, winx, winy, dflag, alpha); - } - /* Check if may need to draw the active stroke cache, only if this layer is the active layer * that is being edited. (Stroke buffer is currently stored in gp-data) */ @@ -793,67 +713,14 @@ static void annotation_draw_data_layers( * It should also be noted that sbuffer contains temporary point types * i.e. tGPspoints NOT bGPDspoints */ - annotation_draw_stroke_buffer(gpd->runtime.sbuffer, - gpd->runtime.sbuffer_used, - lthick, - dflag, - gpd->runtime.sbuffer_sflag, - ink); + annotation_draw_stroke_buffer(gpd, lthick, dflag, ink); } } } -/* draw a short status message in the top-right corner */ -static void annotation_draw_status_text(const bGPdata *gpd, ARegion *region) -{ - - /* Cannot draw any status text when drawing OpenGL Renders */ - if (G.f & G_FLAG_RENDER_VIEWPORT) { - return; - } - - /* Get bounds of region - Necessary to avoid problems with region overlap */ - const rcti *rect = ED_region_visible_rect(region); - - /* for now, this should only be used to indicate when we are in stroke editmode */ - if (gpd->flag & GP_DATA_STROKE_EDITMODE) { - const char *printable = IFACE_("GPencil Stroke Editing"); - float printable_size[2]; - - int font_id = BLF_default(); - - BLF_width_and_height( - font_id, printable, BLF_DRAW_STR_DUMMY_MAX, &printable_size[0], &printable_size[1]); - - int xco = (rect->xmax - U.widget_unit) - (int)printable_size[0]; - int yco = (rect->ymax - U.widget_unit); - - /* text label */ - UI_FontThemeColor(font_id, TH_TEXT_HI); -#ifdef WITH_INTERNATIONAL - BLF_draw_default(xco, yco, 0.0f, printable, BLF_DRAW_STR_DUMMY_MAX); -#else - BLF_draw_default_ascii(xco, yco, 0.0f, printable, BLF_DRAW_STR_DUMMY_MAX); -#endif - - /* grease pencil icon... */ - // XXX: is this too intrusive? - GPU_blend_set_func_separate( - GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); - GPU_blend(true); - - xco -= U.widget_unit; - yco -= (int)printable_size[1] / 2; - - UI_icon_draw(xco, yco, ICON_GREASEPENCIL); - - GPU_blend(false); - } -} - /* draw grease-pencil datablock */ static void annotation_draw_data( - bGPdata *gpd, int offsx, int offsy, int winx, int winy, int cfra, int dflag, float alpha) + bGPdata *gpd, int offsx, int offsy, int winx, int winy, int cfra, int dflag) { /* turn on smooth lines (i.e. anti-aliasing) */ GPU_line_smooth(true); @@ -864,7 +731,7 @@ static void annotation_draw_data( GPU_blend(true); /* draw! */ - annotation_draw_data_layers(gpd, offsx, offsy, winx, winy, cfra, dflag, alpha); + annotation_draw_data_layers(gpd, offsx, offsy, winx, winy, cfra, dflag); /* turn off alpha blending, then smooth lines */ GPU_blend(false); // alpha blending @@ -884,7 +751,6 @@ static void annotation_draw_data_all(Scene *scene, const char spacetype) { bGPdata *gpd_source = NULL; - float alpha = 1.0f; if (scene) { if (spacetype == SPACE_VIEW3D) { @@ -897,14 +763,14 @@ static void annotation_draw_data_all(Scene *scene, } if (gpd_source) { - annotation_draw_data(gpd_source, offsx, offsy, winx, winy, cfra, dflag, alpha); + annotation_draw_data(gpd_source, offsx, offsy, winx, winy, cfra, dflag); } } /* scene/clip data has already been drawn, only object/track data is drawn here * if gpd_source == gpd, we don't have any object/track data and we can skip */ if (gpd_source == NULL || (gpd_source && gpd_source != gpd)) { - annotation_draw_data(gpd, offsx, offsy, winx, winy, cfra, dflag, alpha); + annotation_draw_data(gpd, offsx, offsy, winx, winy, cfra, dflag); } } @@ -1026,11 +892,6 @@ void ED_annotation_draw_view2d(const bContext *C, bool onlyv2d) annotation_draw_data_all( scene, gpd, 0, 0, region->winx, region->winy, CFRA, dflag, area->spacetype); - - /* draw status text (if in screen/pixel-space) */ - if (!onlyv2d) { - annotation_draw_status_text(gpd, region); - } } /* draw annotations sketches to specified 3d-view assuming that matrices are already set diff --git a/source/blender/editors/gpencil/annotate_paint.c b/source/blender/editors/gpencil/annotate_paint.c index 8d50e24b7f0..c53b90fbfee 100644 --- a/source/blender/editors/gpencil/annotate_paint.c +++ b/source/blender/editors/gpencil/annotate_paint.c @@ -100,6 +100,9 @@ typedef enum eGPencil_PaintFlags { GP_PAINTFLAG_STROKEADDED = (1 << 1), GP_PAINTFLAG_V3D_ERASER_DEPTH = (1 << 2), GP_PAINTFLAG_SELECTMASK = (1 << 3), + /* Flags used to indicate if stabilization is being used. */ + GP_PAINTFLAG_USE_STABILIZER = (1 << 7), + GP_PAINTFLAG_USE_STABILIZER_TEMP = (1 << 8), } eGPencil_PaintFlags; /* Temporary 'Stroke' Operation data @@ -148,6 +151,11 @@ typedef struct tGPsdata { /** radius of influence for eraser. */ short radius; + /* Stabilizer. */ + float stabilizer_factor; + char stabilizer_radius; + void *stabilizer_cursor; + /** current mouse-position. */ float mval[2]; /** previous recorded mouse-position. */ @@ -278,6 +286,18 @@ static bool gp_stroke_filtermval(tGPsdata *p, const float mval[2], float pmval[2 * - aims to eliminate some jitter-noise from input when trying to draw straight lines freehand */ } + /* If lazy mouse, check minimum distance. */ + else if (p->flags & GP_PAINTFLAG_USE_STABILIZER_TEMP) { + if ((dx * dx + dy * dy) > (p->stabilizer_radius * p->stabilizer_radius)) { + return true; + } + else { + /* If the mouse is moving within the radius of the last move, + * don't update the mouse position. This allows sharp turns. */ + copy_v2_v2(p->mval, p->mvalo); + return false; + } + } else if ((dx > MIN_MANHATTEN_PX) && (dy > MIN_MANHATTEN_PX)) { return true; @@ -418,6 +438,85 @@ static void gp_smooth_buffer(tGPsdata *p, float inf, int idx) copy_v2_v2(&ptc->x, c); } +static void gp_stroke_arrow_calc_points_segment(float stroke_points[8], + const float ref_point[2], + const float dir_cw[2], + const float dir_ccw[2], + const float lenght, + const float sign) +{ + stroke_points[0] = ref_point[0] + dir_cw[0] * lenght * sign; + stroke_points[1] = ref_point[1] + dir_cw[1] * lenght * sign; + stroke_points[2] = ref_point[0] + dir_ccw[0] * lenght * sign; + stroke_points[3] = ref_point[1] + dir_ccw[1] * lenght * sign; +} + +static void gp_stroke_arrow_calc_points(tGPspoint *point, + const float stroke_dir[2], + float corner[2], + float stroke_points[8], + const int arrow_style) +{ + const int arrow_lenght = 8; + float norm_dir[2]; + copy_v2_v2(norm_dir, stroke_dir); + normalize_v2(norm_dir); + const float inv_norm_dir_clockwise[2] = {norm_dir[1], -norm_dir[0]}; + const float inv_norm_dir_counterclockwise[2] = {-norm_dir[1], norm_dir[0]}; + + switch (arrow_style) { + case GP_STROKE_ARROWSTYLE_OPEN: + mul_v2_fl(norm_dir, arrow_lenght); + stroke_points[0] = corner[0] + inv_norm_dir_clockwise[0] * arrow_lenght + norm_dir[0]; + stroke_points[1] = corner[1] + inv_norm_dir_clockwise[1] * arrow_lenght + norm_dir[1]; + stroke_points[2] = corner[0] + inv_norm_dir_counterclockwise[0] * arrow_lenght + norm_dir[0]; + stroke_points[3] = corner[1] + inv_norm_dir_counterclockwise[1] * arrow_lenght + norm_dir[1]; + break; + case GP_STROKE_ARROWSTYLE_SEGMENT: + gp_stroke_arrow_calc_points_segment(stroke_points, + corner, + inv_norm_dir_clockwise, + inv_norm_dir_counterclockwise, + arrow_lenght, + 1.0f); + break; + case GP_STROKE_ARROWSTYLE_CLOSED: + mul_v2_fl(norm_dir, arrow_lenght); + if (point != NULL) { + add_v2_v2(&point->x, norm_dir); + copy_v2_v2(corner, &point->x); + } + gp_stroke_arrow_calc_points_segment(stroke_points, + corner, + inv_norm_dir_clockwise, + inv_norm_dir_counterclockwise, + arrow_lenght, + -1.0f); + stroke_points[4] = corner[0] - norm_dir[0]; + stroke_points[5] = corner[1] - norm_dir[1]; + break; + case GP_STROKE_ARROWSTYLE_SQUARE: + mul_v2_fl(norm_dir, arrow_lenght * 1.5f); + if (point != NULL) { + add_v2_v2(&point->x, norm_dir); + copy_v2_v2(corner, &point->x); + } + gp_stroke_arrow_calc_points_segment(stroke_points, + corner, + inv_norm_dir_clockwise, + inv_norm_dir_counterclockwise, + arrow_lenght * 0.75f, + -1.0f); + stroke_points[4] = stroke_points[0] - norm_dir[0]; + stroke_points[5] = stroke_points[1] - norm_dir[1]; + stroke_points[6] = stroke_points[2] - norm_dir[0]; + stroke_points[7] = stroke_points[3] - norm_dir[1]; + break; + default: + break; + } +} + /* add current stroke-point to buffer (returns whether point was successfully added) */ static short gp_stroke_addpoint(tGPsdata *p, const float mval[2], float pressure, double curtime) { @@ -457,6 +556,32 @@ static short gp_stroke_addpoint(tGPsdata *p, const float mval[2], float pressure /* now the buffer has 2 points (and shouldn't be allowed to get any larger) */ gpd->runtime.sbuffer_used = 2; + + /* Arrows. */ + if (gpd->runtime.sbuffer_sflag & (GP_STROKE_USE_ARROW_START | GP_STROKE_USE_ARROW_END)) { + /* Store start and end point coords for arrows. */ + float end[2]; + copy_v2_v2(end, &pt->x); + pt = ((tGPspoint *)(gpd->runtime.sbuffer)); + float start[2]; + copy_v2_v2(start, &pt->x); + + /* Arrow end corner. */ + if (gpd->runtime.sbuffer_sflag & GP_STROKE_USE_ARROW_END) { + pt++; + float e_heading[2] = {start[0] - end[0], start[1] - end[1]}; + /* Calculate points for ending arrow. */ + gp_stroke_arrow_calc_points( + pt, e_heading, end, gpd->runtime.arrow_end, gpd->runtime.arrow_end_style); + } + /* Arrow start corner. */ + if (gpd->runtime.sbuffer_sflag & GP_STROKE_USE_ARROW_START) { + float s_heading[2] = {end[0] - start[0], end[1] - start[1]}; + /* Calculate points for starting arrow. */ + gp_stroke_arrow_calc_points( + NULL, s_heading, start, gpd->runtime.arrow_start, gpd->runtime.arrow_start_style); + } + } } /* can keep carrying on this way :) */ @@ -481,16 +606,20 @@ static short gp_stroke_addpoint(tGPsdata *p, const float mval[2], float pressure /* increment counters */ gpd->runtime.sbuffer_used++; - /* smooth while drawing previous points with a reduction factor for previous */ - for (int s = 0; s < 3; s++) { - gp_smooth_buffer(p, 0.5f * ((3.0f - s) / 3.0f), gpd->runtime.sbuffer_used - s); + + /* Don't smooth if stabilizer is on. */ + if ((p->flags & GP_PAINTFLAG_USE_STABILIZER_TEMP) == 0) { + /* smooth while drawing previous points with a reduction factor for previous */ + for (int s = 0; s < 3; s++) { + gp_smooth_buffer(p, 0.5f * ((3.0f - s) / 3.0f), gpd->runtime.sbuffer_used - s); + } } return GP_STROKEADD_NORMAL; } else if (p->paintmode == GP_PAINTMODE_DRAW_POLY) { /* get pointer to destination point */ - pt = (tGPspoint *)(gpd->runtime.sbuffer); + pt = (tGPspoint *)gpd->runtime.sbuffer; /* store settings */ copy_v2_v2(&pt->x, mval); @@ -552,6 +681,123 @@ static short gp_stroke_addpoint(tGPsdata *p, const float mval[2], float pressure return GP_STROKEADD_INVALID; } +static void gp_stroke_arrow_init_point_default(bGPDspoint *pt) +{ + pt->pressure = 1.0f; + pt->strength = 1.0f; + pt->time = 1.0f; +} + +static void gp_stroke_arrow_init_conv_point(bGPDspoint *pt, const float point[3]) +{ + copy_v3_v3(&pt->x, point); + gp_stroke_arrow_init_point_default(pt); +} + +static void gp_stroke_arrow_init_point( + tGPsdata *p, tGPspoint *ptc, bGPDspoint *pt, const float co[8], const int co_idx) +{ + /* Note: provided co_idx should be always pair number as it's [x1, y1, x2, y2, x3, y3]. */ + float real_co[2] = {co[co_idx], co[co_idx + 1]}; + copy_v2_v2(&ptc->x, real_co); + gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL); + gp_stroke_arrow_init_point_default(pt); +} + +static void gp_stroke_arrow_allocate(bGPDstroke *gps, const int totpoints) +{ + /* Copy appropriate settings for stroke. */ + gps->totpoints = totpoints; + /* Allocate enough memory for a continuous array for storage points. */ + gps->points = MEM_callocN(sizeof(bGPDspoint) * gps->totpoints, "gp_stroke_points"); +} + +static void gp_arrow_create_open(tGPsdata *p, + tGPspoint *ptc, + bGPDspoint *pt, + const float corner_point[3], + const float arrow_points[8]) +{ + gp_stroke_arrow_init_point(p, ptc, pt, arrow_points, 0); + pt++; + gp_stroke_arrow_init_conv_point(pt, corner_point); + pt++; + gp_stroke_arrow_init_point(p, ptc, pt, arrow_points, 2); +} + +static void gp_arrow_create_segm(tGPsdata *p, + tGPspoint *ptc, + bGPDspoint *pt, + const float arrow_points[8]) +{ + gp_stroke_arrow_init_point(p, ptc, pt, arrow_points, 0); + pt++; + gp_stroke_arrow_init_point(p, ptc, pt, arrow_points, 2); +} + +static void gp_arrow_create_closed(tGPsdata *p, + tGPspoint *ptc, + bGPDspoint *pt, + const float arrow_points[8]) +{ + gp_stroke_arrow_init_point(p, ptc, pt, arrow_points, 0); + pt++; + gp_stroke_arrow_init_point(p, ptc, pt, arrow_points, 2); + pt++; + gp_stroke_arrow_init_point(p, ptc, pt, arrow_points, 4); + pt++; + gp_stroke_arrow_init_point(p, ptc, pt, arrow_points, 0); +} + +static void gp_arrow_create_square(tGPsdata *p, + tGPspoint *ptc, + bGPDspoint *pt, + const float corner_point[3], + const float arrow_points[8]) +{ + gp_stroke_arrow_init_conv_point(pt, corner_point); + pt++; + gp_stroke_arrow_init_point(p, ptc, pt, arrow_points, 0); + pt++; + gp_stroke_arrow_init_point(p, ptc, pt, arrow_points, 4); + pt++; + gp_stroke_arrow_init_point(p, ptc, pt, arrow_points, 6); + pt++; + gp_stroke_arrow_init_point(p, ptc, pt, arrow_points, 2); + pt++; + gp_stroke_arrow_init_conv_point(pt, corner_point); +} + +static void gp_arrow_create(tGPsdata *p, + tGPspoint *ptc, + bGPDspoint *pt, + bGPDstroke *arrow_stroke, + const float arrow_points[8], + const int style) +{ + float corner_conv[3]; + copy_v3_v3(corner_conv, &pt->x); + + switch (style) { + case GP_STROKE_ARROWSTYLE_SEGMENT: + gp_arrow_create_segm(p, ptc, pt, arrow_points); + break; + case GP_STROKE_ARROWSTYLE_CLOSED: + gp_arrow_create_closed(p, ptc, pt, arrow_points); + break; + case GP_STROKE_ARROWSTYLE_OPEN: + gp_arrow_create_open(p, ptc, pt, corner_conv, arrow_points); + break; + case GP_STROKE_ARROWSTYLE_SQUARE: + gp_arrow_create_square(p, ptc, pt, corner_conv, arrow_points); + break; + default: + break; + } + /* Link stroke to frame. */ + BLI_addtail(&p->gpf->strokes, arrow_stroke); +} + /* make a new stroke from the buffer data */ static void gp_stroke_newfrombuffer(tGPsdata *p) { @@ -637,17 +883,61 @@ static void gp_stroke_newfrombuffer(tGPsdata *p) } if (totelem == 2) { - /* last point if applicable */ - ptc = ((tGPspoint *)gpd->runtime.sbuffer) + (gpd->runtime.sbuffer_used - 1); + bGPdata_Runtime runtime = gpd->runtime; - /* convert screen-coordinates to appropriate coordinates (and store them) */ + /* Last point if applicable. */ + ptc = ((tGPspoint *)runtime.sbuffer) + (runtime.sbuffer_used - 1); + + /* Convert screen-coordinates to appropriate coordinates (and store them). */ gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL); - /* copy pressure and time */ + /* Copy pressure and time. */ pt->pressure = ptc->pressure; pt->strength = ptc->strength; CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f); pt->time = ptc->time; + + /** Create arrow strokes. **/ + /* End arrow stroke. */ + if ((runtime.sbuffer_sflag & GP_STROKE_USE_ARROW_END) && + (runtime.arrow_end_style != GP_STROKE_ARROWSTYLE_NONE)) { + int totarrowpoints = runtime.arrow_end_style; + + /* Setting up arrow stroke. */ + bGPDstroke *e_arrow_gps = BKE_gpencil_stroke_duplicate(gps, false); + gp_stroke_arrow_allocate(e_arrow_gps, totarrowpoints); + + /* Set pointer to first non-initialized point. */ + pt = e_arrow_gps->points + (e_arrow_gps->totpoints - totarrowpoints); + + /* End point. */ + ptc = ((tGPspoint *)runtime.sbuffer) + (runtime.sbuffer_used - 1); + gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL); + gp_stroke_arrow_init_point_default(pt); + + /* Fill and convert arrow points to create arrow shape. */ + gp_arrow_create(p, ptc, pt, e_arrow_gps, runtime.arrow_end, runtime.arrow_end_style); + } + /* Start arrow stroke. */ + if ((runtime.sbuffer_sflag & GP_STROKE_USE_ARROW_START) && + (runtime.arrow_start_style != GP_STROKE_ARROWSTYLE_NONE)) { + int totarrowpoints = runtime.arrow_start_style; + + /* Setting up arrow stroke. */ + bGPDstroke *s_arrow_gps = BKE_gpencil_stroke_duplicate(gps, false); + gp_stroke_arrow_allocate(s_arrow_gps, totarrowpoints); + + /* Set pointer to first non-initialized point. */ + pt = s_arrow_gps->points + (s_arrow_gps->totpoints - totarrowpoints); + + /* Start point. */ + ptc = runtime.sbuffer; + gp_stroke_convertcoords(p, &ptc->x, &pt->x, NULL); + gp_stroke_arrow_init_point_default(pt); + + /* Fill and convert arrow points to create arrow shape. */ + gp_arrow_create(p, ptc, pt, s_arrow_gps, runtime.arrow_start, runtime.arrow_start_style); + } } } else if (p->paintmode == GP_PAINTMODE_DRAW_POLY) { @@ -1456,6 +1746,67 @@ static void gpencil_draw_toggle_eraser_cursor(bContext *C, tGPsdata *p, short en p); } } +static void gpencil_draw_stabilizer(bContext *C, int x, int y, void *p_ptr) +{ + ARegion *region = CTX_wm_region(C); + tGPsdata *p = (tGPsdata *)p_ptr; + bGPdata_Runtime runtime = p->gpd->runtime; + const tGPspoint *points = runtime.sbuffer; + int totpoints = runtime.sbuffer_used; + if (totpoints < 2) { + return; + } + const tGPspoint *pt = &points[totpoints - 1]; + + GPUVertFormat *format = immVertexFormat(); + uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); + GPU_line_smooth(true); + GPU_blend(true); + GPU_line_width(1.25f); + const float color[3] = {1.0f, 0.39f, 0.39f}; + + /* default radius and color */ + float darkcolor[3]; + const float radius = 4.0f; + + /* Inner Ring: Color from UI panel */ + immUniformColor4f(color[0], color[1], color[2], 0.8f); + imm_draw_circle_wire_2d(pos, x, y, radius, 40); + + /* Outer Ring: Dark color for contrast on light backgrounds (e.g. gray on white) */ + mul_v3_v3fl(darkcolor, color, 0.40f); + immUniformColor4f(darkcolor[0], darkcolor[1], darkcolor[2], 0.8f); + imm_draw_circle_wire_2d(pos, x, y, radius + 1, 40); + + /* Rope Simple. */ + immUniformColor4f(color[0], color[1], color[2], 0.8f); + immBegin(GPU_PRIM_LINES, 2); + immVertex2f(pos, pt->x + region->winrct.xmin, pt->y + region->winrct.ymin); + immVertex2f(pos, x, y); + immEnd(); + + /* Returns back all GPU settings */ + GPU_blend(false); + GPU_line_smooth(false); + + immUnbindProgram(); +} + +/* Turn *stabilizer* brush cursor in 3D view on/off */ +static void gpencil_draw_toggle_stabilizer_cursor(bContext *C, tGPsdata *p, short enable) +{ + if (p->stabilizer_cursor && !enable) { + /* clear cursor */ + WM_paint_cursor_end(CTX_wm_manager(C), p->stabilizer_cursor); + p->stabilizer_cursor = NULL; + } + else if (enable && !p->stabilizer_cursor) { + /* enable cursor */ + p->stabilizer_cursor = WM_paint_cursor_activate( + CTX_wm_manager(C), SPACE_TYPE_ANY, RGN_TYPE_ANY, NULL, gpencil_draw_stabilizer, p); + } +} /* Check if tablet eraser is being used (when processing events) */ static bool gpencil_is_tablet_eraser_active(const wmEvent *event) @@ -1479,6 +1830,9 @@ static void gpencil_draw_exit(bContext *C, wmOperator *op) /* turn off radial brush cursor */ gpencil_draw_toggle_eraser_cursor(C, p, false); } + else if (p->paintmode == GP_PAINTMODE_DRAW) { + gpencil_draw_toggle_stabilizer_cursor(C, p, false); + } /* always store the new eraser size to be used again next time * NOTE: Do this even when not in eraser mode, as eraser may @@ -1566,8 +1920,8 @@ static void gpencil_draw_status_indicators(bContext *C, tGPsdata *p) "ESC/Enter to end (or click outside this area)")); break; default: - /* Do nothing - the others are self explanatory, exit quickly once the mouse is released - * Showing any text would just be annoying as it would flicker. + /* Do nothing - the others are self explanatory, exit quickly once the mouse is + * released Showing any text would just be annoying as it would flicker. */ break; } @@ -1632,6 +1986,16 @@ static void gpencil_draw_apply(wmOperator *op, tGPsdata *p, Depsgraph *depsgraph /* Only add current point to buffer if mouse moved * (even though we got an event, it might be just noise). */ else if (gp_stroke_filtermval(p, p->mval, p->mvalo)) { + /* If lazy mouse, interpolate the last and current mouse positions. */ + if (p->flags & GP_PAINTFLAG_USE_STABILIZER_TEMP) { + float now_mouse[2]; + float last_mouse[2]; + copy_v2_v2(now_mouse, p->mval); + copy_v2_v2(last_mouse, p->mvalo); + interp_v2_v2v2(now_mouse, now_mouse, last_mouse, min_ff(p->stabilizer_factor, .995f)); + copy_v2_v2(p->mval, now_mouse); + } + /* try to add point */ short ok = gp_stroke_addpoint(p, p->mval, p->pressure, p->curtime); @@ -1675,7 +2039,7 @@ static void gpencil_draw_apply(wmOperator *op, tGPsdata *p, Depsgraph *depsgraph /* handle draw event */ static void annotation_draw_apply_event( - wmOperator *op, const wmEvent *event, Depsgraph *depsgraph, float x, float y) + bContext *C, wmOperator *op, const wmEvent *event, Depsgraph *depsgraph, float x, float y) { tGPsdata *p = op->customdata; PointerRNA itemptr; @@ -1687,8 +2051,23 @@ static void annotation_draw_apply_event( p->mval[0] = (float)event->mval[0] - x; p->mval[1] = (float)event->mval[1] - y; + /* Key to toggle stabilization. */ + if (event->shift > 0 && p->paintmode == GP_PAINTMODE_DRAW) { + /* Using permanent stabilization, shift will deactivate the flag. */ + if (p->flags & (GP_PAINTFLAG_USE_STABILIZER)) { + if (p->flags & GP_PAINTFLAG_USE_STABILIZER_TEMP) { + gpencil_draw_toggle_stabilizer_cursor(C, p, false); + p->flags &= ~GP_PAINTFLAG_USE_STABILIZER_TEMP; + } + } + /* Not using any stabilization flag. Activate temporal one. */ + else if ((p->flags & GP_PAINTFLAG_USE_STABILIZER_TEMP) == 0) { + p->flags |= GP_PAINTFLAG_USE_STABILIZER_TEMP; + gpencil_draw_toggle_stabilizer_cursor(C, p, true); + } + } /* verify key status for straight lines */ - if ((event->ctrl > 0) || (event->alt > 0)) { + else if ((event->ctrl > 0) || (event->alt > 0)) { if (p->straight[0] == 0) { int dx = abs((int)(p->mval[0] - p->mvalo[0])); int dy = abs((int)(p->mval[1] - p->mvalo[1])); @@ -1709,6 +2088,22 @@ static void annotation_draw_apply_event( } else { p->straight[0] = 0; + /* We were using shift while having permanent stabilization actived, + so activate the temp flag back again. */ + if (p->flags & GP_PAINTFLAG_USE_STABILIZER) { + if ((p->flags & GP_PAINTFLAG_USE_STABILIZER_TEMP) == 0) { + gpencil_draw_toggle_stabilizer_cursor(C, p, true); + p->flags |= GP_PAINTFLAG_USE_STABILIZER_TEMP; + } + } + /* We are using the temporal stabilizer flag atm, + but shift is not pressed as well as the permanent flag is not used, + so we don't need the cursor anymore. */ + else if (p->flags & GP_PAINTFLAG_USE_STABILIZER_TEMP) { + /* Reset temporal stabilizer flag and remove cursor. */ + p->flags &= ~GP_PAINTFLAG_USE_STABILIZER_TEMP; + gpencil_draw_toggle_stabilizer_cursor(C, p, false); + } } p->curtime = PIL_check_seconds_timer(); @@ -1896,12 +2291,35 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event /* TODO: set any additional settings that we can take from the events? * TODO? if tablet is erasing, force eraser to be on? */ - /* TODO: move cursor setting stuff to stroke-start so that paintmode can be changed midway... */ + /* TODO: move cursor setting stuff to stroke-start so that paintmode can be changed midway... + */ /* if eraser is on, draw radial aid */ if (p->paintmode == GP_PAINTMODE_ERASER) { gpencil_draw_toggle_eraser_cursor(C, p, true); } + else if (p->paintmode == GP_PAINTMODE_DRAW_STRAIGHT) { + if (RNA_enum_get(op->ptr, "arrowstyle_start") != GP_STROKE_ARROWSTYLE_NONE) { + p->gpd->runtime.sbuffer_sflag |= GP_STROKE_USE_ARROW_START; + p->gpd->runtime.arrow_start_style = RNA_enum_get(op->ptr, "arrowstyle_start"); + } + if (RNA_enum_get(op->ptr, "arrowstyle_end") != GP_STROKE_ARROWSTYLE_NONE) { + p->gpd->runtime.sbuffer_sflag |= GP_STROKE_USE_ARROW_END; + p->gpd->runtime.arrow_end_style = RNA_enum_get(op->ptr, "arrowstyle_end"); + } + } + else if (p->paintmode == GP_PAINTMODE_DRAW) { + p->stabilizer_factor = RNA_float_get(op->ptr, "stabilizer_factor"); + p->stabilizer_radius = RNA_int_get(op->ptr, "stabilizer_radius"); + if (RNA_boolean_get(op->ptr, "use_stabilizer")) { + p->flags |= GP_PAINTFLAG_USE_STABILIZER | GP_PAINTFLAG_USE_STABILIZER_TEMP; + gpencil_draw_toggle_stabilizer_cursor(C, p, true); + } + else if (event->shift > 0) { + p->flags |= GP_PAINTFLAG_USE_STABILIZER_TEMP; + gpencil_draw_toggle_stabilizer_cursor(C, p, true); + } + } /* set cursor * NOTE: This may change later (i.e. intentionally via brush toggle, * or unintentionally if the user scrolls outside the area)... @@ -1915,7 +2333,7 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event p->status = GP_STATUS_PAINTING; /* handle the initial drawing - i.e. for just doing a simple dot */ - annotation_draw_apply_event(op, event, CTX_data_ensure_evaluated_depsgraph(C), 0.0f, 0.0f); + annotation_draw_apply_event(C, op, event, CTX_data_ensure_evaluated_depsgraph(C), 0.0f, 0.0f); op->flag |= OP_IS_MODAL_CURSOR_REGION; } else { @@ -2007,7 +2425,7 @@ static void annotation_add_missing_events(bContext *C, interp_v2_v2v2(pt, a, b, 0.5f); sub_v2_v2v2(pt, b, pt); /* create fake event */ - annotation_draw_apply_event(op, event, depsgraph, pt[0], pt[1]); + annotation_draw_apply_event(C, op, event, depsgraph, pt[0], pt[1]); } else if (dist >= factor) { int slices = 2 + (int)((dist - 1.0) / factor); @@ -2016,7 +2434,7 @@ static void annotation_add_missing_events(bContext *C, interp_v2_v2v2(pt, a, b, n * i); sub_v2_v2v2(pt, b, pt); /* create fake event */ - annotation_draw_apply_event(op, event, depsgraph, pt[0], pt[1]); + annotation_draw_apply_event(C, op, event, depsgraph, pt[0], pt[1]); } } } @@ -2106,7 +2524,8 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) } /* toggle painting mode upon mouse-button movement - * - LEFTMOUSE = standard drawing (all) / straight line drawing (all) / polyline (toolbox only) + * - LEFTMOUSE = standard drawing (all) / straight line drawing (all) / polyline (toolbox + * only) * - RIGHTMOUSE = polyline (hotkey) / eraser (all) * (Disabling RIGHTMOUSE case here results in bugs like [#32647]) * also making sure we have a valid event value, to not exit too early @@ -2262,7 +2681,8 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) } /* TODO(sergey): Possibly evaluating dependency graph from modal operator? */ - annotation_draw_apply_event(op, event, CTX_data_ensure_evaluated_depsgraph(C), 0.0f, 0.0f); + annotation_draw_apply_event( + C, op, event, CTX_data_ensure_evaluated_depsgraph(C), 0.0f, 0.0f); /* finish painting operation if anything went wrong just now */ if (p->status == GP_STATUS_ERROR) { @@ -2370,6 +2790,19 @@ static const EnumPropertyItem prop_gpencil_drawmodes[] = { {0, NULL, 0, NULL, NULL}, }; +static const EnumPropertyItem arrow_types[] = { + {GP_STROKE_ARROWSTYLE_NONE, "NONE", 0, "None", "Don't use any arrow/style in corner"}, + {GP_STROKE_ARROWSTYLE_CLOSED, "ARROW", 0, "Arrow", "Use closed arrow style"}, + {GP_STROKE_ARROWSTYLE_OPEN, "ARROW_OPEN", 0, "Open Arrow", "Use open arrow style"}, + {GP_STROKE_ARROWSTYLE_SEGMENT, + "ARROW_OPEN_INVERTED", + 0, + "Segment", + "Use perpendicular segment style"}, + {GP_STROKE_ARROWSTYLE_SQUARE, "DIAMOND", 0, "Square", "Use square style"}, + {0, NULL, 0, NULL, NULL}, +}; + void GPENCIL_OT_annotate(wmOperatorType *ot) { PropertyRNA *prop; @@ -2393,6 +2826,37 @@ void GPENCIL_OT_annotate(wmOperatorType *ot) ot->prop = RNA_def_enum( ot->srna, "mode", prop_gpencil_drawmodes, 0, "Mode", "Way to interpret mouse movements"); + /* properties */ + prop = RNA_def_enum( + ot->srna, "arrowstyle_start", arrow_types, 0, "Start Arrow Style", "Stroke start style"); + prop = RNA_def_enum( + ot->srna, "arrowstyle_end", arrow_types, 0, "End Arrow Style", "Stroke end style"); + prop = RNA_def_boolean(ot->srna, + "use_stabilizer", + false, + "Stabilize Stroke", + "Helper to draw smooth and clean lines. Press Shift for an invert effect " + "(even if this option is not active)"); + prop = RNA_def_float(ot->srna, + "stabilizer_factor", + 0.75f, + 0.0f, + 1.0f, + "Stabilizer Stroke Factor", + "Higher values gives a smoother stroke", + 0.0f, + 1.0f); + prop = RNA_def_int(ot->srna, + "stabilizer_radius", + 35, + 0, + 200, + "Stabilizer Stroke Radius", + "Minimun distance from last point before stroke continues", + 1, + 100); + RNA_def_property_subtype(prop, PROP_PIXEL); + prop = RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", ""); RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); diff --git a/source/blender/editors/gpencil/gpencil_armature.c b/source/blender/editors/gpencil/gpencil_armature.c index ab8b1a9719b..962a74d9e6f 100644 --- a/source/blender/editors/gpencil/gpencil_armature.c +++ b/source/blender/editors/gpencil/gpencil_armature.c @@ -491,7 +491,7 @@ bool ED_gpencil_add_armature(const bContext *C, ReportList *reports, Object *ob, } /* if no armature modifier, add a new one */ - GpencilModifierData *md = BKE_gpencil_modifiers_findByType(ob, eGpencilModifierType_Armature); + GpencilModifierData *md = BKE_gpencil_modifiers_findby_type(ob, eGpencilModifierType_Armature); if (md == NULL) { md = ED_object_gpencil_modifier_add( reports, bmain, scene, ob, "Armature", eGpencilModifierType_Armature); @@ -590,8 +590,8 @@ static int gpencil_generate_weights_exec(bContext *C, wmOperator *op) } else { /* get armature from modifier */ - GpencilModifierData *md = BKE_gpencil_modifiers_findByType(ob_eval, - eGpencilModifierType_Armature); + GpencilModifierData *md = BKE_gpencil_modifiers_findby_type(ob_eval, + eGpencilModifierType_Armature); if (md == NULL) { BKE_report(op->reports, RPT_ERROR, "The grease pencil object need an Armature modifier"); return OPERATOR_CANCELLED; diff --git a/source/blender/editors/gpencil/gpencil_convert.c b/source/blender/editors/gpencil/gpencil_convert.c index e89903adf5f..5441d4e24a6 100644 --- a/source/blender/editors/gpencil/gpencil_convert.c +++ b/source/blender/editors/gpencil/gpencil_convert.c @@ -162,7 +162,7 @@ static void gp_strokepoint_convertcoords(bContext *C, View3D *v3d = CTX_wm_view3d(C); ARegion *region = CTX_wm_region(C); /* TODO(sergey): This function might be called from a loop, but no tagging is happening in it, - * so it's not that expensive to ensure evaluated depsgraph here. However, ideally all the + * so it's not that expensive to ensure evaluated depsgraph here. However, ideally all the * parameters are to wrapped into a context style struct and queried from Context once.*/ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); Object *obact = CTX_data_active_object(C); diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c index c7b46858df9..8c80334bf8a 100644 --- a/source/blender/editors/gpencil/gpencil_data.c +++ b/source/blender/editors/gpencil/gpencil_data.c @@ -55,7 +55,7 @@ #include "BKE_brush.h" #include "BKE_context.h" #include "BKE_deform.h" -#include "BKE_fcurve.h" +#include "BKE_fcurve_driver.h" #include "BKE_gpencil.h" #include "BKE_gpencil_modifier.h" #include "BKE_lib_id.h" @@ -2619,7 +2619,7 @@ int ED_gpencil_join_objects_exec(bContext *C, wmOperator *op) /* Apply all GP modifiers before */ LISTBASE_FOREACH (GpencilModifierData *, md, &ob_iter->greasepencil_modifiers) { - const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type); + const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type); if (mti->bakeModifier) { mti->bakeModifier(bmain, depsgraph, md, ob_iter); } @@ -3193,7 +3193,7 @@ void GPENCIL_OT_material_unlock_all(wmOperatorType *ot) /* ***************** Select all strokes using color ************************ */ -static int gpencil_select_material_exec(bContext *C, wmOperator *op) +static int gpencil_material_select_exec(bContext *C, wmOperator *op) { bGPdata *gpd = ED_gpencil_data_get_active(C); Object *ob = CTX_data_active_object(C); @@ -3263,15 +3263,15 @@ static int gpencil_select_material_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -void GPENCIL_OT_select_material(wmOperatorType *ot) +void GPENCIL_OT_material_select(wmOperatorType *ot) { /* identifiers */ ot->name = "Select Material"; - ot->idname = "GPENCIL_OT_select_material"; + ot->idname = "GPENCIL_OT_material_select"; ot->description = "Select/Deselect all Grease Pencil strokes using current material"; /* callbacks */ - ot->exec = gpencil_select_material_exec; + ot->exec = gpencil_material_select_exec; ot->poll = gpencil_active_material_poll; /* flags */ @@ -3282,6 +3282,48 @@ void GPENCIL_OT_select_material(wmOperatorType *ot) RNA_def_property_flag(ot->prop, PROP_HIDDEN | PROP_SKIP_SAVE); } +/* ***************** Set active material ************************* */ +static int gpencil_material_set_exec(bContext *C, wmOperator *op) +{ + Object *ob = CTX_data_active_object(C); + int slot = RNA_enum_get(op->ptr, "slot"); + + /* Try to get material */ + if ((slot < 1) || (slot > ob->totcol)) { + BKE_reportf( + op->reports, RPT_ERROR, "Cannot change to non-existent material (index = %d)", slot); + return OPERATOR_CANCELLED; + } + + /* Set active material. */ + ob->actcol = slot; + + /* updates */ + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_SELECTED, NULL); + + return OPERATOR_FINISHED; +} + +void GPENCIL_OT_material_set(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Set Material"; + ot->idname = "GPENCIL_OT_material_set"; + ot->description = "Set active material"; + + /* callbacks */ + ot->exec = gpencil_material_set_exec; + ot->poll = gpencil_active_material_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* Material to use (dynamic enum) */ + ot->prop = RNA_def_enum(ot->srna, "slot", DummyRNA_DEFAULT_items, 0, "Material Slot", ""); + RNA_def_enum_funcs(ot->prop, ED_gpencil_material_enum_itemf); +} + /* ***************** Set selected stroke material the active material ************************ */ static int gpencil_set_active_material_exec(bContext *C, wmOperator *op) @@ -3344,7 +3386,7 @@ bool ED_gpencil_add_lattice_modifier(const bContext *C, } /* if no lattice modifier, add a new one */ - GpencilModifierData *md = BKE_gpencil_modifiers_findByType(ob, eGpencilModifierType_Lattice); + GpencilModifierData *md = BKE_gpencil_modifiers_findby_type(ob, eGpencilModifierType_Lattice); if (md == NULL) { md = ED_object_gpencil_modifier_add( reports, bmain, scene, ob, "Lattice", eGpencilModifierType_Lattice); diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index 99700a870b9..151f4a930d0 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -90,8 +90,9 @@ #include "gpencil_intern.h" -/* ************************************************ */ -/* Stroke Edit Mode Management */ +/* -------------------------------------------------------------------- */ +/** \name Stroke Edit Mode Management + * \{ */ /* poll callback for all stroke editing operators */ static bool gp_stroke_edit_poll(bContext *C) @@ -138,6 +139,12 @@ static bool gpencil_editmode_toggle_poll(bContext *C) return ED_gpencil_data_get_active(C) != NULL; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Toggle Edit Mode Operator + * \{ */ + static int gpencil_editmode_toggle_exec(bContext *C, wmOperator *op) { const int back = RNA_boolean_get(op->ptr, "back"); @@ -223,6 +230,12 @@ void GPENCIL_OT_editmode_toggle(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Toggle Select Mode Operator + * \{ */ + /* set select mode */ static bool gpencil_selectmode_toggle_poll(bContext *C) { @@ -298,7 +311,11 @@ void GPENCIL_OT_selectmode_toggle(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); } -/* Stroke Paint Mode Management */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Toggle Stroke Paint Mode Operator + * \{ */ static bool gpencil_paintmode_toggle_poll(bContext *C) { @@ -410,7 +427,11 @@ void GPENCIL_OT_paintmode_toggle(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); } -/* Stroke Sculpt Mode Management */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Toggle Stroke Sculpt Mode Operator + * \{ */ static bool gpencil_sculptmode_toggle_poll(bContext *C) { @@ -489,6 +510,12 @@ static int gpencil_sculptmode_toggle_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Toggle Weight Paint Mode Operator + * \{ */ + void GPENCIL_OT_sculptmode_toggle(wmOperatorType *ot) { PropertyRNA *prop; @@ -612,7 +639,11 @@ void GPENCIL_OT_weightmode_toggle(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); } -/* Vertex Paint Mode Management */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Toggle Vertex Paint Mode Operator + * \{ */ static bool gpencil_vertexmode_toggle_poll(bContext *C) { @@ -715,10 +746,11 @@ void GPENCIL_OT_vertexmode_toggle(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); } -/* ************************************************ */ -/* Stroke Editing Operators */ +/** \} */ -/* ************ Stroke Hide selection Toggle ************** */ +/* -------------------------------------------------------------------- */ +/** \name Stroke Hide Selection Toggle Operator + * \{ */ static int gpencil_hideselect_toggle_exec(bContext *C, wmOperator *UNUSED(op)) { @@ -757,7 +789,11 @@ void GPENCIL_OT_selection_opacity_toggle(wmOperatorType *ot) ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER; } -/* ************** Duplicate Selected Strokes **************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Duplicate Selected Strokes Operator + * \{ */ /* Make copies of selected point segments in a selected stroke */ static void gp_duplicate_points(const bGPDstroke *gps, @@ -934,7 +970,11 @@ void GPENCIL_OT_duplicate(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* ************** Extrude Selected Strokes **************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Extrude Selected Strokes Operator + * \{ */ /* helper to copy a point to temp area */ static void copy_move_point(bGPDstroke *gps, @@ -1155,14 +1195,18 @@ void GPENCIL_OT_extrude(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* ******************* Copy/Paste Strokes ************************* */ -/* Grease Pencil stroke data copy/paste buffer: +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Copy/Paste Strokes Utilities + * + * Grease Pencil stroke data copy/paste buffer: * - The copy operation collects all segments of selected strokes, * dumping "ready to be copied" copies of the strokes into the buffer. * - The paste operation makes a copy of those elements, and adds them * to the active layer. This effectively flattens down the strokes * from several different layers into a single layer. - */ + * \{ */ /* list of bGPDstroke instances */ /* NOTE: is exposed within the editors/gpencil module so that other tools can use it too */ @@ -1274,8 +1318,11 @@ GHash *gp_copybuf_validate_colormap(bContext *C) return new_colors; } -/* --------------------- */ -/* Copy selected strokes */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Copy Selected Strokes Operator + * \{ */ static int gp_strokes_copy_exec(bContext *C, wmOperator *op) { @@ -1392,8 +1439,11 @@ void GPENCIL_OT_copy(wmOperatorType *ot) // ot->flag = OPTYPE_REGISTER; } -/* --------------------- */ -/* Paste selected strokes */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Paste Selected Strokes Operator + * \{ */ static bool gp_strokes_paste_poll(bContext *C) { @@ -1564,7 +1614,11 @@ void GPENCIL_OT_paste(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_SKIP_SAVE); } -/* ******************* Move To Layer ****************************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Move To Layer Operator + * \{ */ static int gp_move_to_layer_exec(bContext *C, wmOperator *op) { @@ -1684,7 +1738,11 @@ void GPENCIL_OT_move_to_layer(wmOperatorType *ot) RNA_def_property_flag(ot->prop, PROP_HIDDEN | PROP_SKIP_SAVE); } -/* ********************* Add Blank Frame *************************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Add Blank Frame Operator + * \{ */ static int gp_blank_frame_add_exec(bContext *C, wmOperator *op) { @@ -1758,7 +1816,11 @@ void GPENCIL_OT_blank_frame_add(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_SKIP_SAVE); } -/* ******************* Delete Active Frame ************************ */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Delete Active Frame Operator + * \{ */ static bool gp_actframe_delete_poll(bContext *C) { @@ -1839,7 +1901,12 @@ void GPENCIL_OT_annotation_active_frame_delete(wmOperatorType *ot) ot->exec = gp_actframe_delete_exec; ot->poll = gp_annotation_actframe_delete_poll; } -/* **************** Delete All Active Frames ****************** */ + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Delete All Active Frames + * \{ */ static bool gp_actframe_delete_all_poll(bContext *C) { @@ -1900,7 +1967,11 @@ void GPENCIL_OT_active_frames_delete_all(wmOperatorType *ot) ot->poll = gp_actframe_delete_all_poll; } -/* ******************* Delete Operator ************************ */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Delete/Dissolve Utilities + * \{ */ typedef enum eGP_DeleteMode { /* delete selected stroke points */ @@ -1920,8 +1991,6 @@ typedef enum eGP_DissolveMode { GP_DISSOLVE_UNSELECT = 2, } eGP_DissolveMode; -/* ----------------------------------- */ - /* Delete selected strokes */ static int gp_delete_selected_strokes(bContext *C) { @@ -2515,7 +2584,11 @@ int gp_delete_selected_point_wrap(bContext *C) return gp_delete_selected_points(C); } -/* ----------------------------------- */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Delete Operator + * \{ */ static int gp_delete_exec(bContext *C, wmOperator *op) { @@ -2574,6 +2647,12 @@ void GPENCIL_OT_delete(wmOperatorType *ot) "Method used for deleting Grease Pencil data"); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Dissolve Operator + * \{ */ + static int gp_dissolve_exec(bContext *C, wmOperator *op) { eGP_DissolveMode mode = RNA_enum_get(op->ptr, "type"); @@ -2616,7 +2695,11 @@ void GPENCIL_OT_dissolve(wmOperatorType *ot) "Method used for dissolving Stroke points"); } -/* ****************** Snapping - Strokes <-> Cursor ************************ */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Snapping Selection to Grid Operator + * \{ */ /* Poll callback for snap operators */ /* NOTE: For now, we only allow these in the 3D view, as other editors do not @@ -2631,8 +2714,6 @@ static bool gp_snap_poll(bContext *C) ((area != NULL) && (area->spacetype == SPACE_VIEW3D)); } -/* --------------------------------- */ - static int gp_snap_to_grid(bContext *C, wmOperator *UNUSED(op)) { bGPdata *gpd = ED_gpencil_data_get_active(C); @@ -2707,7 +2788,11 @@ void GPENCIL_OT_snap_to_grid(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* ------------------------------- */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Snapping Selection to Cursor Operator + * \{ */ static int gp_snap_to_cursor(bContext *C, wmOperator *op) { @@ -2799,7 +2884,11 @@ void GPENCIL_OT_snap_to_cursor(wmOperatorType *ot) "Offset the entire stroke instead of selected points only"); } -/* ------------------------------- */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Snapping Cursor to Selection Operator + * \{ */ static int gp_snap_cursor_to_sel(bContext *C, wmOperator *UNUSED(op)) { @@ -2890,7 +2979,11 @@ void GPENCIL_OT_snap_cursor_to_selected(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* ******************* Apply layer thickness change to strokes ************************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Apply Layer Thickness Change to Strokes Operator + * \{ */ static int gp_stroke_apply_thickness_exec(bContext *C, wmOperator *UNUSED(op)) { @@ -2937,7 +3030,11 @@ void GPENCIL_OT_stroke_apply_thickness(wmOperatorType *ot) ot->poll = gp_active_layer_poll; } -/* ******************* Close Strokes ************************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Stroke Toggle Cyclic Operator + * \{ */ enum { GP_STROKE_CYCLIC_CLOSE = 1, @@ -3057,7 +3154,11 @@ void GPENCIL_OT_stroke_cyclical_set(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_SKIP_SAVE); } -/* ******************* Flat Stroke Caps ************************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Stroke Toggle Flat Caps Operator + * \{ */ enum { GP_STROKE_CAPS_TOGGLE_BOTH = 0, @@ -3153,7 +3254,11 @@ void GPENCIL_OT_stroke_caps_set(wmOperatorType *ot) ot->prop = RNA_def_enum(ot->srna, "type", toggle_type, GP_STROKE_CAPS_TOGGLE_BOTH, "Type", ""); } -/* ******************* Stroke join ************************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Stroke Join Operator + * \{ */ /* Helper: flip stroke */ static void gpencil_flip_stroke(bGPDstroke *gps) @@ -3203,8 +3308,8 @@ static void gpencil_flip_stroke(bGPDstroke *gps) /* Helper: copy point between strokes */ static void gpencil_stroke_copy_point(bGPDstroke *gps, + MDeformVert *dvert, bGPDspoint *point, - int idx, const float delta[3], float pressure, float strength, @@ -3216,6 +3321,13 @@ static void gpencil_stroke_copy_point(bGPDstroke *gps, if (gps->dvert != NULL) { gps->dvert = MEM_reallocN(gps->dvert, sizeof(MDeformVert) * (gps->totpoints + 1)); } + else { + /* If destination has weight add weight to origin. */ + if (dvert != NULL) { + gps->dvert = MEM_callocN(sizeof(MDeformVert) * (gps->totpoints + 1), __func__); + } + } + gps->totpoints++; newpoint = &gps->points[gps->totpoints - 1]; @@ -3229,11 +3341,16 @@ static void gpencil_stroke_copy_point(bGPDstroke *gps, copy_v4_v4(newpoint->vert_color, point->vert_color); if (gps->dvert != NULL) { - MDeformVert *dvert = &gps->dvert[idx]; MDeformVert *newdvert = &gps->dvert[gps->totpoints - 1]; - newdvert->totweight = dvert->totweight; - newdvert->dw = MEM_dupallocN(dvert->dw); + if (dvert != NULL) { + newdvert->totweight = dvert->totweight; + newdvert->dw = MEM_dupallocN(dvert->dw); + } + else { + newdvert->totweight = 0; + newdvert->dw = NULL; + } } } @@ -3284,16 +3401,18 @@ static void gpencil_stroke_join_strokes(bGPDstroke *gps_a, /* 1st: add one tail point to start invisible area */ point = gps_a->points[gps_a->totpoints - 1]; deltatime = point.time; - gpencil_stroke_copy_point(gps_a, &point, gps_a->totpoints - 1, delta, 0.0f, 0.0f, 0.0f); + + gpencil_stroke_copy_point(gps_a, NULL, &point, delta, 0.0f, 0.0f, 0.0f); /* 2nd: add one head point to finish invisible area */ point = gps_b->points[0]; - gpencil_stroke_copy_point(gps_a, &point, 0, delta, 0.0f, 0.0f, deltatime); + gpencil_stroke_copy_point(gps_a, NULL, &point, delta, 0.0f, 0.0f, deltatime); } /* 3rd: add all points */ for (i = 0, pt = gps_b->points; i < gps_b->totpoints && pt; i++, pt++) { - gpencil_stroke_copy_point(gps_a, pt, i, delta, pt->pressure, pt->strength, deltatime); + MDeformVert *dvert = (gps_b->dvert) ? &gps_b->dvert[i] : NULL; + gpencil_stroke_copy_point(gps_a, dvert, pt, delta, pt->pressure, pt->strength, deltatime); } } @@ -3439,7 +3558,11 @@ void GPENCIL_OT_stroke_join(wmOperatorType *ot) "Leave gaps between joined strokes instead of linking them"); } -/* ******************* Stroke flip ************************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Stroke Flip Operator + * \{ */ static int gp_stroke_flip_exec(bContext *C, wmOperator *UNUSED(op)) { @@ -3498,7 +3621,11 @@ void GPENCIL_OT_stroke_flip(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* ***************** Reproject Strokes ********************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Stroke Re-project Operator + * \{ */ typedef enum eGP_ReprojectModes { /* Axis */ @@ -3736,7 +3863,6 @@ static int gp_recalc_geometry_exec(bContext *C, wmOperator *UNUSED(op)) void GPENCIL_OT_recalc_geometry(wmOperatorType *ot) { - /* identifiers */ ot->name = "Recalculate internal geometry"; ot->idname = "GPENCIL_OT_recalc_geometry"; @@ -3750,7 +3876,12 @@ void GPENCIL_OT_recalc_geometry(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* ******************* Stroke subdivide ************************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Stroke Subdivide Operator + * \{ */ + /* helper to smooth */ static void gp_smooth_stroke(bContext *C, wmOperator *op) { @@ -4131,7 +4262,12 @@ void GPENCIL_OT_stroke_sample(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_SKIP_SAVE); } -/* ******************* Stroke trim ************************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Stroke Trim Operator + * \{ */ + static int gp_stroke_trim_exec(bContext *C, wmOperator *UNUSED(op)) { bGPdata *gpd = ED_gpencil_data_get_active(C); @@ -4196,7 +4332,12 @@ void GPENCIL_OT_stroke_trim(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* ***************** Separate Strokes ********************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Stroke Separate Operator + * \{ */ + typedef enum eGP_SeparateModes { /* Points */ GP_SEPARATE_POINT = 0, @@ -4414,7 +4555,12 @@ void GPENCIL_OT_stroke_separate(wmOperatorType *ot) ot->prop = RNA_def_enum(ot->srna, "mode", separate_type, GP_SEPARATE_POINT, "Mode", ""); } -/* ***************** Split Strokes ********************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Stroke Split Operator + * \{ */ + static int gp_stroke_split_exec(bContext *C, wmOperator *UNUSED(op)) { Object *ob = CTX_data_active_object(C); @@ -4511,6 +4657,12 @@ void GPENCIL_OT_stroke_split(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Stroke Smooth Operator + * \{ */ + static int gp_stroke_smooth_exec(bContext *C, wmOperator *op) { bGPdata *gpd = ED_gpencil_data_get_active(C); @@ -4561,11 +4713,17 @@ void GPENCIL_OT_stroke_smooth(wmOperatorType *ot) RNA_def_boolean(ot->srna, "smooth_uv", false, "UV", ""); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Stroke Cutter Operator + * \{ */ + /* smart stroke cutter for trimming stroke ends */ struct GP_SelectLassoUserData { rcti rect; - const int (*mcords)[2]; - int mcords_len; + const int (*mcoords)[2]; + int mcoords_len; }; static bool gpencil_test_lasso(bGPDstroke *gps, @@ -4581,7 +4739,7 @@ static bool gpencil_test_lasso(bGPDstroke *gps, gp_point_to_xy(gsc, gps, &pt2, &x0, &y0); /* test if in lasso */ return ((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(&data->rect, x0, y0) && - BLI_lasso_is_point_inside(data->mcords, data->mcords_len, x0, y0, INT_MAX)); + BLI_lasso_is_point_inside(data->mcoords, data->mcoords_len, x0, y0, INT_MAX)); } typedef bool (*GPencilTestFn)(bGPDstroke *gps, @@ -4759,19 +4917,19 @@ static int gpencil_cutter_exec(bContext *C, wmOperator *op) } struct GP_SelectLassoUserData data = {0}; - data.mcords = WM_gesture_lasso_path_to_array(C, op, &data.mcords_len); + data.mcoords = WM_gesture_lasso_path_to_array(C, op, &data.mcoords_len); /* Sanity check. */ - if (data.mcords == NULL) { + if (data.mcoords == NULL) { return OPERATOR_PASS_THROUGH; } /* Compute boundbox of lasso (for faster testing later). */ - BLI_lasso_boundbox(&data.rect, data.mcords, data.mcords_len); + BLI_lasso_boundbox(&data.rect, data.mcoords, data.mcoords_len); gpencil_cutter_lasso_select(C, op, gpencil_test_lasso, &data); - MEM_freeN((void *)data.mcords); + MEM_freeN((void *)data.mcoords); return OPERATOR_FINISHED; } @@ -4817,7 +4975,12 @@ bool ED_object_gpencil_exit(struct Main *bmain, Object *ob) return ok; } -/* ** merge by distance *** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Merge By Distance Operator + * \{ */ + static bool gp_merge_by_distance_poll(bContext *C) { Object *ob = CTX_data_active_object(C); @@ -4886,3 +5049,5 @@ void GPENCIL_OT_stroke_merge_by_distance(wmOperatorType *ot) ot->srna, "use_unselected", 0, "Unselected", "Use whole stroke, not only selected points"); RNA_def_property_flag(prop, PROP_SKIP_SAVE); } + +/** \} */ diff --git a/source/blender/editors/gpencil/gpencil_fill.c b/source/blender/editors/gpencil/gpencil_fill.c index 7e753726564..d23a914fc49 100644 --- a/source/blender/editors/gpencil/gpencil_fill.c +++ b/source/blender/editors/gpencil/gpencil_fill.c @@ -1149,7 +1149,7 @@ static void gpencil_stroke_from_buffer(tGPDfill *tgpf) pt->time = 0.0f; /* Apply the vertex color to point. */ - ED_gpencil_point_vertex_color_set(ts, brush, pt); + ED_gpencil_point_vertex_color_set(ts, brush, pt, NULL); if ((ts->gpencil_flags & GP_TOOL_FLAG_CREATE_WEIGHTS) && (have_weight)) { MDeformWeight *dw = BKE_defvert_ensure_index(dvert, def_nr); diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h index c5e5a0b79ef..473913c5459 100644 --- a/source/blender/editors/gpencil/gpencil_intern.h +++ b/source/blender/editors/gpencil/gpencil_intern.h @@ -68,6 +68,17 @@ struct PropertyRNA; /* Internal Operator-State Data ------------------------ */ +/** Random settings by stroke */ +typedef struct GpRandomSettings { + /** Pressure used for evaluated curves. */ + float pen_press; + + float hsv[3]; + float pressure; + float strength; + float uv; +} GpRandomSettings; + /* Temporary draw data (no draw manager mode) */ typedef struct tGPDdraw { struct RegionView3D *rv3d; /* region to draw */ @@ -230,6 +241,10 @@ typedef struct tGPDprimitive { /** size in pixels for uv calculation */ float totpixlen; + + /** Random settings by stroke */ + GpRandomSettings random_settings; + } tGPDprimitive; /* Modal Operator Drawing Callbacks ------------------------ */ @@ -345,6 +360,10 @@ const struct EnumPropertyItem *ED_gpencil_layers_with_new_enum_itemf(struct bCon struct PointerRNA *ptr, struct PropertyRNA *prop, bool *r_free); +const struct EnumPropertyItem *ED_gpencil_material_enum_itemf(struct bContext *C, + struct PointerRNA *ptr, + struct PropertyRNA *prop, + bool *r_free); /* ***************************************************** */ /* Operator Defines */ @@ -550,7 +569,8 @@ void GPENCIL_OT_material_reveal(struct wmOperatorType *ot); void GPENCIL_OT_material_lock_all(struct wmOperatorType *ot); void GPENCIL_OT_material_unlock_all(struct wmOperatorType *ot); void GPENCIL_OT_material_lock_unused(struct wmOperatorType *ot); -void GPENCIL_OT_select_material(struct wmOperatorType *ot); +void GPENCIL_OT_material_select(struct wmOperatorType *ot); +void GPENCIL_OT_material_set(struct wmOperatorType *ot); void GPENCIL_OT_set_active_material(struct wmOperatorType *ot); /* convert old 2.7 files to 2.8 */ @@ -679,16 +699,13 @@ struct GP_EditableStrokes_Iter { const bool is_multiedit_ = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd_); \ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd_->layers) { \ if (BKE_gpencil_layer_is_editable(gpl)) { \ - bGPDframe *init_gpf_ = gpl->actframe; \ - if (is_multiedit_) { \ - init_gpf_ = gpl->frames.first; \ - } \ + bGPDframe *init_gpf_ = (is_multiedit_) ? gpl->frames.first : gpl->actframe; \ for (bGPDframe *gpf_ = init_gpf_; gpf_; gpf_ = gpf_->next) { \ if ((gpf_ == gpl->actframe) || ((gpf_->flag & GP_FRAME_SELECT) && is_multiedit_)) { \ BKE_gpencil_parent_matrix_get(depsgraph_, obact_, gpl, gpstroke_iter.diff_mat); \ invert_m4_m4(gpstroke_iter.inverse_diff_mat, gpstroke_iter.diff_mat); \ /* loop over strokes */ \ - for (bGPDstroke *gps = gpf_->strokes.first; gps; gps = gps->next) { \ + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf_->strokes) { \ /* skip strokes that are invalid for current view */ \ if (ED_gpencil_stroke_can_use(C, gps) == false) \ continue; \ diff --git a/source/blender/editors/gpencil/gpencil_ops.c b/source/blender/editors/gpencil/gpencil_ops.c index 0171a81f5eb..94c86572fd3 100644 --- a/source/blender/editors/gpencil/gpencil_ops.c +++ b/source/blender/editors/gpencil/gpencil_ops.c @@ -653,7 +653,8 @@ void ED_operatortypes_gpencil(void) WM_operatortype_append(GPENCIL_OT_material_reveal); WM_operatortype_append(GPENCIL_OT_material_lock_all); WM_operatortype_append(GPENCIL_OT_material_unlock_all); - WM_operatortype_append(GPENCIL_OT_select_material); + WM_operatortype_append(GPENCIL_OT_material_select); + WM_operatortype_append(GPENCIL_OT_material_set); /* Editing (Time) --------------- */ diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index 139e52254f4..4e83c4fb11c 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -255,6 +255,10 @@ typedef struct tGPsdata { tGPguide guide; ReportList *reports; + + /** Random settings by stroke */ + GpRandomSettings random_settings; + } tGPsdata; /* ------ */ @@ -687,6 +691,78 @@ static void gp_smooth_segment(bGPdata *gpd, const float inf, int from_idx, int t } } +static void gp_apply_randomness(tGPsdata *p, + BrushGpencilSettings *brush_settings, + tGPspoint *pt, + const bool press, + const bool strength, + const bool uv) +{ + bGPdata *gpd = p->gpd; + GpRandomSettings random_settings = p->random_settings; + float value = 0.0f; + /* Apply randomness to pressure. */ + if ((brush_settings->draw_random_press > 0.0f) && (press)) { + if ((brush_settings->flag2 & GP_BRUSH_USE_PRESS_AT_STROKE) == 0) { + float rand = BLI_rng_get_float(p->rng) * 2.0f - 1.0f; + value = 1.0 + rand * 2.0 * brush_settings->draw_random_press; + } + else { + value = 1.0 + random_settings.pressure * brush_settings->draw_random_press; + } + + /* Apply random curve. */ + if (brush_settings->flag2 & GP_BRUSH_USE_PRESSURE_RAND_PRESS) { + value *= BKE_curvemapping_evaluateF( + brush_settings->curve_rand_pressure, 0, random_settings.pen_press); + } + + pt->pressure *= value; + CLAMP(pt->pressure, 0.1f, 1.0f); + } + + /* Apply randomness to color strength. */ + if ((brush_settings->draw_random_strength) && (strength)) { + if ((brush_settings->flag2 & GP_BRUSH_USE_STRENGTH_AT_STROKE) == 0) { + float rand = BLI_rng_get_float(p->rng) * 2.0f - 1.0f; + value = 1.0 + rand * brush_settings->draw_random_strength; + } + else { + value = 1.0 + random_settings.strength * brush_settings->draw_random_strength; + } + + /* Apply random curve. */ + if (brush_settings->flag2 & GP_BRUSH_USE_STRENGTH_RAND_PRESS) { + value *= BKE_curvemapping_evaluateF( + brush_settings->curve_rand_pressure, 0, random_settings.pen_press); + } + + pt->strength *= value; + CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f); + } + + /* Apply randomness to uv texture rotation. */ + if ((brush_settings->uv_random > 0.0f) && (uv)) { + if ((brush_settings->flag2 & GP_BRUSH_USE_UV_AT_STROKE) == 0) { + float rand = BLI_hash_int_01(BLI_hash_int_2d((int)pt->x, gpd->runtime.sbuffer_used)) * 2.0f - + 1.0f; + value = rand * M_PI_2 * brush_settings->uv_random; + } + else { + value = random_settings.uv * M_PI_2 * brush_settings->uv_random; + } + + /* Apply random curve. */ + if (brush_settings->flag2 & GP_BRUSH_USE_UV_RAND_PRESS) { + value *= BKE_curvemapping_evaluateF( + brush_settings->curve_rand_uv, 0, random_settings.pen_press); + } + + pt->uv_rot += value; + CLAMP(pt->uv_rot, -M_PI_2, M_PI_2); + } +} + /* add current stroke-point to buffer (returns whether point was successfully added) */ static short gp_stroke_addpoint(tGPsdata *p, const float mval[2], float pressure, double curtime) { @@ -744,10 +820,6 @@ static short gp_stroke_addpoint(tGPsdata *p, const float mval[2], float pressure return GP_STROKEADD_INVALID; } - /* Set vertex colors for buffer. */ - ED_gpencil_sbuffer_vertex_color_set( - p->depsgraph, p->ob, p->scene->toolsettings, p->brush, p->material); - /* get pointer to destination point */ pt = ((tGPspoint *)(gpd->runtime.sbuffer) + gpd->runtime.sbuffer_used); @@ -768,6 +840,15 @@ static short gp_stroke_addpoint(tGPsdata *p, const float mval[2], float pressure CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f); } + /* Set vertex colors for buffer. */ + ED_gpencil_sbuffer_vertex_color_set(p->depsgraph, + p->ob, + p->scene->toolsettings, + p->brush, + p->material, + p->random_settings.hsv, + p->random_settings.pen_press); + if (brush_settings->flag & GP_BRUSH_GROUP_RANDOM) { /* Apply jitter to position */ if (brush_settings->draw_jitter > 0.0f) { @@ -781,26 +862,9 @@ static short gp_stroke_addpoint(tGPsdata *p, const float mval[2], float pressure const float fac = rand * square_f(exp_factor) * jitpress; gp_brush_jitter(gpd, pt, fac); } - /* apply randomness to pressure */ - if (brush_settings->draw_random_press > 0.0f) { - float rand = BLI_rng_get_float(p->rng) * 2.0f - 1.0f; - pt->pressure *= 1.0 + rand * 2.0 * brush_settings->draw_random_press; - CLAMP(pt->pressure, GPENCIL_STRENGTH_MIN, 1.0f); - } - /* apply randomness to uv texture rotation */ - if (brush_settings->uv_random > 0.0f) { - float rand = BLI_hash_int_01(BLI_hash_int_2d((int)pt->x, gpd->runtime.sbuffer_used)) * - 2.0f - - 1.0f; - pt->uv_rot += rand * M_PI_2 * brush_settings->uv_random; - CLAMP(pt->uv_rot, -M_PI_2, M_PI_2); - } - /* apply randomness to color strength */ - if (brush_settings->draw_random_strength) { - float rand = BLI_rng_get_float(p->rng) * 2.0f - 1.0f; - pt->strength *= 1.0 + rand * brush_settings->draw_random_strength; - CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f); - } + + /* Apply other randomness. */ + gp_apply_randomness(p, brush_settings, pt, true, true, true); } /* apply angle of stroke to brush size */ @@ -959,9 +1023,10 @@ static void gp_stroke_newfrombuffer(tGPsdata *p) pt->pressure = ptc->pressure; pt->strength = ptc->strength; CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f); + copy_v4_v4(pt->vert_color, ptc->vert_color); pt->time = ptc->time; /* Apply the vertex color to point. */ - ED_gpencil_point_vertex_color_set(ts, brush, pt); + ED_gpencil_point_vertex_color_set(ts, brush, pt, ptc); pt++; @@ -994,7 +1059,7 @@ static void gp_stroke_newfrombuffer(tGPsdata *p) CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f); pt->time = ptc->time; /* Apply the vertex color to point. */ - ED_gpencil_point_vertex_color_set(ts, brush, pt); + ED_gpencil_point_vertex_color_set(ts, brush, pt, ptc); if ((ts->gpencil_flags & GP_TOOL_FLAG_CREATE_WEIGHTS) && (have_weight)) { BKE_gpencil_dvert_ensure(gps); @@ -1113,11 +1178,12 @@ static void gp_stroke_newfrombuffer(tGPsdata *p) pt->pressure = ptc->pressure; pt->strength = ptc->strength; CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f); + copy_v4_v4(pt->vert_color, ptc->vert_color); pt->time = ptc->time; pt->uv_fac = ptc->uv_fac; pt->uv_rot = ptc->uv_rot; /* Apply the vertex color to point. */ - ED_gpencil_point_vertex_color_set(ts, brush, pt); + ED_gpencil_point_vertex_color_set(ts, brush, pt, ptc); if (dvert != NULL) { dvert->totweight = 0; @@ -1751,10 +1817,16 @@ static void gp_init_drawing_brush(bContext *C, tGPsdata *p) BKE_brush_gpencil_paint_presets(bmain, ts, true); changed = true; } - /* be sure curves are initializated */ + /* Be sure curves are initializated. */ BKE_curvemapping_initialize(paint->brush->gpencil_settings->curve_sensitivity); BKE_curvemapping_initialize(paint->brush->gpencil_settings->curve_strength); BKE_curvemapping_initialize(paint->brush->gpencil_settings->curve_jitter); + BKE_curvemapping_initialize(paint->brush->gpencil_settings->curve_rand_pressure); + BKE_curvemapping_initialize(paint->brush->gpencil_settings->curve_rand_strength); + BKE_curvemapping_initialize(paint->brush->gpencil_settings->curve_rand_uv); + BKE_curvemapping_initialize(paint->brush->gpencil_settings->curve_rand_hue); + BKE_curvemapping_initialize(paint->brush->gpencil_settings->curve_rand_saturation); + BKE_curvemapping_initialize(paint->brush->gpencil_settings->curve_rand_value); /* assign to temp tGPsdata */ p->brush = paint->brush; @@ -1999,8 +2071,15 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Deps return; } - /* Eraser mode: If no active strokes, just return. */ + /* Eraser mode: If no active strokes, add one or just return. */ if (paintmode == GP_PAINTMODE_ERASER) { + /* Eraser mode: + * 1) Add new frames to all frames that we might touch, + * 2) Ensure that p->gpf refers to the frame used for the active layer + * (to avoid problems with other tools which expect it to exist) + * + * This is done only if additive drawing is enabled. + */ bool has_layer_to_erase = false; LISTBASE_FOREACH (bGPDlayer *, gpl, &p->gpd->layers) { @@ -2009,12 +2088,27 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode, Deps continue; } + /* Add a new frame if needed (and based off the active frame, + * as we need some existing strokes to erase) + * + * Note: We don't add a new frame if there's nothing there now, so + * -> If there are no frames at all, don't add one + * -> If there are no strokes in that frame, don't add a new empty frame + */ if (gpl->actframe && gpl->actframe->strokes.first) { + if (ts->gpencil_flags & GP_TOOL_FLAG_RETAIN_LAST) { + gpl->actframe = BKE_gpencil_layer_frame_get(gpl, CFRA, GP_GETFRAME_ADD_COPY); + } has_layer_to_erase = true; break; } } + /* Ensure this gets set. */ + if (ts->gpencil_flags & GP_TOOL_FLAG_RETAIN_LAST) { + p->gpf = p->gpl->actframe; + } + if (has_layer_to_erase == false) { p->status = GP_STATUS_ERROR; return; @@ -2700,6 +2794,8 @@ static void gpencil_draw_apply_event(bContext *C, /* handle pressure sensitivity (which is supplied by tablets or otherwise 1.0) */ p->pressure = event->tablet.pressure; + /* By default use pen pressure for random curves but attenuated. */ + p->random_settings.pen_press = pow(p->pressure, 3.0f); /* Hack for pressure sensitive eraser on D+RMB when using a tablet: * The pen has to float over the tablet surface, resulting in @@ -3052,6 +3148,8 @@ static int gpencil_draw_invoke(bContext *C, wmOperator *op, const wmEvent *event else { p = op->customdata; } + /* Init random settings. */ + ED_gpencil_init_random_settings(p->brush, event->mval, &p->random_settings); /* TODO: set any additional settings that we can take from the events? * if eraser is on, draw radial aid */ @@ -3175,10 +3273,17 @@ static void gp_brush_angle_segment(tGPsdata *p, tGPspoint *pt_prev, tGPspoint *p static void gpencil_add_arc_points(tGPsdata *p, float mval[2], int segments) { bGPdata *gpd = p->gpd; + BrushGpencilSettings *brush_settings = p->brush->gpencil_settings; + if (gpd->runtime.sbuffer_used < 3) { + tGPspoint *points = (tGPspoint *)gpd->runtime.sbuffer; + /* Apply other randomness to first points. */ + for (int i = 0; i < gpd->runtime.sbuffer_used; i++) { + tGPspoint *pt = &points[i]; + gp_apply_randomness(p, brush_settings, pt, false, false, true); + } return; } - BrushGpencilSettings *brush_settings = p->brush->gpencil_settings; int idx_prev = gpd->runtime.sbuffer_used; /* Add space for new arc points. */ @@ -3233,6 +3338,7 @@ static void gpencil_add_arc_points(tGPsdata *p, float mval[2], int segments) corner[0] = midpoint[0] - (cp1[0] - midpoint[0]); corner[1] = midpoint[1] - (cp1[1] - midpoint[1]); + float stepcolor = 1.0f / segments; tGPspoint *pt_step = pt_prev; for (int i = 0; i < segments; i++) { @@ -3243,6 +3349,9 @@ static void gpencil_add_arc_points(tGPsdata *p, float mval[2], int segments) /* Set pressure and strength equals to previous. It will be smoothed later. */ pt->pressure = pt_prev->pressure; pt->strength = pt_prev->strength; + /* Interpolate vertex color. */ + interp_v4_v4v4( + pt->vert_color, pt_before->vert_color, pt_prev->vert_color, stepcolor * (i + 1)); /* Apply angle of stroke to brush size to interpolated points but slightly attenuated.. */ if (brush_settings->draw_angle_factor != 0.0f) { @@ -3252,26 +3361,8 @@ static void gpencil_add_arc_points(tGPsdata *p, float mval[2], int segments) pt_step = pt; } - /* Apply randomness to pressure. */ - if (brush_settings->draw_random_press > 0.0f) { - float rand = BLI_rng_get_float(p->rng) * 2.0f - 1.0f; - pt->pressure *= 1.0 + rand * 2.0 * brush_settings->draw_random_press; - CLAMP(pt->pressure, GPENCIL_STRENGTH_MIN, 1.0f); - } - /* Apply randomness to color strength. */ - if (brush_settings->draw_random_strength) { - float rand = BLI_rng_get_float(p->rng) * 2.0f - 1.0f; - pt->strength *= 1.0 + rand * brush_settings->draw_random_strength; - CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f); - } - /* Apply randomness to uv texture rotation. */ - if (brush_settings->uv_random > 0.0f) { - float rand = BLI_hash_int_01(BLI_hash_int_2d((int)pt->x, gpd->runtime.sbuffer_used + i)) * - 2.0f - - 1.0f; - pt->uv_rot += rand * M_PI_2 * brush_settings->uv_random; - CLAMP(pt->uv_rot, -M_PI_2, M_PI_2); - } + /* Apply other randomness. */ + gp_apply_randomness(p, brush_settings, pt, false, false, true); a += step; } @@ -3323,6 +3414,7 @@ static void gpencil_add_guide_points(const tGPsdata *p, /* Set pressure and strength equals to previous. It will be smoothed later. */ pt->pressure = pt_before->pressure; pt->strength = pt_before->strength; + copy_v4_v4(pt->vert_color, pt_before->vert_color); } } else { @@ -3339,6 +3431,7 @@ static void gpencil_add_guide_points(const tGPsdata *p, /* Set pressure and strength equals to previous. It will be smoothed later. */ pt->pressure = pt_before->pressure; pt->strength = pt_before->strength; + copy_v4_v4(pt->vert_color, pt_before->vert_color); } } } diff --git a/source/blender/editors/gpencil/gpencil_primitive.c b/source/blender/editors/gpencil/gpencil_primitive.c index 9e97a936be8..875a6265497 100644 --- a/source/blender/editors/gpencil/gpencil_primitive.c +++ b/source/blender/editors/gpencil/gpencil_primitive.c @@ -124,8 +124,13 @@ static void gp_session_validatebuffer(tGPDprimitive *p) gpd->runtime.sbuffer_sflag |= GP_STROKE_3DSPACE; /* Set vertex colors for buffer. */ - ED_gpencil_sbuffer_vertex_color_set( - p->depsgraph, p->ob, p->scene->toolsettings, p->brush, p->material); + ED_gpencil_sbuffer_vertex_color_set(p->depsgraph, + p->ob, + p->scene->toolsettings, + p->brush, + p->material, + p->random_settings.hsv, + 1.0f); if (ELEM(p->type, GP_STROKE_BOX, GP_STROKE_CIRCLE)) { gpd->runtime.sbuffer_sflag |= GP_STROKE_CYCLIC; @@ -681,6 +686,8 @@ static void gp_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi) ToolSettings *ts = tgpi->scene->toolsettings; bGPdata *gpd = tgpi->gpd; Brush *brush = tgpi->brush; + BrushGpencilSettings *brush_settings = brush->gpencil_settings; + GpRandomSettings random_settings = tgpi->random_settings; bGPDstroke *gps = tgpi->gpf->strokes.first; GP_Sculpt_Settings *gset = &ts->gp_sculpt; int depth_margin = (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 4 : 0; @@ -735,11 +742,11 @@ static void gp_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi) if (gset->flag & GP_SCULPT_SETT_FLAG_PRIMITIVE_CURVE) { BKE_curvemapping_initialize(ts->gp_sculpt.cur_primitive); } - if (tgpi->brush->gpencil_settings->flag & GP_BRUSH_USE_JITTER_PRESSURE) { - BKE_curvemapping_initialize(tgpi->brush->gpencil_settings->curve_jitter); + if (brush_settings->flag & GP_BRUSH_USE_JITTER_PRESSURE) { + BKE_curvemapping_initialize(brush_settings->curve_jitter); } - if (tgpi->brush->gpencil_settings->flag & GP_BRUSH_USE_STENGTH_PRESSURE) { - BKE_curvemapping_initialize(tgpi->brush->gpencil_settings->curve_strength); + if (brush_settings->flag & GP_BRUSH_USE_STENGTH_PRESSURE) { + BKE_curvemapping_initialize(brush_settings->curve_strength); } /* get an array of depths, far depths are blended */ @@ -841,10 +848,9 @@ static void gp_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi) tGPspoint *p2d = &points2D[i]; /* set rnd value for reuse */ - if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_RANDOM) && (p2d->rnd_dirty != true)) { + if ((brush_settings->flag & GP_BRUSH_GROUP_RANDOM) && (p2d->rnd_dirty != true)) { p2d->rnd[0] = BLI_rng_get_float(tgpi->rng); p2d->rnd[1] = BLI_rng_get_float(tgpi->rng); - p2d->rnd[2] = BLI_rng_get_float(tgpi->rng); p2d->rnd_dirty = true; } @@ -858,7 +864,7 @@ static void gp_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi) /* calc pressure */ float curve_pressure = 1.0; float pressure = 1.0; - float strength = brush->gpencil_settings->draw_strength; + float strength = brush_settings->draw_strength; /* normalize value to evaluate curve */ if (gset->flag & GP_SCULPT_SETT_FLAG_PRIMITIVE_CURVE) { @@ -868,20 +874,18 @@ static void gp_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi) } /* apply jitter to position */ - if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_RANDOM) && - (brush->gpencil_settings->draw_jitter > 0.0f)) { + if ((brush_settings->flag & GP_BRUSH_GROUP_RANDOM) && (brush_settings->draw_jitter > 0.0f)) { float jitter; - if (brush->gpencil_settings->flag & GP_BRUSH_USE_JITTER_PRESSURE) { - jitter = BKE_curvemapping_evaluateF( - brush->gpencil_settings->curve_jitter, 0, curve_pressure); + if (brush_settings->flag & GP_BRUSH_USE_JITTER_PRESSURE) { + jitter = BKE_curvemapping_evaluateF(brush_settings->curve_jitter, 0, curve_pressure); } else { - jitter = brush->gpencil_settings->draw_jitter; + jitter = brush_settings->draw_jitter; } /* exponential value */ - const float exfactor = square_f(brush->gpencil_settings->draw_jitter + 2.0f); + const float exfactor = square_f(brush_settings->draw_jitter + 2.0f); const float fac = p2d->rnd[0] * exfactor * jitter; /* vector */ @@ -906,47 +910,68 @@ static void gp_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi) add_v2_v2(&p2d->x, svec); } - /* apply randomness to pressure */ - if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_RANDOM) && - (brush->gpencil_settings->draw_random_press > 0.0f)) { - if (p2d->rnd[0] > 0.5f) { - pressure -= (brush->gpencil_settings->draw_random_press * 2.0f) * p2d->rnd[1]; - } - else { - pressure += (brush->gpencil_settings->draw_random_press * 2.0f) * p2d->rnd[2]; - } - } - /* color strength */ - if (brush->gpencil_settings->flag & GP_BRUSH_USE_STENGTH_PRESSURE) { - float curvef = BKE_curvemapping_evaluateF( - brush->gpencil_settings->curve_strength, 0, curve_pressure); + if (brush_settings->flag & GP_BRUSH_USE_STENGTH_PRESSURE) { + float curvef = BKE_curvemapping_evaluateF(brush_settings->curve_strength, 0, curve_pressure); strength *= curvef; - strength *= brush->gpencil_settings->draw_strength; + strength *= brush_settings->draw_strength; } CLAMP(strength, GPENCIL_STRENGTH_MIN, 1.0f); - /* apply randomness to color strength */ - if ((brush->gpencil_settings->flag & GP_BRUSH_GROUP_RANDOM) && - (brush->gpencil_settings->draw_random_strength > 0.0f)) { - if (p2d->rnd[2] > 0.5f) { - strength -= strength * brush->gpencil_settings->draw_random_strength * p2d->rnd[0]; + if (brush_settings->flag & GP_BRUSH_GROUP_RANDOM) { + /* Apply randomness to pressure. */ + if (brush_settings->draw_random_press > 0.0f) { + if ((brush_settings->flag2 & GP_BRUSH_USE_PRESS_AT_STROKE) == 0) { + float rand = BLI_rng_get_float(tgpi->rng) * 2.0f - 1.0f; + pressure *= 1.0 + rand * 2.0 * brush_settings->draw_random_press; + } + else { + pressure *= 1.0 + random_settings.pressure * brush_settings->draw_random_press; + } + + /* Apply random curve. */ + if (brush_settings->flag2 & GP_BRUSH_USE_PRESSURE_RAND_PRESS) { + pressure *= BKE_curvemapping_evaluateF(brush_settings->curve_rand_pressure, 0, pressure); + } + + CLAMP(pressure, 0.1f, 1.0f); } - else { - strength += strength * brush->gpencil_settings->draw_random_strength * p2d->rnd[1]; + + /* Apply randomness to color strength. */ + if (brush_settings->draw_random_strength) { + if ((brush_settings->flag2 & GP_BRUSH_USE_STRENGTH_AT_STROKE) == 0) { + float rand = BLI_rng_get_float(tgpi->rng) * 2.0f - 1.0f; + strength *= 1.0 + rand * brush_settings->draw_random_strength; + } + else { + strength *= 1.0 + random_settings.strength * brush_settings->draw_random_strength; + } + + /* Apply random curve. */ + if (brush_settings->flag2 & GP_BRUSH_USE_STRENGTH_RAND_PRESS) { + strength *= BKE_curvemapping_evaluateF(brush_settings->curve_rand_strength, 0, pressure); + } + + CLAMP(strength, GPENCIL_STRENGTH_MIN, 1.0f); } - CLAMP(strength, GPENCIL_STRENGTH_MIN, 1.0f); } copy_v2_v2(&tpt->x, &p2d->x); - CLAMP_MIN(pressure, 0.1f); - tpt->pressure = pressure; tpt->strength = strength; tpt->time = p2d->time; + /* Set vertex colors for buffer. */ + ED_gpencil_sbuffer_vertex_color_set(tgpi->depsgraph, + tgpi->ob, + tgpi->scene->toolsettings, + tgpi->brush, + tgpi->material, + tgpi->random_settings.hsv, + strength); + /* point uv */ if (gpd->runtime.sbuffer_used > 0) { tGPspoint *tptb = (tGPspoint *)gpd->runtime.sbuffer + gpd->runtime.sbuffer_used - 1; @@ -994,8 +1019,7 @@ static void gp_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi) pt->time = 0.0f; pt->flag = 0; pt->uv_fac = tpt->uv_fac; - /* Apply the vertex color to point. */ - ED_gpencil_point_vertex_color_set(ts, brush, pt); + copy_v4_v4(pt->vert_color, tpt->vert_color); if (gps->dvert != NULL) { MDeformVert *dvert = &gps->dvert[i]; @@ -1159,6 +1183,7 @@ static void gpencil_primitive_init(bContext *C, wmOperator *op) /* Set Draw brush. */ Brush *brush = BKE_paint_toolslots_brush_get(paint, 0); + BKE_brush_tool_set(brush, paint, 0); BKE_paint_brush_set(paint, brush); tgpi->brush = brush; @@ -1226,6 +1251,9 @@ static int gpencil_primitive_invoke(bContext *C, wmOperator *op, const wmEvent * gpencil_primitive_init(C, op); tgpi = op->customdata; + /* Init random settings. */ + ED_gpencil_init_random_settings(tgpi->brush, event->mval, &tgpi->random_settings); + const bool is_modal = RNA_boolean_get(op->ptr, "wait_for_input"); if (!is_modal) { tgpi->flag = IN_PROGRESS; @@ -1262,6 +1290,7 @@ static void gpencil_primitive_interaction_end(bContext *C, ToolSettings *ts = tgpi->scene->toolsettings; Brush *brush = tgpi->brush; + BrushGpencilSettings *brush_settings = brush->gpencil_settings; const int def_nr = tgpi->ob->actdef - 1; const bool have_weight = (bool)BLI_findlink(&tgpi->ob->defbase, def_nr); @@ -1285,8 +1314,8 @@ static void gpencil_primitive_interaction_end(bContext *C, gps = tgpi->gpf->strokes.first; if (gps) { gps->thickness = brush->size; - gps->hardeness = brush->gpencil_settings->hardeness; - copy_v2_v2(gps->aspect_ratio, brush->gpencil_settings->aspect_ratio); + gps->hardeness = brush_settings->hardeness; + copy_v2_v2(gps->aspect_ratio, brush_settings->aspect_ratio); /* Calc geometry data. */ BKE_gpencil_stroke_geometry_update(gps); @@ -1449,23 +1478,25 @@ static void gpencil_primitive_edit_event_handling( static void gpencil_primitive_strength(tGPDprimitive *tgpi, bool reset) { Brush *brush = tgpi->brush; + BrushGpencilSettings *brush_settings = brush->gpencil_settings; + if (brush) { if (reset) { - brush->gpencil_settings->draw_strength = tgpi->brush_strength; + brush_settings->draw_strength = tgpi->brush_strength; tgpi->brush_strength = 0.0f; } else { if (tgpi->brush_strength == 0.0f) { - tgpi->brush_strength = brush->gpencil_settings->draw_strength; + tgpi->brush_strength = brush_settings->draw_strength; } float move[2]; sub_v2_v2v2(move, tgpi->mval, tgpi->mvalo); float adjust = (move[1] > 0.0f) ? 0.01f : -0.01f; - brush->gpencil_settings->draw_strength += adjust * fabsf(len_manhattan_v2(move)); + brush_settings->draw_strength += adjust * fabsf(len_manhattan_v2(move)); } /* limit low limit because below 0.2f the stroke is invisible */ - CLAMP(brush->gpencil_settings->draw_strength, 0.2f, 1.0f); + CLAMP(brush_settings->draw_strength, 0.2f, 1.0f); } } diff --git a/source/blender/editors/gpencil/gpencil_select.c b/source/blender/editors/gpencil/gpencil_select.c index e25576f32aa..69d22b52ded 100644 --- a/source/blender/editors/gpencil/gpencil_select.c +++ b/source/blender/editors/gpencil/gpencil_select.c @@ -1327,8 +1327,8 @@ void GPENCIL_OT_select_box(wmOperatorType *ot) struct GP_SelectLassoUserData { rcti rect; - const int (*mcords)[2]; - int mcords_len; + const int (*mcoords)[2]; + int mcoords_len; }; static bool gpencil_test_lasso(bGPDstroke *gps, @@ -1344,25 +1344,25 @@ static bool gpencil_test_lasso(bGPDstroke *gps, gp_point_to_xy(gsc, gps, &pt2, &x0, &y0); /* test if in lasso boundbox + within the lasso noose */ return ((!ELEM(V2D_IS_CLIPPED, x0, y0)) && BLI_rcti_isect_pt(&data->rect, x0, y0) && - BLI_lasso_is_point_inside(data->mcords, data->mcords_len, x0, y0, INT_MAX)); + BLI_lasso_is_point_inside(data->mcoords, data->mcoords_len, x0, y0, INT_MAX)); } static int gpencil_lasso_select_exec(bContext *C, wmOperator *op) { struct GP_SelectLassoUserData data = {0}; - data.mcords = WM_gesture_lasso_path_to_array(C, op, &data.mcords_len); + data.mcoords = WM_gesture_lasso_path_to_array(C, op, &data.mcoords_len); /* Sanity check. */ - if (data.mcords == NULL) { + if (data.mcoords == NULL) { return OPERATOR_PASS_THROUGH; } /* Compute boundbox of lasso (for faster testing later). */ - BLI_lasso_boundbox(&data.rect, data.mcords, data.mcords_len); + BLI_lasso_boundbox(&data.rect, data.mcoords, data.mcoords_len); int ret = gpencil_generic_select_exec(C, op, gpencil_test_lasso, &data); - MEM_freeN((void *)data.mcords); + MEM_freeN((void *)data.mcoords); return ret; } diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c index c1843b1c138..3cab26eab44 100644 --- a/source/blender/editors/gpencil/gpencil_utils.c +++ b/source/blender/editors/gpencil/gpencil_utils.c @@ -30,11 +30,14 @@ #include "BLI_blenlib.h" #include "BLI_ghash.h" +#include "BLI_hash.h" #include "BLI_math.h" #include "BLI_rand.h" #include "BLI_utildefines.h" #include "BLT_translation.h" +#include "PIL_time.h" + #include "DNA_brush_types.h" #include "DNA_gpencil_types.h" #include "DNA_meshdata_types.h" @@ -74,6 +77,7 @@ #include "ED_object.h" #include "ED_screen.h" #include "ED_select_utils.h" +#include "ED_transform_snap_object_context.h" #include "ED_view3d.h" #include "GPU_immediate.h" @@ -481,6 +485,40 @@ const EnumPropertyItem *ED_gpencil_layers_with_new_enum_itemf(bContext *C, return item; } +/* Just existing Materials */ +const EnumPropertyItem *ED_gpencil_material_enum_itemf(bContext *C, + PointerRNA *UNUSED(ptr), + PropertyRNA *UNUSED(prop), + bool *r_free) +{ + Object *ob = CTX_data_active_object(C); + EnumPropertyItem *item = NULL, item_tmp = {0}; + int totitem = 0; + int i = 0; + + if (ELEM(NULL, C, ob)) { + return DummyRNA_DEFAULT_items; + } + + /* Existing materials */ + for (i = 1; i <= ob->totcol; i++) { + Material *ma = BKE_object_material_get(ob, i); + if (ma) { + item_tmp.identifier = ma->id.name + 2; + item_tmp.name = ma->id.name + 2; + item_tmp.value = i; + item_tmp.icon = ma->preview ? ma->preview->icon_id : ICON_NONE; + + RNA_enum_item_add(&item, &totitem, &item_tmp); + } + } + + RNA_enum_item_end(&item, &totitem); + *r_free = true; + + return item; +} + /* ******************************************************** */ /* Brush Tool Core */ @@ -670,8 +708,8 @@ void gp_apply_parent_point(Depsgraph *depsgraph, Object *obact, bGPDlayer *gpl, /** * Convert a Grease Pencil coordinate (i.e. can be 2D or 3D) to screenspace (2D) * - * \param[out] r_x The screen-space x-coordinate of the point - * \param[out] r_y The screen-space y-coordinate of the point + * \param[out] r_x: The screen-space x-coordinate of the point + * \param[out] r_y: The screen-space y-coordinate of the point * * \warning This assumes that the caller has already checked * whether the stroke in question can be drawn. @@ -2525,26 +2563,170 @@ void ED_gpencil_fill_vertex_color_set(ToolSettings *ts, Brush *brush, bGPDstroke } } -void ED_gpencil_point_vertex_color_set(ToolSettings *ts, Brush *brush, bGPDspoint *pt) +void ED_gpencil_point_vertex_color_set(ToolSettings *ts, + Brush *brush, + bGPDspoint *pt, + tGPspoint *tpt) { if (GPENCIL_USE_VERTEX_COLOR_STROKE(ts, brush)) { - copy_v3_v3(pt->vert_color, brush->rgb); - pt->vert_color[3] = brush->gpencil_settings->vertex_factor; - srgb_to_linearrgb_v4(pt->vert_color, pt->vert_color); + if (tpt == NULL) { + copy_v3_v3(pt->vert_color, brush->rgb); + pt->vert_color[3] = brush->gpencil_settings->vertex_factor; + srgb_to_linearrgb_v4(pt->vert_color, pt->vert_color); + } + else { + copy_v3_v3(pt->vert_color, tpt->vert_color); + pt->vert_color[3] = brush->gpencil_settings->vertex_factor; + } } else { zero_v4(pt->vert_color); } } -void ED_gpencil_sbuffer_vertex_color_set( - Depsgraph *depsgraph, Object *ob, ToolSettings *ts, Brush *brush, Material *material) +void ED_gpencil_init_random_settings(Brush *brush, + const int mval[2], + GpRandomSettings *random_settings) +{ + int seed = ((uint)(ceil(PIL_check_seconds_timer())) + 1) % 128; + /* Use mouse position to get randomness. */ + int ix = mval[0] * seed; + int iy = mval[1] * seed; + int iz = ix + iy * seed; + zero_v3(random_settings->hsv); + + BrushGpencilSettings *brush_settings = brush->gpencil_settings; + /* Random to Hue. */ + if (brush_settings->random_hue > 0.0f) { + float rand = BLI_hash_int_01(BLI_hash_int_2d(ix, iy)) * 2.0f - 1.0f; + random_settings->hsv[0] = rand * brush_settings->random_hue * 0.5f; + } + /* Random to Saturation. */ + if (brush_settings->random_saturation > 0.0f) { + float rand = BLI_hash_int_01(BLI_hash_int_2d(iy, ix)) * 2.0f - 1.0f; + random_settings->hsv[1] = rand * brush_settings->random_saturation; + } + /* Random to Value. */ + if (brush_settings->random_value > 0.0f) { + float rand = BLI_hash_int_01(BLI_hash_int_2d(ix * iz, iy * iz)) * 2.0f - 1.0f; + random_settings->hsv[2] = rand * brush_settings->random_value; + } + + /* Random to pressure. */ + if (brush_settings->draw_random_press > 0.0f) { + random_settings->pressure = BLI_hash_int_01(BLI_hash_int_2d(ix + iz, iy + iz)) * 2.0f - 1.0f; + } + + /* Randomn to color strength. */ + if (brush_settings->draw_random_strength) { + random_settings->strength = BLI_hash_int_01(BLI_hash_int_2d(ix + iy, iy + iz + ix)) * 2.0f - + 1.0f; + } + + /* Random to uv texture rotation. */ + if (brush_settings->uv_random > 0.0f) { + random_settings->uv = BLI_hash_int_01(BLI_hash_int_2d(iy + iz, ix * iz)) * 2.0f - 1.0f; + } +} + +static void gpencil_sbuffer_vertex_color_random( + bGPdata *gpd, Brush *brush, tGPspoint *tpt, float random_color[3], float pen_pressure) +{ + BrushGpencilSettings *brush_settings = brush->gpencil_settings; + if (brush_settings->flag & GP_BRUSH_GROUP_RANDOM) { + int seed = ((uint)(ceil(PIL_check_seconds_timer())) + 1) % 128; + + int ix = (int)(tpt->x * seed); + int iy = (int)(tpt->y * seed); + int iz = ix + iy * seed; + float hsv[3]; + float factor_value[3]; + zero_v3(factor_value); + + /* Apply randomness to Hue. */ + if (brush_settings->random_hue > 0.0f) { + if ((brush_settings->flag2 & GP_BRUSH_USE_HUE_AT_STROKE) == 0) { + + float rand = BLI_hash_int_01(BLI_hash_int_2d(ix, gpd->runtime.sbuffer_used)) * 2.0f - 1.0f; + factor_value[0] = rand * brush_settings->random_hue * 0.5f; + } + else { + factor_value[0] = random_color[0]; + } + + /* Apply random curve. */ + if (brush_settings->flag2 & GP_BRUSH_USE_HUE_RAND_PRESS) { + factor_value[0] *= BKE_curvemapping_evaluateF( + brush_settings->curve_rand_hue, 0, pen_pressure); + } + } + + /* Apply randomness to Saturation. */ + if (brush_settings->random_saturation > 0.0f) { + if ((brush_settings->flag2 & GP_BRUSH_USE_SAT_AT_STROKE) == 0) { + float rand = BLI_hash_int_01(BLI_hash_int_2d(iy, gpd->runtime.sbuffer_used)) * 2.0f - 1.0f; + factor_value[1] = rand * brush_settings->random_saturation; + } + else { + factor_value[1] = random_color[1]; + } + + /* Apply random curve. */ + if (brush_settings->flag2 & GP_BRUSH_USE_SAT_RAND_PRESS) { + factor_value[1] *= BKE_curvemapping_evaluateF( + brush_settings->curve_rand_saturation, 0, pen_pressure); + } + } + + /* Apply randomness to Value. */ + if (brush_settings->random_value > 0.0f) { + if ((brush_settings->flag2 & GP_BRUSH_USE_VAL_AT_STROKE) == 0) { + float rand = BLI_hash_int_01(BLI_hash_int_2d(iz, gpd->runtime.sbuffer_used)) * 2.0f - 1.0f; + factor_value[2] = rand * brush_settings->random_value; + } + else { + factor_value[2] = random_color[2]; + } + + /* Apply random curve. */ + if (brush_settings->flag2 & GP_BRUSH_USE_VAL_RAND_PRESS) { + factor_value[2] *= BKE_curvemapping_evaluateF( + brush_settings->curve_rand_value, 0, pen_pressure); + } + } + + rgb_to_hsv_v(tpt->vert_color, hsv); + add_v3_v3(hsv, factor_value); + /* For Hue need to cover all range, but for Saturation and Value + * is not logic because the effect is too hard, so the value is just clamped. */ + if (hsv[0] < 0.0f) { + hsv[0] += 1.0f; + } + else if (hsv[0] > 1.0f) { + hsv[0] -= 1.0f; + } + + CLAMP3(hsv, 0.0f, 1.0f); + hsv_to_rgb_v(hsv, tpt->vert_color); + } +} + +void ED_gpencil_sbuffer_vertex_color_set(Depsgraph *depsgraph, + Object *ob, + ToolSettings *ts, + Brush *brush, + Material *material, + float random_color[3], + float pen_pressure) { bGPdata *gpd = (bGPdata *)ob->data; Object *ob_eval = (Object *)DEG_get_evaluated_id(depsgraph, &ob->id); bGPdata *gpd_eval = (bGPdata *)ob_eval->data; MaterialGPencilStyle *gp_style = material->gp_style; + int idx = gpd->runtime.sbuffer_used; + tGPspoint *tpt = (tGPspoint *)gpd->runtime.sbuffer + idx; + float vertex_color[4]; copy_v3_v3(vertex_color, brush->rgb); vertex_color[3] = brush->gpencil_settings->vertex_factor; @@ -2559,15 +2741,18 @@ void ED_gpencil_sbuffer_vertex_color_set( } /* Copy stroke vertex color. */ if (GPENCIL_USE_VERTEX_COLOR_STROKE(ts, brush)) { - copy_v4_v4(gpd->runtime.vert_color, vertex_color); + copy_v4_v4(tpt->vert_color, vertex_color); } else { - copy_v4_v4(gpd->runtime.vert_color, gp_style->stroke_rgba); + copy_v4_v4(tpt->vert_color, gp_style->stroke_rgba); } - /* Copy to eval data because paint operators don't tag refresh until end for speedup painting. */ + /* Random Color. */ + gpencil_sbuffer_vertex_color_random(gpd, brush, tpt, random_color, pen_pressure); + + /* Copy to eval data because paint operators don't tag refresh until end for speedup + painting. */ if (gpd_eval != NULL) { - copy_v4_v4(gpd_eval->runtime.vert_color, gpd->runtime.vert_color); copy_v4_v4(gpd_eval->runtime.vert_color_fill, gpd->runtime.vert_color_fill); gpd_eval->runtime.matid = gpd->runtime.matid; } diff --git a/source/blender/editors/include/ED_anim_api.h b/source/blender/editors/include/ED_anim_api.h index a9b34e3c735..7d38792f332 100644 --- a/source/blender/editors/include/ED_anim_api.h +++ b/source/blender/editors/include/ED_anim_api.h @@ -229,6 +229,7 @@ typedef enum eAnim_ChannelType { ANIMTYPE_DSHAIR, ANIMTYPE_DSPOINTCLOUD, ANIMTYPE_DSVOLUME, + ANIMTYPE_DSSIMULATION, ANIMTYPE_SHAPEKEY, @@ -356,6 +357,8 @@ typedef enum eAnimFilter_Flags { #define FILTER_HAIR_OBJD(ha) (CHECK_TYPE_INLINE(ha, Hair *), ((ha->flag & HA_DS_EXPAND))) #define FILTER_POINTS_OBJD(pt) (CHECK_TYPE_INLINE(pt, PointCloud *), ((pt->flag & PT_DS_EXPAND))) #define FILTER_VOLUME_OBJD(vo) (CHECK_TYPE_INLINE(vo, Volume *), ((vo->flag & VO_DS_EXPAND))) +#define FILTER_SIMULATION_OBJD(sim) \ + (CHECK_TYPE_INLINE(sim, Simulation *), ((sim->flag & SIM_DS_EXPAND))) /* Variable use expanders */ #define FILTER_NTREE_DATA(ntree) \ (CHECK_TYPE_INLINE(ntree, bNodeTree *), (((ntree)->flag & NTREE_DS_EXPAND))) diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h index 1403ae1f3cc..2dbd979564e 100644 --- a/source/blender/editors/include/ED_gpencil.h +++ b/source/blender/editors/include/ED_gpencil.h @@ -40,6 +40,7 @@ struct bGPDspoint; struct bGPDstroke; struct bGPdata; struct tGPspoint; +struct GpRandomSettings; struct ARegion; struct Depsgraph; @@ -48,6 +49,7 @@ struct RegionView3D; struct ReportList; struct Scene; struct ScrArea; +struct SnapObjectContext; struct ToolSettings; struct View3D; struct ViewLayer; @@ -69,14 +71,15 @@ struct wmOperator; * Used as part of the 'stroke cache' used during drawing of new strokes */ typedef struct tGPspoint { - float x, y; /* x and y coordinates of cursor (in relative to area) */ - float pressure; /* pressure of tablet at this point */ - float strength; /* pressure of tablet at this point for alpha factor */ - float time; /* Time relative to stroke start (used when converting to path) */ - float uv_fac; /* factor of uv along the stroke */ - float uv_rot; /* uv rotation for dor mode */ - float rnd[3]; /* rnd value */ - bool rnd_dirty; /* rnd flag */ + float x, y; /* x and y coordinates of cursor (in relative to area) */ + float pressure; /* pressure of tablet at this point */ + float strength; /* pressure of tablet at this point for alpha factor */ + float time; /* Time relative to stroke start (used when converting to path) */ + float uv_fac; /* factor of uv along the stroke */ + float uv_rot; /* uv rotation for dor mode */ + float rnd[3]; /* rnd value */ + bool rnd_dirty; /* rnd flag */ + float vert_color[4]; /* Point vertex color. */ } tGPspoint; /* ----------- Grease Pencil Tools/Context ------------- */ @@ -296,12 +299,18 @@ void ED_gpencil_fill_vertex_color_set(struct ToolSettings *ts, struct bGPDstroke *gps); void ED_gpencil_point_vertex_color_set(struct ToolSettings *ts, struct Brush *brush, - struct bGPDspoint *pt); + struct bGPDspoint *pt, + struct tGPspoint *tpt); void ED_gpencil_sbuffer_vertex_color_set(struct Depsgraph *depsgraph, struct Object *ob, struct ToolSettings *ts, struct Brush *brush, - struct Material *material); + struct Material *material, + float random_color[3], + float pen_pressure); +void ED_gpencil_init_random_settings(struct Brush *brush, + const int mval[2], + struct GpRandomSettings *random_settings); bool ED_gpencil_stroke_check_collision(struct GP_SpaceConversion *gsc, struct bGPDstroke *gps, diff --git a/source/blender/editors/include/ED_image.h b/source/blender/editors/include/ED_image.h index 910cf362a37..a8476e3d1ca 100644 --- a/source/blender/editors/include/ED_image.h +++ b/source/blender/editors/include/ED_image.h @@ -69,7 +69,7 @@ void ED_space_image_get_size(struct SpaceImage *sima, int *r_width, int *r_heigh void ED_space_image_get_size_fl(struct SpaceImage *sima, float r_size[2]); void ED_space_image_get_aspect(struct SpaceImage *sima, float *r_aspx, float *r_aspy); void ED_space_image_get_zoom(struct SpaceImage *sima, - struct ARegion *region, + const struct ARegion *region, float *r_zoomx, float *r_zoomy); void ED_space_image_get_uv_aspect(struct SpaceImage *sima, float *r_aspx, float *r_aspy); @@ -88,14 +88,18 @@ void ED_image_get_uv_aspect(struct Image *ima, float *r_aspx, float *r_aspy); void ED_image_mouse_pos(struct SpaceImage *sima, - struct ARegion *region, + const struct ARegion *region, const int mval[2], float co[2]); void ED_image_view_center_to_point(struct SpaceImage *sima, float x, float y); -void ED_image_point_pos( - struct SpaceImage *sima, struct ARegion *region, float x, float y, float *r_x, float *r_y); +void ED_image_point_pos(struct SpaceImage *sima, + const struct ARegion *region, + float x, + float y, + float *r_x, + float *r_y); void ED_image_point_pos__reverse(struct SpaceImage *sima, - struct ARegion *region, + const struct ARegion *region, const float co[2], float r_co[2]); bool ED_image_slot_cycle(struct Image *image, int direction); diff --git a/source/blender/editors/include/ED_info.h b/source/blender/editors/include/ED_info.h index 82662a6b118..1146c49bef2 100644 --- a/source/blender/editors/include/ED_info.h +++ b/source/blender/editors/include/ED_info.h @@ -31,9 +31,9 @@ struct Main; /* info_stats.c */ void ED_info_stats_clear(struct ViewLayer *view_layer); -const char *ED_info_stats_string(struct Main *bmain, - struct Scene *scene, - struct ViewLayer *view_layer); +const char *ED_info_footer_string(struct ViewLayer *view_layer); +void ED_info_draw_stats( + Main *bmain, Scene *scene, ViewLayer *view_layer, int x, int *y, int height); #ifdef __cplusplus } diff --git a/source/blender/editors/include/ED_keyframes_edit.h b/source/blender/editors/include/ED_keyframes_edit.h index 3ae0c254000..28bc0b22790 100644 --- a/source/blender/editors/include/ED_keyframes_edit.h +++ b/source/blender/editors/include/ED_keyframes_edit.h @@ -24,12 +24,12 @@ #ifndef __ED_KEYFRAMES_EDIT_H__ #define __ED_KEYFRAMES_EDIT_H__ +#include "ED_anim_api.h" /* for enum eAnimFilter_Flags */ + #ifdef __cplusplus extern "C" { #endif -#include "ED_anim_api.h" /* for enum eAnimFilter_Flags */ - struct BezTriple; struct FCurve; struct Scene; @@ -106,8 +106,8 @@ typedef enum eEditKeyframes_Mirror { typedef struct KeyframeEdit_LassoData { rctf *rectf_scaled; const rctf *rectf_view; - const int (*mcords)[2]; - int mcords_tot; + const int (*mcoords)[2]; + int mcoords_len; } KeyframeEdit_LassoData; /* use with BEZT_OK_REGION_CIRCLE */ diff --git a/source/blender/editors/include/ED_keyframing.h b/source/blender/editors/include/ED_keyframing.h index 4225ecc6f3d..5635ef2800a 100644 --- a/source/blender/editors/include/ED_keyframing.h +++ b/source/blender/editors/include/ED_keyframing.h @@ -24,6 +24,9 @@ #ifndef __ED_KEYFRAMING_H__ #define __ED_KEYFRAMING_H__ +#include "DNA_anim_types.h" +#include "RNA_types.h" + #ifdef __cplusplus extern "C" { #endif @@ -50,9 +53,6 @@ struct PropertyRNA; struct NlaKeyframingContext; -#include "DNA_anim_types.h" -#include "RNA_types.h" - /* ************ Keyframing Management **************** */ /* Get the active settings for keyframing settings from context (specifically the given scene) diff --git a/source/blender/editors/include/ED_node.h b/source/blender/editors/include/ED_node.h index 7a1f64b61d4..1dc98cfee2f 100644 --- a/source/blender/editors/include/ED_node.h +++ b/source/blender/editors/include/ED_node.h @@ -37,6 +37,7 @@ struct Tex; struct View2D; struct bContext; struct bNode; +struct bNodeSocket; struct bNodeSocketType; struct bNodeTree; struct bNodeTree; @@ -79,6 +80,10 @@ void ED_node_draw_snap( struct View2D *v2d, const float cent[2], float size, NodeBorder border, unsigned int pos); /* node_draw.c */ +void ED_node_socket_draw(struct bNodeSocket *sock, + const struct rcti *rect, + const float color[4], + float scale); void ED_node_tree_update(const struct bContext *C); void ED_node_tag_update_id(struct ID *id); void ED_node_tag_update_nodetree(struct Main *bmain, struct bNodeTree *ntree, struct bNode *node); @@ -94,6 +99,7 @@ void ED_node_set_tree_type(struct SpaceNode *snode, struct bNodeTreeType *typein bool ED_node_is_compositor(struct SpaceNode *snode); bool ED_node_is_shader(struct SpaceNode *snode); bool ED_node_is_texture(struct SpaceNode *snode); +bool ED_node_is_simulation(struct SpaceNode *snode); void ED_node_shader_default(const struct bContext *C, struct ID *id); void ED_node_composit_default(const struct bContext *C, struct Scene *scene); diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h index 13a0dd1ffd2..e6d39d5f966 100644 --- a/source/blender/editors/include/ED_object.h +++ b/source/blender/editors/include/ED_object.h @@ -24,6 +24,9 @@ #ifndef __ED_OBJECT_H__ #define __ED_OBJECT_H__ +#include "BLI_compiler_attrs.h" +#include "DNA_object_enums.h" + #ifdef __cplusplus extern "C" { #endif @@ -54,9 +57,6 @@ struct wmOperator; struct wmOperatorType; struct wmWindowManager; -#include "BLI_compiler_attrs.h" -#include "DNA_object_enums.h" - /* object_edit.c */ /* context.object */ struct Object *ED_object_context(struct bContext *C); diff --git a/source/blender/editors/include/ED_outliner.h b/source/blender/editors/include/ED_outliner.h index beed0f98fb5..d3fc5174dd9 100644 --- a/source/blender/editors/include/ED_outliner.h +++ b/source/blender/editors/include/ED_outliner.h @@ -27,9 +27,9 @@ extern "C" { #endif +struct Base; struct ListBase; struct bContext; -struct Base; bool ED_outliner_collections_editor_poll(struct bContext *C); diff --git a/source/blender/editors/include/ED_particle.h b/source/blender/editors/include/ED_particle.h index c8a4dc5b49d..789db5ae56e 100644 --- a/source/blender/editors/include/ED_particle.h +++ b/source/blender/editors/include/ED_particle.h @@ -71,8 +71,8 @@ bool PE_mouse_particles( bool PE_box_select(struct bContext *C, const struct rcti *rect, const int sel_op); bool PE_circle_select(struct bContext *C, const int sel_op, const int mval[2], float rad); int PE_lasso_select(struct bContext *C, - const int mcords[][2], - const short moves, + const int mcoords[][2], + const int mcoords_len, const int sel_op); bool PE_deselect_all_visible_ex(struct PTCacheEdit *edit); bool PE_deselect_all_visible(struct bContext *C); diff --git a/source/blender/editors/include/ED_transform.h b/source/blender/editors/include/ED_transform.h index beba4a7199b..9969acd04b7 100644 --- a/source/blender/editors/include/ED_transform.h +++ b/source/blender/editors/include/ED_transform.h @@ -157,6 +157,8 @@ int BIF_countTransformOrientation(const struct bContext *C); #define P_GPENCIL_EDIT (1 << 13) #define P_CURSOR_EDIT (1 << 14) #define P_CLNOR_INVALIDATE (1 << 15) +/* For properties performed when confirming the transformation. */ +#define P_POST_TRANSFORM (1 << 19) void Transform_Properties(struct wmOperatorType *ot, int flags); diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h index 6fdef4a06e0..452a1fca111 100644 --- a/source/blender/editors/include/UI_icons.h +++ b/source/blender/editors/include/UI_icons.h @@ -428,7 +428,7 @@ DEF_ICON(FORCE_CURVE) DEF_ICON(FORCE_BOID) DEF_ICON(FORCE_TURBULENCE) DEF_ICON(FORCE_DRAG) -DEF_ICON(FORCE_SMOKEFLOW) +DEF_ICON(FORCE_FLUIDFLOW) DEF_ICON_BLANK(673) DEF_ICON_BLANK(674) DEF_ICON(RIGID_BODY) diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index b8413fc86f9..3ad1608b47b 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -250,6 +250,8 @@ enum { UI_BUT_TEXT_RIGHT = 1 << 3, /** Prevent the button to show any tooltip. */ UI_BUT_NO_TOOLTIP = 1 << 4, + /** Do not add the usual horizontal padding for text drawing. */ + UI_BUT_NO_TEXT_PADDING = 1 << 5, /* Button align flag, for drawing groups together. * Used in 'uiBlock.flag', take care! */ @@ -500,15 +502,24 @@ typedef void (*uiButHandleRenameFunc)(struct bContext *C, void *arg, char *origs typedef void (*uiButHandleNFunc)(struct bContext *C, void *argN, void *arg2); typedef void (*uiButHandleHoldFunc)(struct bContext *C, struct ARegion *butregion, uiBut *but); typedef int (*uiButCompleteFunc)(struct bContext *C, char *str, void *arg); -typedef struct ARegion *(*uiButSearchCreateFunc)(struct bContext *C, - struct ARegion *butregion, - uiBut *but); -typedef void (*uiButSearchFunc)(const struct bContext *C, - void *arg, - const char *str, - uiSearchItems *items); -typedef void (*uiButSearchArgFreeFunc)(void *arg); +/* Search types. */ +typedef struct ARegion *(*uiButSearchCreateFn)(struct bContext *C, + struct ARegion *butregion, + uiBut *but); +typedef void (*uiButSearchUpdateFn)(const struct bContext *C, + void *arg, + const char *str, + uiSearchItems *items); +typedef void (*uiButSearchArgFreeFn)(void *arg); +typedef bool (*uiButSearchContextMenuFn)(struct bContext *C, + void *arg, + void *active, + const struct wmEvent *event); +typedef struct ARegion *(*uiButSearchTooltipFn)(struct bContext *C, + struct ARegion *region, + void *arg, + void *active); /* Must return allocated string. */ typedef char *(*uiButToolTipFunc)(struct bContext *C, void *argN, const char *tip); @@ -619,8 +630,7 @@ void UI_popup_block_invoke_ex(struct bContext *C, uiBlockCreateFunc func, void *arg, void (*arg_free)(void *arg), - const char *opname, - int opcontext); + bool can_refresh); void UI_popup_block_ex(struct bContext *C, uiBlockCreateFunc func, uiBlockHandleFunc popup_func, @@ -1570,21 +1580,25 @@ eAutoPropButsReturn uiDefAutoButsRNA(uiLayout *layout, /* use inside searchfunc to add items */ bool UI_search_item_add(uiSearchItems *items, const char *name, void *poin, int iconid, int state); -/* bfunc gets search item *poin as arg2, or if NULL the old string */ void UI_but_func_search_set(uiBut *but, - uiButSearchCreateFunc cfunc, - uiButSearchFunc sfunc, + uiButSearchCreateFn search_create_fn, + uiButSearchUpdateFn search_update_fn, void *arg, - uiButSearchArgFreeFunc search_arg_free_func, - uiButHandleFunc bfunc, - const char *search_sep_string, + uiButSearchArgFreeFn search_arg_free_fn, + uiButHandleFunc search_exec_fn, void *active); +void UI_but_func_search_set_context_menu(uiBut *but, uiButSearchContextMenuFn context_menu_fn); +void UI_but_func_search_set_tooltip(uiBut *but, uiButSearchTooltipFn tooltip_fn); +void UI_but_func_search_set_sep_string(uiBut *but, const char *search_sep_string); + /* height in pixels, it's using hardcoded values still */ int UI_searchbox_size_y(void); int UI_searchbox_size_x(void); /* check if a string is in an existing search box */ int UI_search_items_find_index(uiSearchItems *items, const char *name); +void UI_but_node_link_set(uiBut *but, struct bNodeSocket *socket, const float draw_color[4]); + void UI_block_func_handle_set(uiBlock *block, uiBlockHandleFunc func, void *arg); void UI_block_func_butmenu_set(uiBlock *block, uiMenuHandleFunc func, void *arg); void UI_block_func_set(uiBlock *block, uiButHandleFunc func, void *arg1, void *arg2); @@ -1668,6 +1682,7 @@ void UI_panel_end(const struct ScrArea *area, void UI_panels_scale(struct ARegion *region, float new_width); void UI_panel_label_offset(struct uiBlock *block, int *r_x, int *r_y); int UI_panel_size_y(const struct Panel *panel); +bool UI_panel_is_dragging(const struct Panel *panel); bool UI_panel_category_is_visible(const struct ARegion *region); void UI_panel_category_add(struct ARegion *region, const char *name); @@ -1772,6 +1787,10 @@ enum { UI_ITEM_O_DEPRESS = 1 << 10, UI_ITEM_R_COMPACT = 1 << 11, UI_ITEM_R_CHECKBOX_INVERT = 1 << 12, + /** Don't add a real decorator item, just blank space. */ + UI_ITEM_R_FORCE_BLANK_DECORATE = 1 << 13, + /* Even create the property split layout if there's no name to show there. */ + UI_ITEM_R_SPLIT_EMPTY_NAME = 1 << 14, }; #define UI_HEADER_OFFSET ((void)0, 0.4f * UI_UNIT_X) @@ -1782,6 +1801,9 @@ enum { UI_TEMPLATE_OP_PROPS_SHOW_EMPTY = 1 << 1, UI_TEMPLATE_OP_PROPS_COMPACT = 1 << 2, UI_TEMPLATE_OP_PROPS_HIDE_ADVANCED = 1 << 3, + /* Disable property split for the default layout (custom ui callbacks still have full control + * over the layout and can enable it). */ + UI_TEMPLATE_OP_PROPS_NO_SPLIT_LAYOUT = 1 << 4, }; /* used for transp checkers */ @@ -1869,7 +1891,9 @@ bool uiLayoutGetPropDecorate(uiLayout *layout); /* layout specifiers */ uiLayout *uiLayoutRow(uiLayout *layout, bool align); +uiLayout *uiLayoutRowWithHeading(uiLayout *layout, bool align, const char *heading); uiLayout *uiLayoutColumn(uiLayout *layout, bool align); +uiLayout *uiLayoutColumnWithHeading(uiLayout *layout, bool align, const char *heading); uiLayout *uiLayoutColumnFlow(uiLayout *layout, int number, bool align); uiLayout *uiLayoutGridFlow(uiLayout *layout, bool row_major, @@ -2044,11 +2068,11 @@ void uiTemplateOperatorSearch(uiLayout *layout); void UI_but_func_menu_search(uiBut *but); void uiTemplateMenuSearch(uiLayout *layout); -eAutoPropButsReturn uiTemplateOperatorPropertyButs(const struct bContext *C, - uiLayout *layout, - struct wmOperator *op, - const eButLabelAlign label_align, - const short flag); +void uiTemplateOperatorPropertyButs(const struct bContext *C, + uiLayout *layout, + struct wmOperator *op, + eButLabelAlign label_align, + short flag); void uiTemplateHeader3D_mode(uiLayout *layout, struct bContext *C); void uiTemplateEditModeSelection(uiLayout *layout, struct bContext *C); void uiTemplateReportsBanner(uiLayout *layout, struct bContext *C); @@ -2088,6 +2112,7 @@ void uiTemplateList(uiLayout *layout, bool sort_reverse, bool sort_lock); void uiTemplateNodeLink(uiLayout *layout, + struct bContext *C, struct bNodeTree *ntree, struct bNode *node, struct bNodeSocket *input); @@ -2297,6 +2322,14 @@ void uiItemsFullEnumO_items(uiLayout *layout, const EnumPropertyItem *item_array, int totitem); +typedef struct uiPropertySplitWrapper { + uiLayout *label_column; + uiLayout *property_row; + uiLayout *decorate_column; +} uiPropertySplitWrapper; + +uiPropertySplitWrapper uiItemPropertySplitWrapperCreate(uiLayout *parent_layout); + void uiItemL(uiLayout *layout, const char *name, int icon); /* label */ void uiItemL_ex( uiLayout *layout, const char *name, int icon, const bool highlight, const bool redalert); @@ -2308,6 +2341,9 @@ void uiItemM_ptr(uiLayout *layout, struct MenuType *mt, const char *name, int ic void uiItemM(uiLayout *layout, const char *menuname, const char *name, int icon); /* menu contents */ void uiItemMContents(uiLayout *layout, const char *menuname); +/* Decorators */ +void uiItemDecoratorR_prop(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop, int index); +void uiItemDecoratorR(uiLayout *layout, PointerRNA *ptr, const char *propname, int index); /* value */ void uiItemV(uiLayout *layout, const char *name, int icon, int argval); /* separator */ @@ -2375,6 +2411,7 @@ bool UI_context_copy_to_selected_list(struct bContext *C, /* Helpers for Operators */ uiBut *UI_context_active_but_get(const struct bContext *C); +uiBut *UI_context_active_but_get_respect_menu(const struct bContext *C); uiBut *UI_context_active_but_prop_get(const struct bContext *C, struct PointerRNA *r_ptr, struct PropertyRNA **r_prop, diff --git a/source/blender/editors/include/UI_resources.h b/source/blender/editors/include/UI_resources.h index b0995250979..c5c4ca79f14 100644 --- a/source/blender/editors/include/UI_resources.h +++ b/source/blender/editors/include/UI_resources.h @@ -26,10 +26,6 @@ #include "BLI_sys_types.h" -#ifdef __cplusplus -extern "C" { -#endif - /* Define icon enum. */ #define DEF_ICON(name) ICON_##name, #define DEF_ICON_VECTOR(name) ICON_##name, @@ -47,6 +43,10 @@ typedef enum { /* use to denote intentionally unset theme color */ #define TH_UNDEFINED -1 +#ifdef __cplusplus +extern "C" { +#endif + typedef enum ThemeColorID { TH_REDALERT, diff --git a/source/blender/editors/include/UI_view2d.h b/source/blender/editors/include/UI_view2d.h index d4db1b14074..ffc06e94a90 100644 --- a/source/blender/editors/include/UI_view2d.h +++ b/source/blender/editors/include/UI_view2d.h @@ -137,9 +137,9 @@ void UI_view2d_view_orthoSpecial(struct ARegion *region, struct View2D *v2d, con void UI_view2d_view_restore(const struct bContext *C); /* grid drawing */ -void UI_view2d_constant_grid_draw(struct View2D *v2d, float step); +void UI_view2d_constant_grid_draw(const struct View2D *v2d, float step); void UI_view2d_multi_grid_draw( - struct View2D *v2d, int colorid, float step, int level_size, int totlevels); + const struct View2D *v2d, int colorid, float step, int level_size, int totlevels); void UI_view2d_draw_lines_y__values(const struct View2D *v2d); void UI_view2d_draw_lines_x__values(const struct View2D *v2d); @@ -209,14 +209,17 @@ bool UI_view2d_view_to_region_clip( const struct View2D *v2d, float x, float y, int *r_region_x, int *r_region_y) ATTR_NONNULL(); void UI_view2d_view_to_region( - struct View2D *v2d, float x, float y, int *r_region_x, int *r_region_y) ATTR_NONNULL(); -void UI_view2d_view_to_region_fl( - struct View2D *v2d, float x, float y, float *r_region_x, float *r_region_y) ATTR_NONNULL(); -void UI_view2d_view_to_region_m4(struct View2D *v2d, float matrix[4][4]) ATTR_NONNULL(); -void UI_view2d_view_to_region_rcti(struct View2D *v2d, + const struct View2D *v2d, float x, float y, int *r_region_x, int *r_region_y) ATTR_NONNULL(); +void UI_view2d_view_to_region_fl(const struct View2D *v2d, + float x, + float y, + float *r_region_x, + float *r_region_y) ATTR_NONNULL(); +void UI_view2d_view_to_region_m4(const struct View2D *v2d, float matrix[4][4]) ATTR_NONNULL(); +void UI_view2d_view_to_region_rcti(const struct View2D *v2d, const struct rctf *rect_src, struct rcti *rect_dst) ATTR_NONNULL(); -bool UI_view2d_view_to_region_rcti_clip(struct View2D *v2d, +bool UI_view2d_view_to_region_rcti_clip(const struct View2D *v2d, const struct rctf *rect_src, struct rcti *rect_dst) ATTR_NONNULL(); @@ -228,9 +231,9 @@ void UI_view2d_scroller_size_get(const struct View2D *v2d, float *r_x, float *r_ void UI_view2d_scale_get(struct View2D *v2d, float *r_x, float *r_y); float UI_view2d_scale_get_x(const struct View2D *v2d); float UI_view2d_scale_get_y(const struct View2D *v2d); -void UI_view2d_scale_get_inverse(struct View2D *v2d, float *r_x, float *r_y); +void UI_view2d_scale_get_inverse(const struct View2D *v2d, float *r_x, float *r_y); -void UI_view2d_center_get(struct View2D *v2d, float *r_x, float *r_y); +void UI_view2d_center_get(const struct View2D *v2d, float *r_x, float *r_y); void UI_view2d_center_set(struct View2D *v2d, float x, float y); void UI_view2d_offset(struct View2D *v2d, float xfac, float yfac); diff --git a/source/blender/editors/interface/CMakeLists.txt b/source/blender/editors/interface/CMakeLists.txt index d33023c69a1..c2c27af9770 100644 --- a/source/blender/editors/interface/CMakeLists.txt +++ b/source/blender/editors/interface/CMakeLists.txt @@ -69,6 +69,9 @@ set(SRC interface_regions.c interface_style.c interface_templates.c + interface_template_search_menu.c + interface_template_search_operator.c + interface_undo.c interface_utils.c interface_widgets.c resources.c diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index 9ec660a9714..04c259ab092 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -641,6 +641,26 @@ static int ui_but_calc_float_precision(uiBut *but, double value) /* ************** BLOCK ENDING FUNCTION ************* */ +bool ui_but_rna_equals(const uiBut *a, const uiBut *b) +{ + return ui_but_rna_equals_ex(a, &b->rnapoin, b->rnaprop, b->rnaindex); +} + +bool ui_but_rna_equals_ex(const uiBut *but, + const PointerRNA *ptr, + const PropertyRNA *prop, + int index) +{ + if (but->rnapoin.data != ptr->data) { + return false; + } + if (but->rnaprop != prop || but->rnaindex != index) { + return false; + } + + return true; +} + /* NOTE: if but->poin is allocated memory for every defbut, things fail... */ static bool ui_but_equals_old(const uiBut *but, const uiBut *oldbut) { @@ -649,10 +669,7 @@ static bool ui_but_equals_old(const uiBut *but, const uiBut *oldbut) if (but->retval != oldbut->retval) { return false; } - if (but->rnapoin.data != oldbut->rnapoin.data) { - return false; - } - if (but->rnaprop != oldbut->rnaprop || but->rnaindex != oldbut->rnaindex) { + if (!ui_but_rna_equals(but, oldbut)) { return false; } if (but->func != oldbut->func) { @@ -790,8 +807,7 @@ static bool ui_but_update_from_old_block(const bContext *C, SWAP(ListBase, but->extra_op_icons, oldbut->extra_op_icons); - SWAP(uiButSearchArgFreeFunc, oldbut->search_arg_free_func, but->search_arg_free_func); - SWAP(void *, oldbut->search_arg, but->search_arg); + SWAP(struct uiButSearchData *, oldbut->search, but->search); /* copy hardmin for list rows to prevent 'sticking' highlight to mouse position * when scrolling without moving mouse (see [#28432]) */ @@ -979,7 +995,9 @@ static void ui_menu_block_set_keyaccels(uiBlock *block) UI_BTYPE_BUT_MENU, UI_BTYPE_MENU, UI_BTYPE_BLOCK, - UI_BTYPE_PULLDOWN) || + UI_BTYPE_PULLDOWN, + /* For PIE-menus. */ + UI_BTYPE_ROW) || (but->flag & UI_HIDDEN)) { /* pass */ } @@ -3208,9 +3226,12 @@ static void ui_but_free(const bContext *C, uiBut *but) MEM_freeN(but->hold_argN); } - if (but->search_arg_free_func) { - but->search_arg_free_func(but->search_arg); - but->search_arg = NULL; + if (but->search != NULL) { + if (but->search->arg_free_fn) { + but->search->arg_free_fn(but->search->arg); + but->search->arg = NULL; + } + MEM_freeN(but->search); } if (but->active) { @@ -6330,40 +6351,51 @@ uiBut *uiDefSearchBut(uiBlock *block, } /** - * \param search_func, bfunc: both get it as \a arg. - * \param arg: user value, - * \param active: when set, button opens with this item visible and selected. - * \param separator_string: when not NULL, this string is used as a separator, - * showing the icon and highlighted text after the last instance of this string. + * \note The item-pointer (referred to below) is a per search item user pointer + * passed to #UI_search_item_add (stored in #uiSearchItems.pointers). + * + * \param search_create_fn: Function to create the menu. + * \param search_update_fn: Function to refresh search content after the search text has changed. + * \param arg: user value. + * \param search_arg_free_fn: When non-null, use this function to free \a arg. + * \param search_exec_fn: Function that executes the action, gets \a arg as the first argument. + * The second argument as the active item-pointer + * \param active: When non-null, this item-pointer item will be visible and selected, + * otherwise the first item will be selected. */ void UI_but_func_search_set(uiBut *but, - uiButSearchCreateFunc search_create_func, - uiButSearchFunc search_func, + uiButSearchCreateFn search_create_fn, + uiButSearchUpdateFn search_update_fn, void *arg, - uiButSearchArgFreeFunc search_arg_free_func, - uiButHandleFunc bfunc, - const char *search_sep_string, + uiButSearchArgFreeFn search_arg_free_fn, + uiButHandleFunc search_exec_fn, void *active) { /* needed since callers don't have access to internal functions * (as an alternative we could expose it) */ - if (search_create_func == NULL) { - search_create_func = ui_searchbox_create_generic; + if (search_create_fn == NULL) { + search_create_fn = ui_searchbox_create_generic; } - if (but->search_arg_free_func != NULL) { - but->search_arg_free_func(but->search_arg); - but->search_arg = NULL; + struct uiButSearchData *search = but->search; + if (search != NULL) { + if (search->arg_free_fn != NULL) { + search->arg_free_fn(but->search->arg); + search->arg = NULL; + } + } + else { + search = MEM_callocN(sizeof(*but->search), __func__); + but->search = search; } - but->search_create_func = search_create_func; - but->search_func = search_func; + search->create_fn = search_create_fn; + search->update_fn = search_update_fn; - but->search_arg = arg; - but->search_arg_free_func = search_arg_free_func; - but->search_sep_string = search_sep_string; + search->arg = arg; + search->arg_free_fn = search_arg_free_fn; - if (bfunc) { + if (search_exec_fn) { #ifdef DEBUG if (but->func) { /* watch this, can be cause of much confusion, see: T47691 */ @@ -6371,7 +6403,7 @@ void UI_but_func_search_set(uiBut *but, __func__); } #endif - UI_but_func_set(but, bfunc, arg, active); + UI_but_func_set(but, search_exec_fn, search->arg, active); } /* search buttons show red-alert if item doesn't exist, not for menus */ @@ -6383,11 +6415,33 @@ void UI_but_func_search_set(uiBut *but, } } +void UI_but_func_search_set_context_menu(uiBut *but, uiButSearchContextMenuFn context_menu_fn) +{ + struct uiButSearchData *search = but->search; + search->context_menu_fn = context_menu_fn; +} + +/** + * \param separator_string: when not NULL, this string is used as a separator, + * showing the icon and highlighted text after the last instance of this string. + */ +void UI_but_func_search_set_sep_string(uiBut *but, const char *search_sep_string) +{ + struct uiButSearchData *search = but->search; + search->sep_string = search_sep_string; +} + +void UI_but_func_search_set_tooltip(uiBut *but, uiButSearchTooltipFn tooltip_fn) +{ + struct uiButSearchData *search = but->search; + search->tooltip_fn = tooltip_fn; +} + /* Callbacks for operator search button. */ -static void operator_enum_search_cb(const struct bContext *C, - void *but, - const char *str, - uiSearchItems *items) +static void operator_enum_search_update_fn(const struct bContext *C, + void *but, + const char *str, + uiSearchItems *items) { wmOperatorType *ot = ((uiBut *)but)->optype; PropertyRNA *prop = ot->prop; @@ -6424,7 +6478,7 @@ static void operator_enum_search_cb(const struct bContext *C, } } -static void operator_enum_call_cb(struct bContext *UNUSED(C), void *but, void *arg2) +static void operator_enum_search_exec_fn(struct bContext *UNUSED(C), void *but, void *arg2) { wmOperatorType *ot = ((uiBut *)but)->optype; PointerRNA *opptr = UI_but_operator_ptr_get(but); /* Will create it if needed! */ @@ -6467,11 +6521,10 @@ uiBut *uiDefSearchButO_ptr(uiBlock *block, but = uiDefSearchBut(block, arg, retval, icon, maxlen, x, y, width, height, a1, a2, tip); UI_but_func_search_set(but, ui_searchbox_create_generic, - operator_enum_search_cb, + operator_enum_search_update_fn, but, NULL, - operator_enum_call_cb, - NULL, + operator_enum_search_exec_fn, NULL); but->optype = ot; @@ -6486,6 +6539,13 @@ uiBut *uiDefSearchButO_ptr(uiBlock *block, return but; } +void UI_but_node_link_set(uiBut *but, bNodeSocket *socket, const float draw_color[4]) +{ + but->flag |= UI_BUT_NODE_LINK; + but->custom_data = socket; + rgba_float_to_uchar(but->col, draw_color); +} + /** * push a new event onto event queue to activate the given button * (usually a text-field) upon entering a popup diff --git a/source/blender/editors/interface/interface_anim.c b/source/blender/editors/interface/interface_anim.c index 15fc23bc539..8c9768f523d 100644 --- a/source/blender/editors/interface/interface_anim.c +++ b/source/blender/editors/interface/interface_anim.c @@ -28,12 +28,14 @@ #include "DNA_scene_types.h" #include "DNA_screen_types.h" +#include "BLI_listbase.h" #include "BLI_string.h" #include "BLI_string_utf8.h" #include "BLI_utildefines.h" #include "BKE_context.h" #include "BKE_fcurve.h" +#include "BKE_fcurve_driver.h" #include "BKE_global.h" #include "BKE_main.h" #include "BKE_nla.h" @@ -114,10 +116,40 @@ void ui_but_anim_flag(uiBut *but, float cfra) } } +static uiBut *ui_but_anim_decorate_find_attached_button(uiBut *but_decorate) +{ + uiBut *but_iter = NULL; + + BLI_assert(UI_but_is_decorator(but_decorate)); + BLI_assert(but_decorate->rnasearchpoin.data && but_decorate->rnasearchprop); + + LISTBASE_CIRCULAR_BACKWARD_BEGIN (&but_decorate->block->buttons, but_iter, but_decorate->prev) { + if (but_iter != but_decorate && + ui_but_rna_equals_ex(but_iter, + &but_decorate->rnasearchpoin, + but_decorate->rnasearchprop, + POINTER_AS_INT(but_decorate->custom_data))) { + return but_iter; + } + } + LISTBASE_CIRCULAR_BACKWARD_END(&but_decorate->block->buttons, but_iter, but_decorate->prev); + + return NULL; +} + void ui_but_anim_decorate_update_from_flag(uiBut *but) { - BLI_assert(UI_but_is_decorator(but) && but->prev); - int flag = but->prev->flag; + const uiBut *but_anim = ui_but_anim_decorate_find_attached_button(but); + + if (!but_anim) { + printf("Could not find button with matching property to decorate (%s.%s)\n", + RNA_struct_identifier(but->rnasearchpoin.type), + RNA_property_identifier(but->rnasearchprop)); + return; + } + + int flag = but_anim->flag; + if (flag & UI_BUT_DRIVEN) { but->icon = ICON_DECORATE_DRIVER; } @@ -289,22 +321,26 @@ void ui_but_anim_paste_driver(bContext *C) void ui_but_anim_decorate_cb(bContext *C, void *arg_but, void *UNUSED(arg_dummy)) { wmWindowManager *wm = CTX_wm_manager(C); - uiBut *but = arg_but; - but = but->prev; + uiBut *but_decorate = arg_but; + uiBut *but_anim = ui_but_anim_decorate_find_attached_button(but_decorate); + + if (!but_anim) { + return; + } /* FIXME(campbell), swapping active pointer is weak. */ - SWAP(struct uiHandleButtonData *, but->active, but->next->active); + SWAP(struct uiHandleButtonData *, but_anim->active, but_decorate->active); wm->op_undo_depth++; - if (but->flag & UI_BUT_DRIVEN) { + if (but_anim->flag & UI_BUT_DRIVEN) { /* pass */ /* TODO: report? */ } - else if (but->flag & UI_BUT_ANIMATED_KEY) { + else if (but_anim->flag & UI_BUT_ANIMATED_KEY) { PointerRNA props_ptr; wmOperatorType *ot = WM_operatortype_find("ANIM_OT_keyframe_delete_button", false); WM_operator_properties_create_ptr(&props_ptr, ot); - RNA_boolean_set(&props_ptr, "all", but->rnaindex == -1); + RNA_boolean_set(&props_ptr, "all", but_anim->rnaindex == -1); WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &props_ptr); WM_operator_properties_free(&props_ptr); } @@ -312,11 +348,11 @@ void ui_but_anim_decorate_cb(bContext *C, void *arg_but, void *UNUSED(arg_dummy) PointerRNA props_ptr; wmOperatorType *ot = WM_operatortype_find("ANIM_OT_keyframe_insert_button", false); WM_operator_properties_create_ptr(&props_ptr, ot); - RNA_boolean_set(&props_ptr, "all", but->rnaindex == -1); + RNA_boolean_set(&props_ptr, "all", but_anim->rnaindex == -1); WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &props_ptr); WM_operator_properties_free(&props_ptr); } - SWAP(struct uiHandleButtonData *, but->active, but->next->active); + SWAP(struct uiHandleButtonData *, but_anim->active, but_decorate->active); wm->op_undo_depth--; } diff --git a/source/blender/editors/interface/interface_context_menu.c b/source/blender/editors/interface/interface_context_menu.c index 5245b724da4..cc370113422 100644 --- a/source/blender/editors/interface/interface_context_menu.c +++ b/source/blender/editors/interface/interface_context_menu.c @@ -962,7 +962,7 @@ bool ui_popup_context_menu_for_button(bContext *C, uiBut *but) const PropertyType prop_type = RNA_property_type(but->rnaprop); if (((prop_type == PROP_POINTER) || (prop_type == PROP_STRING && but->type == UI_BTYPE_SEARCH_MENU && - but->search_func == ui_rna_collection_search_cb)) && + but->search->update_fn == ui_rna_collection_search_update_fn)) && ui_jump_to_target_button_poll(C)) { uiItemO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Jump to Target"), diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index c7cbe7f75f5..eb99d044e17 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -381,6 +381,9 @@ typedef struct uiHandleButtonData { uiSelectContextStore select_others; #endif + /* Text field undo. */ + struct uiUndoStack_Text *undo_stack_text; + /* post activate */ uiButtonActivateType posttype; uiBut *postbut; @@ -417,7 +420,7 @@ typedef struct uiAfterFunc { PropertyRNA *rnaprop; void *search_arg; - uiButSearchArgFreeFunc search_arg_free_func; + uiButSearchArgFreeFn search_arg_free_fn; bContextStore *context; @@ -753,10 +756,12 @@ static void ui_apply_but_func(bContext *C, uiBut *but) after->rnapoin = but->rnapoin; after->rnaprop = but->rnaprop; - after->search_arg_free_func = but->search_arg_free_func; - after->search_arg = but->search_arg; - but->search_arg_free_func = NULL; - but->search_arg = NULL; + if (but->search != NULL) { + after->search_arg_free_fn = but->search->arg_free_fn; + after->search_arg = but->search->arg; + but->search->arg_free_fn = NULL; + but->search->arg = NULL; + } if (but->context) { after->context = CTX_store_copy(but->context); @@ -924,8 +929,8 @@ static void ui_apply_but_funcs_after(bContext *C) MEM_freeN(after.rename_orig); } - if (after.search_arg_free_func) { - after.search_arg_free_func(after.search_arg); + if (after.search_arg_free_fn) { + after.search_arg_free_fn(after.search_arg); } ui_afterfunc_update_preferences_dirty(&after); @@ -2848,6 +2853,23 @@ static bool ui_textedit_delete_selection(uiBut *but, uiHandleButtonData *data) return changed; } +static bool ui_textedit_set_cursor_pos_foreach_glyph(const char *UNUSED(str), + const size_t str_step_ofs, + const rcti *glyph_step_bounds, + const int UNUSED(glyph_advance_x), + const rctf *glyph_bounds, + const int UNUSED(glyph_bearing[2]), + void *user_data) +{ + int *cursor_data = user_data; + float center = glyph_step_bounds->xmin + (BLI_rctf_size_x(glyph_bounds) / 2.0f); + if (cursor_data[0] < center) { + cursor_data[1] = str_step_ofs; + return false; + } + return true; +} + /** * \param x: Screen space cursor location - #wmEvent.x * @@ -2883,8 +2905,7 @@ static void ui_textedit_set_cursor_pos(uiBut *but, uiHandleButtonData *data, con startx += UI_DPI_ICON_SIZE / aspect; } } - /* But this extra .05 makes clicks in between characters feel nicer. */ - startx += ((UI_TEXT_MARGIN_X + 0.05f) * U.widget_unit) / aspect; + startx += (UI_TEXT_MARGIN_X * U.widget_unit) / aspect; /* mouse dragged outside the widget to the left */ if (x < startx) { @@ -2907,48 +2928,24 @@ static void ui_textedit_set_cursor_pos(uiBut *but, uiHandleButtonData *data, con but->pos = but->ofs; } /* mouse inside the widget, mouse coords mapped in widget space */ - else { /* (x >= startx) */ - int pos_i; - - /* keep track of previous distance from the cursor to the char */ - float cdist, cdist_prev = 0.0f; - short pos_prev; - - str_last = &str[strlen(str)]; - - but->pos = pos_prev = ((str_last - str) - but->ofs); - - while (true) { - cdist = startx + BLF_width(fstyle.uifont_id, str + but->ofs, (str_last - str) - but->ofs); - - /* check if position is found */ - if (cdist < x) { - /* check is previous location was in fact closer */ - if ((x - cdist) > (cdist_prev - x)) { - but->pos = pos_prev; - } - break; - } - cdist_prev = cdist; - pos_prev = but->pos; - /* done with tricky distance checks */ - - pos_i = but->pos; - if (but->pos <= 0) { - break; - } - if (BLI_str_cursor_step_prev_utf8(str + but->ofs, but->ofs, &pos_i)) { - but->pos = pos_i; - str_last = &str[but->pos + but->ofs]; - } - else { - break; /* unlikely but possible */ - } - } - but->pos += but->ofs; - if (but->pos < 0) { - but->pos = 0; - } + else { + str_last = &str[but->ofs]; + const int str_last_len = strlen(str_last); + int x_pos = (int)(x - startx); + int glyph_data[2] = { + x_pos, /* horizontal position to test. */ + -1, /* Write the character offset here. */ + }; + BLF_boundbox_foreach_glyph(fstyle.uifont_id, + str + but->ofs, + INT_MAX, + ui_textedit_set_cursor_pos_foreach_glyph, + glyph_data); + /* If value untouched then we are to the right. */ + if (glyph_data[1] == -1) { + glyph_data[1] = str_last_len; + } + but->pos = glyph_data[1] + but->ofs; } if (fstyle.kerning == 1) { @@ -3314,9 +3311,13 @@ static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data) but->selsta = 0; but->selend = len; + /* Initialize undo history tracking. */ + data->undo_stack_text = ui_textedit_undo_stack_create(); + ui_textedit_undo_push(data->undo_stack_text, but->editstr, but->pos); + /* optional searchbox */ if (but->type == UI_BTYPE_SEARCH_MENU) { - data->searchbox = but->search_create_func(C, data->region, but); + data->searchbox = but->search->create_fn(C, data->region, but); ui_searchbox_update(C, data->searchbox, but, true); /* true = reset */ } @@ -3356,6 +3357,9 @@ static void ui_textedit_end(bContext *C, uiBut *but, uiHandleButtonData *data) /* ensure menu (popup) too is closed! */ data->escapecancel = true; + + WM_reportf(RPT_ERROR, "Failed to find '%s'", but->editstr); + WM_report_banner_show(); } } @@ -3369,6 +3373,10 @@ static void ui_textedit_end(bContext *C, uiBut *but, uiHandleButtonData *data) WM_cursor_modal_restore(win); + /* Free text undo history text blocks. */ + ui_textedit_undo_stack_destroy(data->undo_stack_text); + data->undo_stack_text = NULL; + #ifdef WITH_INPUT_IME if (win->ime_data) { ui_textedit_ime_end(win, but); @@ -3448,7 +3456,7 @@ static void ui_do_but_textedit( bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event) { int retval = WM_UI_HANDLER_CONTINUE; - bool changed = false, inbox = false, update = false; + bool changed = false, inbox = false, update = false, skip_undo_push = false; #ifdef WITH_INPUT_IME wmWindow *win = CTX_wm_window(C); @@ -3468,7 +3476,7 @@ static void ui_do_but_textedit( /* pass */ } else { - ui_searchbox_event(C, data->searchbox, but, event); + ui_searchbox_event(C, data->searchbox, but, data->region, event); } #else ui_searchbox_event(C, data->searchbox, but, event); @@ -3479,6 +3487,16 @@ static void ui_do_but_textedit( case RIGHTMOUSE: case EVT_ESCKEY: if (event->val == KM_PRESS) { + /* Support search context menu. */ + if (event->type == RIGHTMOUSE) { + if (data->searchbox) { + if (ui_searchbox_event(C, data->searchbox, but, data->region, event)) { + /* Only break if the event was handled. */ + break; + } + } + } + #ifdef WITH_INPUT_IME /* skips button handling since it is not wanted */ if (is_ime_composing) { @@ -3587,7 +3605,7 @@ static void ui_do_but_textedit( #ifdef USE_KEYNAV_LIMIT ui_mouse_motion_keynav_init(&data->searchbox_keynav_state, event); #endif - ui_searchbox_event(C, data->searchbox, but, event); + ui_searchbox_event(C, data->searchbox, but, data->region, event); break; } if (event->type == WHEELDOWNMOUSE) { @@ -3604,7 +3622,7 @@ static void ui_do_but_textedit( #ifdef USE_KEYNAV_LIMIT ui_mouse_motion_keynav_init(&data->searchbox_keynav_state, event); #endif - ui_searchbox_event(C, data->searchbox, but, event); + ui_searchbox_event(C, data->searchbox, but, data->region, event); break; } if (event->type == WHEELUPMOUSE) { @@ -3670,6 +3688,32 @@ static void ui_do_but_textedit( } retval = WM_UI_HANDLER_BREAK; break; + case EVT_ZKEY: { + /* Ctrl-Z or Ctrl-Shift-Z: Undo/Redo (allowing for OS-Key on Apple). */ + + const bool is_redo = (event->shift != 0); + if ( +#if defined(__APPLE__) + (event->oskey && !IS_EVENT_MOD(event, alt, ctrl)) || +#endif + (event->ctrl && !IS_EVENT_MOD(event, alt, oskey))) { + int undo_pos; + const char *undo_str = ui_textedit_undo( + data->undo_stack_text, is_redo ? 1 : -1, &undo_pos); + if (undo_str != NULL) { + ui_textedit_string_set(but, data, undo_str); + + /* Set the cursor & clear selection. */ + but->pos = undo_pos; + but->selsta = but->pos; + but->selend = but->pos; + changed = true; + } + retval = WM_UI_HANDLER_BREAK; + skip_undo_push = true; + } + break; + } } if ((event->ascii || event->utf8_buf[0]) && (retval == WM_UI_HANDLER_CONTINUE) @@ -3723,6 +3767,11 @@ static void ui_do_but_textedit( #endif if (changed) { + /* The undo stack may be NULL if an event exits editing. */ + if ((skip_undo_push == false) && (data->undo_stack_text != NULL)) { + ui_textedit_undo_push(data->undo_stack_text, data->str, but->pos); + } + /* only do live update when but flag request it (UI_BUT_TEXTEDIT_UPDATE). */ if (update && data->interactive) { ui_apply_but(C, block, but, data, true); @@ -4397,7 +4446,8 @@ static int ui_do_but_TOG(bContext *C, uiBut *but, uiHandleButtonData *data, cons do_activate = (event->val == KM_RELEASE); } else { - do_activate = (event->val == KM_PRESS); + /* Also use double-clicks to prevent fast clicks to leak to other handlers (T76481). */ + do_activate = ELEM(event->val, KM_PRESS, KM_DBL_CLICK); } } @@ -8213,11 +8263,22 @@ static uiBut *ui_context_rna_button_active(const bContext *C) return ui_context_button_active(CTX_wm_region(C), ui_context_rna_button_active_test); } -uiBut *UI_context_active_but_get(const struct bContext *C) +uiBut *UI_context_active_but_get(const bContext *C) { return ui_context_button_active(CTX_wm_region(C), NULL); } +/* + * Version of #UI_context_active_get() that uses the result of #CTX_wm_menu() + * if set. Does not traverse into parent menus, which may be wanted in some + * cases. + */ +uiBut *UI_context_active_but_get_respect_menu(const bContext *C) +{ + ARegion *ar_menu = CTX_wm_menu(C); + return ui_context_button_active(ar_menu ? ar_menu : CTX_wm_region(C), NULL); +} + uiBut *UI_region_active_but_get(ARegion *region) { return ui_context_button_active(region, NULL); @@ -8819,7 +8880,7 @@ static int ui_handle_button_event(bContext *C, const wmEvent *event, uiBut *but) * This is needed to make sure if a button was active, * it stays active while the mouse is over it. * This avoids adding mousemoves, see: [#33466] */ - if (ELEM(state_orig, BUTTON_STATE_INIT, BUTTON_STATE_HIGHLIGHT)) { + if (ELEM(state_orig, BUTTON_STATE_INIT, BUTTON_STATE_HIGHLIGHT, BUTTON_STATE_WAIT_DRAG)) { if (ui_but_find_mouse_over(region, event) == but) { button_activate_init(C, region, but, BUTTON_ACTIVATE_OVER); } @@ -9344,6 +9405,11 @@ static int ui_handle_menu_button(bContext *C, const wmEvent *event, uiPopupBlock if (event->val == KM_RELEASE) { /* pass, needed so we can exit active menu-items when click-dragging out of them */ } + else if (but->type == UI_BTYPE_SEARCH_MENU) { + /* Pass, needed so search popup can have RMB context menu. + * This may be useful for other interactions which happen in the search popup + * without being directly over the search button. */ + } else if (!ui_block_is_menu(but->block) || ui_block_is_pie_menu(but->block)) { /* pass, skip for dialogs */ } @@ -10777,9 +10843,6 @@ static int ui_popup_handler(bContext *C, const wmEvent *event, void *userdata) if (temp.popup_func) { temp.popup_func(C, temp.popup_arg, temp.retvalue); } - if (temp.optype) { - WM_operator_name_call_ptr(C, temp.optype, temp.opcontext, NULL); - } } else if (temp.cancel_func) { temp.cancel_func(C, temp.popup_arg); diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c index 9f9e04eea82..c94a95890c0 100644 --- a/source/blender/editors/interface/interface_icons.c +++ b/source/blender/editors/interface/interface_icons.c @@ -2320,6 +2320,9 @@ int UI_idcode_icon_get(const int idcode) return ICON_WORLD_DATA; case ID_WS: return ICON_WORKSPACE; + case ID_SIM: + /* TODO: Use correct icon. */ + return ICON_PHYSICS; default: return ICON_NONE; } diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index 3ded62dca7f..5b68ccf9e7c 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -41,6 +41,7 @@ struct bContextStore; struct uiHandleButtonData; struct uiLayout; struct uiStyle; +struct uiUndoStack_Text; struct uiWidgetColors; struct wmEvent; struct wmKeyConfig; @@ -104,7 +105,6 @@ extern const char ui_radial_dir_to_numpad[8]; extern const short ui_radial_dir_to_angle[8]; /* internal panel drawing defines */ -#define PNL_GRID (UI_UNIT_Y / 5) /* 4 default */ #define PNL_HEADER (UI_UNIT_Y * 1.2) /* 24 default */ /* bit button defines */ @@ -147,6 +147,17 @@ enum { /* max amount of items a radial menu (pie menu) can contain */ #define PIE_MAX_ITEMS 8 +struct uiButSearchData { + uiButSearchCreateFn create_fn; + uiButSearchUpdateFn update_fn; + void *arg; + uiButSearchArgFreeFn arg_free_fn; + uiButSearchContextMenuFn context_menu_fn; + uiButSearchTooltipFn tooltip_fn; + + const char *sep_string; +}; + struct uiBut { struct uiBut *next, *prev; int flag, drawflag; @@ -203,11 +214,7 @@ struct uiBut { uiButCompleteFunc autocomplete_func; void *autofunc_arg; - uiButSearchCreateFunc search_create_func; - uiButSearchFunc search_func; - void *search_arg; - uiButSearchArgFreeFunc search_arg_free_func; - const char *search_sep_string; + struct uiButSearchData *search; uiButHandleRenameFunc rename_func; void *rename_arg1; @@ -601,10 +608,8 @@ struct uiPopupBlockHandle { /* for operator popups */ struct wmOperator *popup_op; - struct wmOperatorType *optype; struct ScrArea *ctx_area; struct ARegion *ctx_region; - int opcontext; /* return values */ int butretval; @@ -666,9 +671,10 @@ bool ui_searchbox_inside(struct ARegion *region, int x, int y); int ui_searchbox_find_index(struct ARegion *region, const char *name); void ui_searchbox_update(struct bContext *C, struct ARegion *region, uiBut *but, const bool reset); int ui_searchbox_autocomplete(struct bContext *C, struct ARegion *region, uiBut *but, char *str); -void ui_searchbox_event(struct bContext *C, +bool ui_searchbox_event(struct bContext *C, struct ARegion *region, uiBut *but, + struct ARegion *butregion, const struct wmEvent *event); bool ui_searchbox_apply(uiBut *but, struct ARegion *region); void ui_searchbox_free(struct bContext *C, struct ARegion *region); @@ -709,7 +715,7 @@ uiPopupBlockHandle *ui_popover_panel_create(struct bContext *C, void ui_pie_menu_level_create(uiBlock *block, struct wmOperatorType *ot, const char *propname, - IDProperty *properties, + struct IDProperty *properties, const EnumPropertyItem *items, int totitem, int context, @@ -774,6 +780,16 @@ void ui_draw_but_TRACKPREVIEW(struct ARegion *region, const struct uiWidgetColors *wcol, const rcti *rect); +/* interface_undo.c */ +struct uiUndoStack_Text *ui_textedit_undo_stack_create(void); +void ui_textedit_undo_stack_destroy(struct uiUndoStack_Text *undo_stack); +void ui_textedit_undo_push(struct uiUndoStack_Text *undo_stack, + const char *text, + int cursor_index); +const char *ui_textedit_undo(struct uiUndoStack_Text *undo_stack, + int direction, + int *r_cursor_index); + /* interface_handlers.c */ PointerRNA *ui_handle_afterfunc_add_operator(struct wmOperatorType *ot, int opcontext, @@ -800,6 +816,11 @@ float ui_block_calc_pie_segment(struct uiBlock *block, const float event_xy[2]); void ui_but_add_shortcut(uiBut *but, const char *key_str, const bool do_strip); void ui_but_clipboard_free(void); +bool ui_but_rna_equals(const uiBut *a, const uiBut *b); +bool ui_but_rna_equals_ex(const uiBut *but, + const PointerRNA *ptr, + const PropertyRNA *prop, + int index); uiBut *ui_but_find_old(uiBlock *block_old, const uiBut *but_new); uiBut *ui_but_find_new(uiBlock *block_old, const uiBut *but_new); @@ -869,7 +890,7 @@ void ui_draw_menu_item(const struct uiFontStyle *fstyle, int iconid, int state, bool use_sep, - int *r_name_width); + int *r_xmax); void ui_draw_preview_item( const struct uiFontStyle *fstyle, rcti *rect, const char *name, int iconid, int state); @@ -1023,9 +1044,10 @@ void UI_OT_eyedropper_driver(struct wmOperatorType *ot); void UI_OT_eyedropper_gpencil_color(struct wmOperatorType *ot); /* interface_util.c */ +bool ui_str_has_word_prefix(const char *haystack, const char *needle, size_t needle_len); /** - * For use with #ui_rna_collection_search_cb. + * For use with #ui_rna_collection_search_update_fn. */ typedef struct uiRNACollectionSearch { PointerRNA target_ptr; @@ -1040,10 +1062,10 @@ typedef struct uiRNACollectionSearch { /* Block has to be stored for freeing butstore (uiBut.block doesn't work with undo). */ uiBlock *butstore_block; } uiRNACollectionSearch; -void ui_rna_collection_search_cb(const struct bContext *C, - void *arg, - const char *str, - uiSearchItems *items); +void ui_rna_collection_search_update_fn(const struct bContext *C, + void *arg, + const char *str, + uiSearchItems *items); /* interface_ops.c */ bool ui_jump_to_target_button_poll(struct bContext *C); diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c index cbea32f179a..884e43b4026 100644 --- a/source/blender/editors/interface/interface_layout.c +++ b/source/blender/editors/interface/interface_layout.c @@ -75,7 +75,7 @@ } \ (void)0 -#define UI_ITEM_PROP_SEP_DIVIDE 0.5f +#define UI_ITEM_PROP_SEP_DIVIDE 0.4f /* uiLayoutRoot */ @@ -135,10 +135,11 @@ enum { UI_ITEM_BOX_ITEM = 1 << 2, /* The item is "inside" a box item */ UI_ITEM_PROP_SEP = 1 << 3, + UI_ITEM_INSIDE_PROP_SEP = 1 << 4, /* Show an icon button next to each property (to set keyframes, show status). * Enabled by default, depends on 'UI_ITEM_PROP_SEP'. */ - UI_ITEM_PROP_DECORATE = 1 << 4, - UI_ITEM_PROP_DECORATE_NO_PAD = 1 << 5, + UI_ITEM_PROP_DECORATE = 1 << 5, + UI_ITEM_PROP_DECORATE_NO_PAD = 1 << 6, }; typedef struct uiButtonItem { @@ -151,8 +152,11 @@ struct uiLayout { uiLayoutRoot *root; bContextStore *context; + uiLayout *parent; ListBase items; + char heading[UI_MAX_NAME_STR]; + /** Sub layout to add child items, if not the layout itself. */ uiLayout *child_items_layout; @@ -1780,6 +1784,7 @@ static void ui_item_rna_size(uiLayout *layout, PropertyType type; PropertySubType subtype; int len, w = 0, h; + bool is_checkbox_only = false; /* arbitrary extended width by type */ type = RNA_property_type(prop); @@ -1791,6 +1796,10 @@ static void ui_item_rna_size(uiLayout *layout, name = "non-empty text"; } else if (type == PROP_BOOLEAN) { + if (icon == ICON_NONE) { + /* Exception for checkboxes, they need a little less space to align nicely. */ + is_checkbox_only = true; + } icon = ICON_DOT; } else if (type == PROP_ENUM) { @@ -1850,6 +1859,9 @@ static void ui_item_rna_size(uiLayout *layout, if (type == PROP_BOOLEAN && name[0]) { w += UI_UNIT_X / 5; } + else if (is_checkbox_only) { + w -= UI_UNIT_X / 4; + } else if (type == PROP_ENUM && !icon_only) { w += UI_UNIT_X / 4; } @@ -1862,6 +1874,57 @@ static void ui_item_rna_size(uiLayout *layout, *r_h = h; } +static bool ui_item_rna_is_expand(PropertyRNA *prop, int index, int item_flag) +{ + const bool is_array = RNA_property_array_check(prop); + const int subtype = RNA_property_subtype(prop); + return is_array && (index == RNA_NO_INDEX) && + ((item_flag & UI_ITEM_R_EXPAND) || + !ELEM(subtype, PROP_COLOR, PROP_COLOR_GAMMA, PROP_DIRECTION)); +} + +/** + * Find first layout ancestor (or self) with a heading set. + * + * \returns the layout to add the heading to as fallback (i.e. if it can't be placed in a split + * layout). Its #uiLayout.heading member can be cleared to mark the heading as added (so + * it's not added multiple times). Returns a pointer to the heading + */ +static uiLayout *ui_layout_heading_find(uiLayout *cur_layout) +{ + for (uiLayout *parent = cur_layout; parent; parent = parent->parent) { + if (parent->heading[0]) { + return parent; + } + } + + return NULL; +} + +static void ui_layout_heading_label_add(uiLayout *layout, + uiLayout *heading_layout, + bool right_align, + bool respect_prop_split) +{ + const int prev_alignment = layout->alignment; + + if (right_align) { + uiLayoutSetAlignment(layout, UI_LAYOUT_ALIGN_RIGHT); + } + + if (respect_prop_split) { + uiItemL_respect_property_split(layout, heading_layout->heading, ICON_NONE); + } + else { + uiItemL(layout, heading_layout->heading, ICON_NONE); + } + /* After adding the heading label, we have to mark it somehow as added, so it's not added again + * for other items in this layout. For now just clear it. */ + heading_layout->heading[0] = '\0'; + + layout->alignment = prev_alignment; +} + /** * Hack to add further items in a row into the second part of the split layout, so the label part * keeps a fixed size. @@ -1869,7 +1932,14 @@ static void ui_item_rna_size(uiLayout *layout, */ static uiLayout *ui_item_prop_split_layout_hack(uiLayout *layout_parent, uiLayout *layout_split) { + /* Tag item as using property split layout, this is inherited to children so they can get special + * treatment if needed. */ + layout_parent->item.flag |= UI_ITEM_INSIDE_PROP_SEP; + if (layout_parent->item.type == ITEM_LAYOUT_ROW) { + /* Prevent further splits within the row. */ + uiLayoutSetPropSep(layout_parent, false); + layout_parent->child_items_layout = uiLayoutRow(layout_split, true); return layout_parent->child_items_layout; } @@ -1888,13 +1958,18 @@ void uiItemFullR(uiLayout *layout, uiBlock *block = layout->root->block; char namestr[UI_MAX_NAME_STR]; const bool use_prop_sep = ((layout->item.flag & UI_ITEM_PROP_SEP) != 0); - - /* By default 'use_prop_sep' uses a separate column for labels. - * This is an exception for check-boxes otherwise only the small checkbox region is clickable. + const bool inside_prop_sep = ((layout->item.flag & UI_ITEM_INSIDE_PROP_SEP) != 0); + /* Columns can define a heading to insert. If the first item added to a split layout doesn't have + * a label to display in the first column, the heading is inserted there. Otherwise it's inserted + * as a new row before the first item. */ + uiLayout *heading_layout = ui_layout_heading_find(layout); + /* Although checkboxes use the split layout, they are an exception and should only place their + * label in the second column, to not make that almost empty. * * Keep using 'use_prop_sep' instead of disabling it entirely because * we need the ability to have decorators still. */ bool use_prop_sep_split_label = use_prop_sep; + bool use_split_empty_name = (flag & UI_ITEM_R_SPLIT_EMPTY_NAME); #ifdef UI_PROP_DECORATE struct { @@ -2005,6 +2080,9 @@ void uiItemFullR(uiLayout *layout, if (use_prop_sep) { if (type == PROP_BOOLEAN && (icon == ICON_NONE) && !icon_only) { use_prop_sep_split_label = false; + /* For check-boxes we make an exception: We allow showing them in a split row even without + * label. It typically relates to its neighbor items, so no need for an extra label. */ + use_split_empty_name = true; } } #endif @@ -2031,6 +2109,7 @@ void uiItemFullR(uiLayout *layout, /* Split the label / property. */ uiLayout *layout_parent = layout; + if (use_prop_sep) { uiLayout *layout_row = NULL; #ifdef UI_PROP_DECORATE @@ -2041,21 +2120,26 @@ void uiItemFullR(uiLayout *layout, } #endif /* UI_PROP_DECORATE */ - if ((name[0] == '\0') || (use_prop_sep_split_label == false)) { + if ((name[0] == '\0') && !use_split_empty_name) { /* Ensure we get a column when text is not set. */ layout = uiLayoutColumn(layout_row ? layout_row : layout, true); layout->space = 0; + if (heading_layout) { + ui_layout_heading_label_add(layout, heading_layout, false, false); + } } else { - const PropertySubType subtype = RNA_property_subtype(prop); uiLayout *layout_split = uiLayoutSplit( layout_row ? layout_row : layout, UI_ITEM_PROP_SEP_DIVIDE, true); + bool label_added = false; layout_split->space = 0; uiLayout *layout_sub = uiLayoutColumn(layout_split, true); layout_sub->space = 0; - if ((index == RNA_NO_INDEX && is_array) && - ((!expand && ELEM(subtype, PROP_COLOR, PROP_COLOR_GAMMA, PROP_DIRECTION)) == 0)) { + if (!use_prop_sep_split_label) { + /* Pass */ + } + else if (ui_item_rna_is_expand(prop, index, flag)) { char name_with_suffix[UI_MAX_DRAW_STR + 2]; char str[2] = {'\0'}; for (int a = 0; a < len; a++) { @@ -2084,6 +2168,8 @@ void uiItemFullR(uiLayout *layout, ""); but->drawflag |= UI_BUT_TEXT_RIGHT; but->drawflag &= ~UI_BUT_TEXT_LEFT; + + label_added = true; } } else { @@ -2092,13 +2178,17 @@ void uiItemFullR(uiLayout *layout, block, UI_BTYPE_LABEL, 0, name, 0, 0, w, UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, ""); but->drawflag |= UI_BUT_TEXT_RIGHT; but->drawflag &= ~UI_BUT_TEXT_LEFT; + + label_added = true; } } - if (layout_parent) { - layout_split = ui_item_prop_split_layout_hack(layout_parent, layout_split); + if (!label_added && heading_layout) { + ui_layout_heading_label_add(layout_sub, heading_layout, true, false); } + layout_split = ui_item_prop_split_layout_hack(layout_parent, layout_split); + /* Watch out! We can only write into the new layout now. */ if ((type == PROP_ENUM) && (flag & UI_ITEM_R_EXPAND)) { /* Expanded enums each have their own name. */ @@ -2113,7 +2203,9 @@ void uiItemFullR(uiLayout *layout, } } else { - name = ""; + if (use_prop_sep_split_label) { + name = ""; + } layout = uiLayoutColumn(layout_split, true); } layout->space = 0; @@ -2132,9 +2224,20 @@ void uiItemFullR(uiLayout *layout, #endif /* UI_PROP_DECORATE */ } /* End split. */ + else if (heading_layout) { + /* Could not add heading to split layout, fallback to inserting it to the layout with the + * heading itself. */ + ui_layout_heading_label_add(heading_layout, heading_layout, false, false); + } /* array property */ if (index == RNA_NO_INDEX && is_array) { + if (inside_prop_sep) { + /* Within a split row, add array items to a column so they match the column layout of + * previous items (e.g. transform vector with lock icon for each item). */ + layout = uiLayoutColumn(layout, true); + } + ui_item_array(layout, block, name, @@ -2214,12 +2317,6 @@ void uiItemFullR(uiLayout *layout, if (layout->activate_init) { UI_but_flag_enable(but, UI_BUT_ACTIVATE_ON_INIT); } - - if (use_prop_sep && (use_prop_sep_split_label == false)) { - /* When the button uses it's own text right align it. */ - but->drawflag |= UI_BUT_TEXT_RIGHT; - but->drawflag &= ~UI_BUT_TEXT_LEFT; - } } /* The resulting button may have the icon set since boolean button drawing @@ -2242,50 +2339,21 @@ void uiItemFullR(uiLayout *layout, #ifdef UI_PROP_DECORATE if (ui_decorate.use_prop_decorate) { - const bool is_anim = RNA_property_animateable(ptr, prop); uiBut *but_decorate = ui_decorate.but ? ui_decorate.but->next : block->buttons.first; + const bool use_blank_decorator = (flag & UI_ITEM_R_FORCE_BLANK_DECORATE); uiLayout *layout_col = uiLayoutColumn(ui_decorate.layout, false); layout_col->space = 0; layout_col->emboss = UI_EMBOSS_NONE; + int i; for (i = 0; i < ui_decorate.len && but_decorate; i++) { + PointerRNA *ptr_dec = use_blank_decorator ? NULL : &but_decorate->rnapoin; + PropertyRNA *prop_dec = use_blank_decorator ? NULL : but_decorate->rnaprop; + /* The icons are set in 'ui_but_anim_flag' */ - if (is_anim) { - but = uiDefIconBut(block, - UI_BTYPE_BUT, - 0, - ICON_DOT, - 0, - 0, - UI_UNIT_X, - UI_UNIT_Y, - NULL, - 0.0, - 0.0, - 0.0, - 0.0, - TIP_("Animate property")); - UI_but_func_set(but, ui_but_anim_decorate_cb, but, NULL); - but->flag |= UI_BUT_UNDO | UI_BUT_DRAG_LOCK; - } - else { - /* We may show other information here in future, for now use empty space. */ - but = uiDefIconBut(block, - UI_BTYPE_BUT, - 0, - ICON_BLANK1, - 0, - 0, - UI_UNIT_X, - UI_UNIT_Y, - NULL, - 0.0, - 0.0, - 0.0, - 0.0, - ""); - but->flag |= UI_BUT_DISABLED; - } + uiItemDecoratorR_prop(layout_col, ptr_dec, prop_dec, but_decorate->rnaindex); + but = block->buttons.last; + /* Order the decorator after the button we decorate, this is used so we can always * do a quick lookup. */ BLI_remlink(&block->buttons, but); @@ -2577,7 +2645,7 @@ static void search_id_collection(StructRNA *ptype, PointerRNA *r_ptr, PropertyRN RNA_STRUCT_END; } -static void ui_rna_collection_search_free_cb(void *ptr) +static void ui_rna_collection_search_arg_free_fn(void *ptr) { uiRNACollectionSearch *coll_search = ptr; UI_butstore_free(coll_search->butstore_block, coll_search->butstore); @@ -2629,10 +2697,9 @@ void ui_but_add_search( UI_but_func_search_set(but, ui_searchbox_create_generic, - ui_rna_collection_search_cb, + ui_rna_collection_search_update_fn, coll_search, - ui_rna_collection_search_free_cb, - NULL, + ui_rna_collection_search_arg_free_fn, NULL, NULL); } @@ -2759,6 +2826,7 @@ static uiBut *ui_item_menu(uiLayout *layout, bool force_menu) { uiBlock *block = layout->root->block; + uiLayout *heading_layout = ui_layout_heading_find(layout); uiBut *but; int w, h; @@ -2788,6 +2856,10 @@ static uiBut *ui_item_menu(uiLayout *layout, } } + if (heading_layout) { + ui_layout_heading_label_add(layout, heading_layout, true, true); + } + if (name[0] && icon) { but = uiDefIconTextMenuBut(block, func, arg, icon, name, 0, 0, w, h, tip); } @@ -2861,6 +2933,91 @@ void uiItemMContents(uiLayout *layout, const char *menuname) UI_menutype_draw(C, mt, layout); } +/** + * Insert a decorator item for a button with the same property as \a prop. + * To force inserting a blank dummy element, NULL can be passed for \a ptr and \a prop. + */ +void uiItemDecoratorR_prop(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop, int index) +{ + uiBlock *block = layout->root->block; + uiBut *but = NULL; + + uiLayout *col; + UI_block_layout_set_current(block, layout); + col = uiLayoutColumn(layout, false); + col->space = 0; + col->emboss = UI_EMBOSS_NONE; + + if (ELEM(NULL, ptr, prop) || !RNA_property_animateable(ptr, prop)) { + but = uiDefIconBut(block, + UI_BTYPE_BUT, + 0, + ICON_BLANK1, + 0, + 0, + UI_UNIT_X, + UI_UNIT_Y, + NULL, + 0.0, + 0.0, + 0.0, + 0.0, + ""); + but->flag |= UI_BUT_DISABLED; + return; + } + + const bool is_expand = ui_item_rna_is_expand(prop, index, 0); + const bool is_array = RNA_property_array_check(prop); + + /* Loop for the array-case, but only do in case of an expanded array. */ + for (int i = 0; i < (is_expand ? RNA_property_array_length(ptr, prop) : 1); i++) { + but = uiDefIconBut(block, + UI_BTYPE_BUT, + 0, + ICON_DOT, + 0, + 0, + UI_UNIT_X, + UI_UNIT_Y, + NULL, + 0.0, + 0.0, + 0.0, + 0.0, + TIP_("Animate property")); + UI_but_func_set(but, ui_but_anim_decorate_cb, but, NULL); + but->flag |= UI_BUT_UNDO | UI_BUT_DRAG_LOCK; + /* Reusing RNA search members, setting actual RNA data has many side-effects. */ + but->rnasearchpoin = *ptr; + but->rnasearchprop = prop; + /* ui_def_but_rna() sets non-array buttons to have a RNA index of 0. */ + but->custom_data = POINTER_FROM_INT((!is_array || is_expand) ? i : index); + } +} + +/** + * Insert a decorator item for a button with the same property as \a prop. + * To force inserting a blank dummy element, NULL can be passed for \a ptr and \a propname. + */ +void uiItemDecoratorR(uiLayout *layout, PointerRNA *ptr, const char *propname, int index) +{ + PropertyRNA *prop = NULL; + + if (ptr && propname) { + /* validate arguments */ + prop = RNA_struct_find_property(ptr, propname); + if (!prop) { + ui_item_disabled(layout, propname); + RNA_warning("property not found: %s.%s", RNA_struct_identifier(ptr->type), propname); + return; + } + } + + /* ptr and prop are allowed to be NULL here. */ + uiItemDecoratorR_prop(layout, ptr, prop, index); +} + /* popover */ void uiItemPopoverPanel_ptr( uiLayout *layout, bContext *C, PanelType *pt, const char *name, int icon) @@ -3004,33 +3161,40 @@ void uiItemL(uiLayout *layout, const char *name, int icon) } /** - * Helper to add a label, which handles logic for split property layout if needed. - * - * Normally, we handle the split layout in #uiItemFullR(), but there are other cases where we may - * want to use the logic. For those this helper was added, although it will likely have to be - * extended to support more cases. - * Ideally, #uiItemFullR() could just call this, but it currently has too many special needs. - * - * \return A layout placed in the row after the split layout. Used to place decorator items. + * Normally, we handle the split layout in #uiItemFullR(), but there are other cases where the + * logic is needed. Ideally, #uiItemFullR() could just call this, but it currently has too many + * special needs. + */ +uiPropertySplitWrapper uiItemPropertySplitWrapperCreate(uiLayout *parent_layout) +{ + uiPropertySplitWrapper split_wrapper = {NULL}; + + uiLayout *layout_row = uiLayoutRow(parent_layout, true); + uiLayout *layout_split = uiLayoutSplit(layout_row, UI_ITEM_PROP_SEP_DIVIDE, true); + + layout_split->space = 0; + split_wrapper.label_column = uiLayoutColumn(layout_split, true); + split_wrapper.label_column->alignment = UI_LAYOUT_ALIGN_RIGHT; + split_wrapper.property_row = ui_item_prop_split_layout_hack(parent_layout, layout_split); + split_wrapper.decorate_column = uiLayoutColumn(layout_row, true); + + return split_wrapper; +} + +/* + * Helper to add a label and creates a property split layout if needed. */ uiLayout *uiItemL_respect_property_split(uiLayout *layout, const char *text, int icon) { if (layout->item.flag & UI_ITEM_PROP_SEP) { uiBlock *block = uiLayoutGetBlock(layout); - uiLayout *layout_row = uiLayoutRow(layout, true); - uiLayout *layout_split = uiLayoutSplit(layout_row, UI_ITEM_PROP_SEP_DIVIDE, true); - uiLayout *layout_sub = uiLayoutColumn(layout_split, true); - - layout_split->space = layout_sub->space = layout_row->space = 0; - layout_sub->alignment = UI_LAYOUT_ALIGN_RIGHT; + uiPropertySplitWrapper split_wrapper = uiItemPropertySplitWrapperCreate(layout); + /* Further items added to 'layout' will automatically be added to split_wrapper.property_row */ - uiItemL_(layout_sub, text, icon); + uiItemL_(split_wrapper.label_column, text, icon); + UI_block_layout_set_current(block, split_wrapper.property_row); - layout_split = ui_item_prop_split_layout_hack(layout, layout_split); - UI_block_layout_set_current(block, layout_split); - - /* Give caller a new sub-row to place items in. */ - return layout_row; + return split_wrapper.decorate_column; } else { char namestr[UI_MAX_NAME_STR]; @@ -4471,13 +4635,24 @@ static void ui_litem_init_from_parent(uiLayout *litem, uiLayout *layout, int ali litem->redalert = layout->redalert; litem->w = layout->w; litem->emboss = layout->emboss; - litem->item.flag = (layout->item.flag & (UI_ITEM_PROP_SEP | UI_ITEM_PROP_DECORATE)); + litem->item.flag = (layout->item.flag & + (UI_ITEM_PROP_SEP | UI_ITEM_PROP_DECORATE | UI_ITEM_INSIDE_PROP_SEP)); if (layout->child_items_layout) { BLI_addtail(&layout->child_items_layout->items, litem); + litem->parent = layout->child_items_layout; } else { BLI_addtail(&layout->items, litem); + litem->parent = layout; + } +} + +static void ui_layout_heading_set(uiLayout *layout, const char *heading) +{ + BLI_assert(layout->heading[0] == '\0'); + if (heading) { + STRNCPY(layout->heading, heading); } } @@ -4497,6 +4672,16 @@ uiLayout *uiLayoutRow(uiLayout *layout, bool align) return litem; } +/** + * See #uiLayoutColumnWithHeading(). + */ +uiLayout *uiLayoutRowWithHeading(uiLayout *layout, bool align, const char *heading) +{ + uiLayout *litem = uiLayoutRow(layout, align); + ui_layout_heading_set(litem, heading); + return litem; +} + uiLayout *uiLayoutColumn(uiLayout *layout, bool align) { uiLayout *litem; @@ -4512,6 +4697,19 @@ uiLayout *uiLayoutColumn(uiLayout *layout, bool align) return litem; } +/** + * Variant of #uiLayoutColumn() that sets a heading label for the layout if the first item is + * added through #uiItemFullR(). If split layout is used and the item has no string to add to the + * first split-column, the heading is added there instead. Otherwise the heading inserted with a + * new row. + */ +uiLayout *uiLayoutColumnWithHeading(uiLayout *layout, bool align, const char *heading) +{ + uiLayout *litem = uiLayoutColumn(layout, align); + ui_layout_heading_set(litem, heading); + return litem; +} + uiLayout *uiLayoutColumnFlow(uiLayout *layout, int number, bool align) { uiLayoutItemFlow *flow; diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c index 53ea51c9e97..909da434554 100644 --- a/source/blender/editors/interface/interface_ops.c +++ b/source/blender/editors/interface/interface_ops.c @@ -1135,8 +1135,9 @@ static bool jump_to_target_button(bContext *C, bool poll) else if (type == PROP_STRING) { const uiBut *but = UI_context_active_but_get(C); - if (but->type == UI_BTYPE_SEARCH_MENU && but->search_func == ui_rna_collection_search_cb) { - uiRNACollectionSearch *coll_search = but->search_arg; + if (but->type == UI_BTYPE_SEARCH_MENU && but->search && + but->search->update_fn == ui_rna_collection_search_update_fn) { + uiRNACollectionSearch *coll_search = but->search->arg; char str_buf[MAXBONENAME]; char *str_ptr = RNA_property_string_get_alloc(&ptr, prop, str_buf, sizeof(str_buf), NULL); @@ -1678,7 +1679,7 @@ static void UI_OT_button_execute(wmOperatorType *ot) static int button_string_clear_exec(bContext *C, wmOperator *UNUSED(op)) { - uiBut *but = UI_context_active_but_get(C); + uiBut *but = UI_context_active_but_get_respect_menu(C); if (but) { ui_but_active_string_clear_and_exit(C, but); diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c index 2ad1c25305c..c5f67e63bd3 100644 --- a/source/blender/editors/interface/interface_panel.c +++ b/source/blender/editors/interface/interface_panel.c @@ -102,6 +102,7 @@ typedef struct uiHandlePanelData { double starttime; /* dragging */ + bool is_drag_drop; int startx, starty; int startofsx, startofsy; int startsizex, startsizey; @@ -743,7 +744,7 @@ void ui_draw_aligned_panel(uiStyle *style, /* an open panel */ else { /* in some occasions, draw a border */ - if (panel->flag & PNL_SELECT) { + if (panel->flag & PNL_SELECT && !is_subpanel) { if (panel->control & UI_PNL_SOLID) { UI_draw_roundbox_corner_set(UI_CNR_ALL); } @@ -876,6 +877,16 @@ static int get_panel_real_ofsx(Panel *panel) } } +bool UI_panel_is_dragging(const struct Panel *panel) +{ + uiHandlePanelData *data = panel->activedata; + if (!data) { + return false; + } + + return data->is_drag_drop; +} + typedef struct PanelSort { Panel *panel, *orig; } PanelSort; @@ -1311,8 +1322,8 @@ static void ui_do_drag(const bContext *C, const wmEvent *event, Panel *panel) return; } - dx = (event->x - data->startx) & ~(PNL_GRID - 1); - dy = (event->y - data->starty) & ~(PNL_GRID - 1); + dx = (event->x - data->startx); + dy = (event->y - data->starty); dx *= (float)BLI_rctf_size_x(®ion->v2d.cur) / (float)BLI_rcti_size_x(®ion->winrct); dy *= (float)BLI_rctf_size_y(®ion->v2d.cur) / (float)BLI_rcti_size_y(®ion->winrct); @@ -2458,6 +2469,24 @@ static void ui_handler_remove_panel(bContext *C, void *userdata) panel_activate_state(C, panel, PANEL_STATE_EXIT); } +/** + * Set selection state for a panel and its subpanels. The subpanels need to know they are selected + * too so they can be drawn above their parent when it is dragged. + */ +static void set_panel_selection(Panel *panel, bool value) +{ + if (value) { + panel->flag |= PNL_SELECT; + } + else { + panel->flag &= ~PNL_SELECT; + } + + LISTBASE_FOREACH (Panel *, child, &panel->children) { + set_panel_selection(child, value); + } +} + static void panel_activate_state(const bContext *C, Panel *panel, uiHandlePanelState state) { uiHandlePanelData *data = panel->activedata; @@ -2468,6 +2497,8 @@ static void panel_activate_state(const bContext *C, Panel *panel, uiHandlePanelS return; } + bool was_drag_drop = (data && data->state == PANEL_STATE_DRAG); + if (state == PANEL_STATE_EXIT || state == PANEL_STATE_ANIMATION) { if (data && data->state != PANEL_STATE_ANIMATION) { /* XXX: @@ -2480,10 +2511,10 @@ static void panel_activate_state(const bContext *C, Panel *panel, uiHandlePanelS check_panel_overlap(region, NULL); /* clears */ } - panel->flag &= ~PNL_SELECT; + set_panel_selection(panel, false); } else { - panel->flag |= PNL_SELECT; + set_panel_selection(panel, true); } if (data && data->animtimer) { @@ -2519,6 +2550,12 @@ static void panel_activate_state(const bContext *C, Panel *panel, uiHandlePanelS data->startsizex = panel->sizex; data->startsizey = panel->sizey; data->starttime = PIL_check_seconds_timer(); + + /* Remember drag drop state even when animating to the aligned position after dragging. */ + data->is_drag_drop = was_drag_drop; + if (state == PANEL_STATE_DRAG) { + data->is_drag_drop = true; + } } ED_region_tag_redraw(region); diff --git a/source/blender/editors/interface/interface_region_hud.c b/source/blender/editors/interface/interface_region_hud.c index 34ac58c1dca..1f8af7b9e6e 100644 --- a/source/blender/editors/interface/interface_region_hud.c +++ b/source/blender/editors/interface/interface_region_hud.c @@ -177,11 +177,13 @@ static void hud_region_layout(const bContext *C, ARegion *region) return; } + ScrArea *area = CTX_wm_area(C); int size_y = region->sizey; ED_region_panels_layout(C, region); - if (region->panels.first && (region->sizey != size_y)) { + if (region->panels.first && + ((area->flag & AREA_FLAG_REGION_SIZE_UPDATE) || (region->sizey != size_y))) { int winx_new = UI_DPI_FAC * (region->sizex + 0.5f); int winy_new = UI_DPI_FAC * (region->sizey + 0.5f); View2D *v2d = ®ion->v2d; @@ -339,6 +341,7 @@ void ED_area_type_hud_ensure(bContext *C, ScrArea *area) } else { if (region->flag & RGN_FLAG_HIDDEN) { + /* Also forces recalculating HUD size in hud_region_layout(). */ area->flag |= AREA_FLAG_REGION_SIZE_UPDATE; } region->flag &= ~RGN_FLAG_HIDDEN; diff --git a/source/blender/editors/interface/interface_region_menu_popup.c b/source/blender/editors/interface/interface_region_menu_popup.c index 31ef7261eb3..3e34b7f3f8a 100644 --- a/source/blender/editors/interface/interface_region_menu_popup.c +++ b/source/blender/editors/interface/interface_region_menu_popup.c @@ -581,21 +581,18 @@ int UI_popup_menu_invoke(bContext *C, const char *idname, ReportList *reports) /** \name Popup Block API * \{ */ -void UI_popup_block_invoke_ex(bContext *C, - uiBlockCreateFunc func, - void *arg, - void (*arg_free)(void *arg), - const char *opname, - int opcontext) +void UI_popup_block_invoke_ex( + bContext *C, uiBlockCreateFunc func, void *arg, void (*arg_free)(void *arg), bool can_refresh) { wmWindow *window = CTX_wm_window(C); uiPopupBlockHandle *handle; handle = ui_popup_block_create(C, NULL, NULL, func, NULL, arg, arg_free); handle->popup = true; - handle->can_refresh = true; - handle->optype = (opname) ? WM_operatortype_find(opname, 0) : NULL; - handle->opcontext = opcontext; + + /* It can be useful to disable refresh (even though it will work) + * as this exists text fields which can be disruptive if refresh isn't needed. */ + handle->can_refresh = can_refresh; UI_popup_handlers_add(C, &window->modalhandlers, handle, 0); UI_block_active_only_flagged_buttons(C, handle->region, handle->region->uiblocks.first); @@ -607,7 +604,7 @@ void UI_popup_block_invoke(bContext *C, void *arg, void (*arg_free)(void *arg)) { - UI_popup_block_invoke_ex(C, func, arg, arg_free, NULL, WM_OP_INVOKE_DEFAULT); + UI_popup_block_invoke_ex(C, func, arg, arg_free, true); } void UI_popup_block_ex(bContext *C, diff --git a/source/blender/editors/interface/interface_region_search.c b/source/blender/editors/interface/interface_region_search.c index e2c87891169..0007f6ab9a2 100644 --- a/source/blender/editors/interface/interface_region_search.c +++ b/source/blender/editors/interface/interface_region_search.c @@ -35,6 +35,7 @@ #include "BLI_math.h" +#include "BLI_listbase.h" #include "BLI_rect.h" #include "BLI_string.h" #include "BLI_utildefines.h" @@ -153,7 +154,8 @@ bool UI_search_item_add(uiSearchItems *items, const char *name, void *poin, int /* Limit flags that can be set so flags such as 'UI_SELECT' aren't accidentally set * which will cause problems, add others as needed. */ - BLI_assert((state & ~(UI_BUT_DISABLED | UI_BUT_INACTIVE | UI_BUT_REDALERT)) == 0); + BLI_assert( + (state & ~(UI_BUT_DISABLED | UI_BUT_INACTIVE | UI_BUT_REDALERT | UI_BUT_HAS_SEP_CHAR)) == 0); if (items->states) { items->states[items->totitem] = state; } @@ -295,10 +297,31 @@ bool ui_searchbox_apply(uiBut *but, ARegion *region) } } -void ui_searchbox_event(bContext *C, ARegion *region, uiBut *but, const wmEvent *event) +static struct ARegion *wm_searchbox_tooltip_init(struct bContext *C, + struct ARegion *region, + int *UNUSED(r_pass), + double *UNUSED(pass_delay), + bool *r_exit_on_event) +{ + *r_exit_on_event = true; + + LISTBASE_FOREACH (uiBlock *, block, ®ion->uiblocks) { + LISTBASE_FOREACH (uiBut *, but, &block->buttons) { + if (but->search && but->search->tooltip_fn) { + return but->search->tooltip_fn(C, region, but->search->arg, but->func_arg2); + } + } + } + return NULL; +} + +bool ui_searchbox_event( + bContext *C, ARegion *region, uiBut *but, ARegion *butregion, const wmEvent *event) { uiSearchboxData *data = region->regiondata; int type = event->type, val = event->val; + bool handled = false; + bool tooltip_timer_started = false; if (type == MOUSEPAN) { ui_pan_to_scroll(event, &type, &val); @@ -308,12 +331,36 @@ void ui_searchbox_event(bContext *C, ARegion *region, uiBut *but, const wmEvent case WHEELUPMOUSE: case EVT_UPARROWKEY: ui_searchbox_select(C, region, but, -1); + handled = true; break; case WHEELDOWNMOUSE: case EVT_DOWNARROWKEY: ui_searchbox_select(C, region, but, 1); + handled = true; break; - case MOUSEMOVE: + case RIGHTMOUSE: + if (val) { + if (but->search->context_menu_fn) { + if (data->active != -1) { + /* Check the cursor is over the active element + * (a little confusing if this isn't the case, although it does work). */ + rcti rect; + ui_searchbox_butrect(&rect, data, data->active); + if (BLI_rcti_isect_pt( + &rect, event->x - region->winrct.xmin, event->y - region->winrct.ymin)) { + + void *active = data->items.pointers[data->active]; + if (but->search->context_menu_fn(C, but->search->arg, active, event)) { + handled = true; + } + } + } + } + } + break; + case MOUSEMOVE: { + bool is_inside = false; + if (BLI_rcti_isect_pt(®ion->winrct, event->x, event->y)) { rcti rect; int a; @@ -322,16 +369,46 @@ void ui_searchbox_event(bContext *C, ARegion *region, uiBut *but, const wmEvent ui_searchbox_butrect(&rect, data, a); if (BLI_rcti_isect_pt( &rect, event->x - region->winrct.xmin, event->y - region->winrct.ymin)) { + is_inside = true; if (data->active != a) { data->active = a; ui_searchbox_select(C, region, but, 0); + handled = true; break; } } } } + + if (U.flag & USER_TOOLTIPS) { + if (is_inside) { + if (data->active != -1) { + ScrArea *area = CTX_wm_area(C); + but->func_arg2 = data->items.pointers[data->active]; + WM_tooltip_timer_init(C, CTX_wm_window(C), area, butregion, wm_searchbox_tooltip_init); + tooltip_timer_started = true; + } + } + } + break; + } } + + if (handled && (tooltip_timer_started == false)) { + wmWindow *win = CTX_wm_window(C); + WM_tooltip_clear(C, win); + } + + return handled; +} + +/** Wrap #uiButSearchUpdateFn callback. */ +static void ui_searchbox_update_fn(bContext *C, uiBut *but, const char *str, uiSearchItems *items) +{ + wmWindow *win = CTX_wm_window(C); + WM_tooltip_clear(C, win); + but->search->update_fn(C, but->search->arg, str, items); } /* region is the search box itself */ @@ -350,9 +427,9 @@ void ui_searchbox_update(bContext *C, ARegion *region, uiBut *but, const bool re data->active = -1; /* handle active */ - if (but->search_func && but->func_arg2) { + if (but->search->update_fn && but->func_arg2) { data->items.active = but->func_arg2; - but->search_func(C, but->search_arg, but->editstr, &data->items); + ui_searchbox_update_fn(C, but, but->editstr, &data->items); data->items.active = NULL; /* found active item, calculate real offset by centering it */ @@ -381,8 +458,8 @@ void ui_searchbox_update(bContext *C, ARegion *region, uiBut *but, const bool re } /* callback */ - if (but->search_func) { - but->search_func(C, but->search_arg, but->editstr, &data->items); + if (but->search->update_fn) { + ui_searchbox_update_fn(C, but, but->editstr, &data->items); } /* handle case where editstr is equal to one of items */ @@ -416,7 +493,7 @@ int ui_searchbox_autocomplete(bContext *C, ARegion *region, uiBut *but, char *st if (str[0]) { data->items.autocpl = UI_autocomplete_begin(str, ui_but_string_get_max_length(but)); - but->search_func(C, but->search_arg, but->editstr, &data->items); + ui_searchbox_update_fn(C, but, but->editstr, &data->items); match = UI_autocomplete_end(data->items.autocpl, str); data->items.autocpl = NULL; @@ -603,7 +680,7 @@ ARegion *ui_searchbox_create_generic(bContext *C, ARegion *butregion, uiBut *but if (but->optype != NULL || (but->drawflag & UI_BUT_HAS_SHORTCUT) != 0) { data->use_sep = true; } - data->sep_string = but->search_sep_string; + data->sep_string = but->search->sep_string; /* compute position */ if (but->block->flag & UI_BLOCK_SEARCH_MENU) { @@ -881,7 +958,7 @@ void ui_but_search_refresh(uiBut *but) items->names[x1] = MEM_callocN(but->hardmax + 1, "search names"); } - but->search_func(but->block->evil_C, but->search_arg, but->drawstr, items); + ui_searchbox_update_fn(but->block->evil_C, but, but->drawstr, items); /* only redalert when we are sure of it, this can miss cases when >10 matches */ if (items->totitem == 0) { diff --git a/source/blender/editors/interface/interface_template_search_menu.c b/source/blender/editors/interface/interface_template_search_menu.c new file mode 100644 index 00000000000..2c6b09168f4 --- /dev/null +++ b/source/blender/editors/interface/interface_template_search_menu.c @@ -0,0 +1,1139 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup edinterface + * + * Search available menu items via the user interface & key-maps. + * Accessed via the #WM_OT_search_menu operator. + */ + +#include <string.h> + +#include "MEM_guardedalloc.h" + +#include "DNA_action_types.h" +#include "DNA_gpencil_modifier_types.h" +#include "DNA_node_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" +#include "DNA_shader_fx_types.h" +#include "DNA_texture_types.h" + +#include "BLI_alloca.h" +#include "BLI_dynstr.h" +#include "BLI_ghash.h" +#include "BLI_linklist.h" +#include "BLI_listbase.h" +#include "BLI_math_matrix.h" +#include "BLI_memarena.h" +#include "BLI_string.h" +#include "BLI_string_utils.h" +#include "BLI_utildefines.h" + +#include "BLT_translation.h" + +#include "BKE_context.h" +#include "BKE_global.h" +#include "BKE_screen.h" + +#include "ED_screen.h" + +#include "RNA_access.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "UI_interface.h" +#include "interface_intern.h" + +/* For key-map item access. */ +#include "wm_event_system.h" + +/* -------------------------------------------------------------------- */ +/** \name Menu Search Template Implementation + * \{ */ + +/* Unicode arrow. */ +#define MENU_SEP "\xe2\x96\xb6" + +/** + * Use when #menu_items_from_ui_create is called with `include_all_areas`. + * so we can run the menu item in the area it was extracted from. + */ +struct MenuSearch_Context { + /** + * Index into `Area.ui_type` #EnumPropertyItem or the top-bar when -1. + * Needed to get the display-name to use as a prefix for each menu item. + */ + int space_type_ui_index; + + ScrArea *area; + ARegion *region; +}; + +struct MenuSearch_Parent { + struct MenuSearch_Parent *parent; + MenuType *parent_mt; + const char *drawstr; + + /** Set while writing menu items only. */ + struct MenuSearch_Parent *temp_child; +}; + +struct MenuSearch_Item { + struct MenuSearch_Item *next, *prev; + const char *drawstr; + const char *drawwstr_full; + /** Support a single level sub-menu nesting (for operator buttons that expand). */ + const char *drawstr_submenu; + int icon; + int state; + + struct MenuSearch_Parent *menu_parent; + MenuType *mt; + + enum { + MENU_SEARCH_TYPE_OP = 1, + MENU_SEARCH_TYPE_RNA = 2, + } type; + + union { + /** Operator menu item. */ + struct { + wmOperatorType *type; + PointerRNA *opptr; + short opcontext; + bContextStore *context; + } op; + + /** Property (only for check-box/boolean). */ + struct { + PointerRNA ptr; + PropertyRNA *prop; + int index; + /** Only for enum buttons. */ + int enum_value; + } rna; + }; + + /** Set when we need each menu item to be able to set it's own context. may be NULL. */ + struct MenuSearch_Context *wm_context; +}; + +struct MenuSearch_Data { + /** MenuSearch_Item */ + ListBase items; + /** Use for all small allocations. */ + MemArena *memarena; + + /** Use for context menu, to fake a button to create a context menu. */ + struct { + uiBut but; + uiBlock block; + } context_menu_data; +}; + +static int menu_item_sort_by_drawstr_full(const void *menu_item_a_v, const void *menu_item_b_v) +{ + const struct MenuSearch_Item *menu_item_a = menu_item_a_v; + const struct MenuSearch_Item *menu_item_b = menu_item_b_v; + return strcmp(menu_item_a->drawwstr_full, menu_item_b->drawwstr_full); +} + +static const char *strdup_memarena(MemArena *memarena, const char *str) +{ + const uint str_size = strlen(str) + 1; + char *str_dst = BLI_memarena_alloc(memarena, str_size); + memcpy(str_dst, str, str_size); + return str_dst; +} + +static const char *strdup_memarena_from_dynstr(MemArena *memarena, DynStr *dyn_str) +{ + const uint str_size = BLI_dynstr_get_len(dyn_str) + 1; + char *str_dst = BLI_memarena_alloc(memarena, str_size); + BLI_dynstr_get_cstring_ex(dyn_str, str_dst); + return str_dst; +} + +static bool menu_items_from_ui_create_item_from_button(struct MenuSearch_Data *data, + MemArena *memarena, + struct MenuType *mt, + const char *drawstr_submenu, + uiBut *but, + struct MenuSearch_Context *wm_context) +{ + struct MenuSearch_Item *item = NULL; + + /* Use override if the name is empty, this can happen with popovers. */ + const char *drawstr_override = NULL; + const char *drawstr_sep = (but->flag & UI_BUT_HAS_SEP_CHAR) ? + strrchr(but->drawstr, UI_SEP_CHAR) : + NULL; + const bool drawstr_is_empty = (drawstr_sep == but->drawstr) || (but->drawstr[0] == '\0'); + + if (but->optype != NULL) { + if (drawstr_is_empty) { + drawstr_override = WM_operatortype_name(but->optype, but->opptr); + } + + item = BLI_memarena_calloc(memarena, sizeof(*item)); + item->type = MENU_SEARCH_TYPE_OP; + + item->op.type = but->optype; + item->op.opcontext = but->opcontext; + item->op.context = but->context; + item->op.opptr = but->opptr; + but->opptr = NULL; + } + else if (but->rnaprop != NULL) { + const int prop_type = RNA_property_type(but->rnaprop); + + if (drawstr_is_empty) { + if (prop_type == PROP_ENUM) { + const int value_enum = (int)but->hardmax; + EnumPropertyItem enum_item; + if (RNA_property_enum_item_from_value_gettexted( + but->block->evil_C, &but->rnapoin, but->rnaprop, value_enum, &enum_item)) { + drawstr_override = enum_item.name; + } + else { + /* Should never happen. */ + drawstr_override = "Unknown"; + } + } + else { + drawstr_override = RNA_property_ui_name(but->rnaprop); + } + } + + if (!ELEM(prop_type, PROP_BOOLEAN, PROP_ENUM)) { + /* Note that these buttons are not prevented, + * but aren't typically used in menus. */ + printf("Button '%s' in menu '%s' is a menu item with unsupported RNA type %d\n", + but->drawstr, + mt->idname, + prop_type); + } + else { + item = BLI_memarena_calloc(memarena, sizeof(*item)); + item->type = MENU_SEARCH_TYPE_RNA; + + item->rna.ptr = but->rnapoin; + item->rna.prop = but->rnaprop; + item->rna.index = but->rnaindex; + + if (prop_type == PROP_ENUM) { + item->rna.enum_value = (int)but->hardmax; + } + } + } + + if (item != NULL) { + /* Handle shared settings. */ + if (drawstr_override != NULL) { + const char *drawstr_suffix = drawstr_sep ? drawstr_sep : ""; + char *drawstr_alloc = BLI_string_joinN("(", drawstr_override, ")", drawstr_suffix); + item->drawstr = strdup_memarena(memarena, drawstr_alloc); + MEM_freeN(drawstr_alloc); + } + else { + item->drawstr = strdup_memarena(memarena, but->drawstr); + } + + item->icon = ui_but_icon(but); + item->state = (but->flag & + (UI_BUT_DISABLED | UI_BUT_INACTIVE | UI_BUT_REDALERT | UI_BUT_HAS_SEP_CHAR)); + item->mt = mt; + item->drawstr_submenu = drawstr_submenu ? strdup_memarena(memarena, drawstr_submenu) : NULL; + + item->wm_context = wm_context; + + BLI_addtail(&data->items, item); + return true; + } + + return false; +} + +/** + * Populate a fake button from a menu item (use for context menu). + */ +static bool menu_items_to_ui_button(struct MenuSearch_Item *item, uiBut *but) +{ + bool changed = false; + switch (item->type) { + case MENU_SEARCH_TYPE_OP: { + but->optype = item->op.type; + but->opcontext = item->op.opcontext; + but->context = item->op.context; + but->opptr = item->op.opptr; + changed = true; + break; + } + case MENU_SEARCH_TYPE_RNA: { + const int prop_type = RNA_property_type(item->rna.prop); + + but->rnapoin = item->rna.ptr; + but->rnaprop = item->rna.prop; + but->rnaindex = item->rna.index; + + if (prop_type == PROP_ENUM) { + but->hardmax = item->rna.enum_value; + } + changed = true; + break; + } + } + + if (changed) { + STRNCPY(but->drawstr, item->drawstr); + char *drawstr_sep = (item->state & UI_BUT_HAS_SEP_CHAR) ? strrchr(but->drawstr, UI_SEP_CHAR) : + NULL; + if (drawstr_sep) { + *drawstr_sep = '\0'; + } + + but->icon = item->icon; + but->str = but->strdata; + } + + return changed; +} + +/** + * Populate \a menu_stack with menus from inspecting active key-maps for this context. + */ +static void menu_types_add_from_keymap_items(bContext *C, + wmWindow *win, + ScrArea *area, + ARegion *region, + LinkNode **menuid_stack_p, + GHash *menu_to_kmi, + GSet *menu_tagged) +{ + wmWindowManager *wm = CTX_wm_manager(C); + ListBase *handlers[] = { + region ? ®ion->handlers : NULL, + area ? &area->handlers : NULL, + &win->handlers, + }; + + for (int handler_index = 0; handler_index < ARRAY_SIZE(handlers); handler_index++) { + if (handlers[handler_index] == NULL) { + continue; + } + LISTBASE_FOREACH (wmEventHandler *, handler_base, handlers[handler_index]) { + /* During this loop, UI handlers for nested menus can tag multiple handlers free. */ + if (handler_base->flag & WM_HANDLER_DO_FREE) { + continue; + } + if (handler_base->type != WM_HANDLER_TYPE_KEYMAP) { + continue; + } + + else if (handler_base->poll == NULL || handler_base->poll(region, win->eventstate)) { + wmEventHandler_Keymap *handler = (wmEventHandler_Keymap *)handler_base; + wmKeyMap *keymap = WM_event_get_keymap_from_handler(wm, handler); + if (keymap && WM_keymap_poll(C, keymap)) { + LISTBASE_FOREACH (wmKeyMapItem *, kmi, &keymap->items) { + if (kmi->flag & KMI_INACTIVE) { + continue; + } + if (STR_ELEM(kmi->idname, "WM_OT_call_menu", "WM_OT_call_menu_pie")) { + char menu_idname[MAX_NAME]; + RNA_string_get(kmi->ptr, "name", menu_idname); + MenuType *mt = WM_menutype_find(menu_idname, false); + + if (mt && BLI_gset_add(menu_tagged, mt)) { + /* Unlikely, but possible this will be included twice. */ + BLI_linklist_prepend(menuid_stack_p, mt); + + void **kmi_p; + if (!BLI_ghash_ensure_p(menu_to_kmi, mt, &kmi_p)) { + *kmi_p = kmi; + } + } + } + } + } + } + } + } +} + +/** + * Display all operators (last). Developer-only convenience feature. + */ +static void menu_items_from_all_operators(bContext *C, struct MenuSearch_Data *data) +{ + /* Add to temporary list so we can sort them separately. */ + ListBase operator_items = {NULL, NULL}; + + MemArena *memarena = data->memarena; + GHashIterator iter; + for (WM_operatortype_iter(&iter); !BLI_ghashIterator_done(&iter); + BLI_ghashIterator_step(&iter)) { + wmOperatorType *ot = BLI_ghashIterator_getValue(&iter); + + if ((ot->flag & OPTYPE_INTERNAL) && (G.debug & G_DEBUG_WM) == 0) { + continue; + } + + if (WM_operator_poll((bContext *)C, ot)) { + const char *ot_ui_name = CTX_IFACE_(ot->translation_context, ot->name); + + struct MenuSearch_Item *item = NULL; + item = BLI_memarena_calloc(memarena, sizeof(*item)); + item->type = MENU_SEARCH_TYPE_OP; + + item->op.type = ot; + item->op.opcontext = WM_OP_INVOKE_DEFAULT; + item->op.context = NULL; + + char idname_as_py[OP_MAX_TYPENAME]; + char uiname[256]; + WM_operator_py_idname(idname_as_py, ot->idname); + + SNPRINTF(uiname, "%s " MENU_SEP "%s", idname_as_py, ot_ui_name); + + item->drawwstr_full = strdup_memarena(memarena, uiname); + item->drawstr = ot_ui_name; + + item->wm_context = NULL; + + BLI_addtail(&operator_items, item); + } + } + + BLI_listbase_sort(&operator_items, menu_item_sort_by_drawstr_full); + + BLI_movelisttolist(&data->items, &operator_items); +} + +/** + * Create #MenuSearch_Data by inspecting the current context, this uses two methods: + * + * - Look-up pre-defined editor-menus. + * - Look-up key-map items which call menus. + */ +static struct MenuSearch_Data *menu_items_from_ui_create( + bContext *C, wmWindow *win, ScrArea *area_init, ARegion *region_init, bool include_all_areas) +{ + MemArena *memarena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); + /** Map (#MenuType to #MenuSearch_Parent) */ + GHash *menu_parent_map = BLI_ghash_ptr_new(__func__); + GHash *menu_display_name_map = BLI_ghash_ptr_new(__func__); + const uiStyle *style = UI_style_get_dpi(); + + /* Convert into non-ui structure. */ + struct MenuSearch_Data *data = MEM_callocN(sizeof(*data), __func__); + + DynStr *dyn_str = BLI_dynstr_new_memarena(); + + /* Use a stack of menus to handle and discover new menus in passes. */ + LinkNode *menu_stack = NULL; + + /* Tag menu types not to add, either because they have already been added + * or they have been blacklisted. + * Set of #MenuType. */ + GSet *menu_tagged = BLI_gset_ptr_new(__func__); + /** Map (#MenuType -> #wmKeyMapItem). */ + GHash *menu_to_kmi = BLI_ghash_ptr_new(__func__); + + /* Blacklist menus we don't want to show. */ + { + const char *idname_array[] = { + /* While we could include this, it's just showing filenames to load. */ + "TOPBAR_MT_file_open_recent", + }; + for (int i = 0; i < ARRAY_SIZE(idname_array); i++) { + MenuType *mt = WM_menutype_find(idname_array[i], false); + if (mt != NULL) { + BLI_gset_add(menu_tagged, mt); + } + } + } + + /* Collect contexts, one for each 'ui_type'. */ + struct MenuSearch_Context *wm_contexts = NULL; + + const EnumPropertyItem *space_type_ui_items = NULL; + int space_type_ui_items_len = 0; + bool space_type_ui_items_free = false; + + /* Text used as prefix for top-bar menu items. */ + const char *global_menu_prefix = NULL; + + if (include_all_areas) { + /* First create arrays for ui_type. */ + PropertyRNA *prop_ui_type = NULL; + { + PointerRNA ptr; + RNA_pointer_create(NULL, &RNA_Area, NULL, &ptr); + prop_ui_type = RNA_struct_find_property(&ptr, "ui_type"); + RNA_property_enum_items(C, + &ptr, + prop_ui_type, + &space_type_ui_items, + &space_type_ui_items_len, + &space_type_ui_items_free); + + wm_contexts = BLI_memarena_calloc(memarena, sizeof(*wm_contexts) * space_type_ui_items_len); + for (int i = 0; i < space_type_ui_items_len; i++) { + wm_contexts[i].space_type_ui_index = -1; + } + } + + bScreen *screen = WM_window_get_active_screen(win); + LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { + ARegion *region = BKE_area_find_region_type(area, RGN_TYPE_WINDOW); + if (region != NULL) { + PointerRNA ptr; + RNA_pointer_create(&screen->id, &RNA_Area, area, &ptr); + const int space_type_ui = RNA_property_enum_get(&ptr, prop_ui_type); + + int space_type_ui_index = RNA_enum_from_value(space_type_ui_items, space_type_ui); + if (space_type_ui_index == -1) { + continue; + } + + if (wm_contexts[space_type_ui_index].space_type_ui_index != -1) { + ScrArea *area_best = wm_contexts[space_type_ui_index].area; + const uint value_best = (uint)area_best->winx * (uint)area_best->winy; + const uint value_test = (uint)area->winx * (uint)area->winy; + if (value_best > value_test) { + continue; + } + } + + wm_contexts[space_type_ui_index].space_type_ui_index = space_type_ui_index; + wm_contexts[space_type_ui_index].area = area; + wm_contexts[space_type_ui_index].region = region; + } + } + + global_menu_prefix = CTX_IFACE_(RNA_property_translation_context(prop_ui_type), "Top Bar"); + } + + GHashIterator iter; + + for (int space_type_ui_index = -1; space_type_ui_index < space_type_ui_items_len; + space_type_ui_index += 1) { + + ScrArea *area = NULL; + ARegion *region = NULL; + struct MenuSearch_Context *wm_context = NULL; + + if (include_all_areas) { + if (space_type_ui_index == -1) { + /* First run without any context, to populate the top-bar without. */ + wm_context = NULL; + area = NULL; + region = NULL; + } + else { + wm_context = &wm_contexts[space_type_ui_index]; + if (wm_context->space_type_ui_index == -1) { + continue; + } + + area = wm_context->area; + region = wm_context->region; + + CTX_wm_area_set(C, area); + CTX_wm_region_set(C, region); + } + } + else { + area = area_init; + region = region_init; + } + + /* Populate menus from the editors, + * note that we could create a fake header, draw the header and extract the menus + * from the buttons, however this is quite involved and can be avoided as by convention + * each space-type has a single root-menu that headers use. */ + { + const char *idname_array[2] = {NULL}; + int idname_array_len = 0; + + /* Use negative for global (no area) context, populate the top-bar. */ + if (space_type_ui_index == -1) { + idname_array[idname_array_len++] = "TOPBAR_MT_editor_menus"; + } + +#define SPACE_MENU_MAP(space_type, menu_id) \ + case space_type: \ + idname_array[idname_array_len++] = menu_id; \ + break +#define SPACE_MENU_NOP(space_type) \ + case space_type: \ + break + + if (area != NULL) { + SpaceLink *sl = area->spacedata.first; + switch ((eSpace_Type)area->spacetype) { + SPACE_MENU_MAP(SPACE_VIEW3D, "VIEW3D_MT_editor_menus"); + SPACE_MENU_MAP(SPACE_GRAPH, "GRAPH_MT_editor_menus"); + SPACE_MENU_MAP(SPACE_OUTLINER, "OUTLINER_MT_editor_menus"); + SPACE_MENU_NOP(SPACE_PROPERTIES); + SPACE_MENU_MAP(SPACE_FILE, "FILEBROWSER_MT_editor_menus"); + SPACE_MENU_MAP(SPACE_IMAGE, "IMAGE_MT_editor_menus"); + SPACE_MENU_MAP(SPACE_INFO, "INFO_MT_editor_menus"); + SPACE_MENU_MAP(SPACE_SEQ, "SEQUENCER_MT_editor_menus"); + SPACE_MENU_MAP(SPACE_TEXT, "TEXT_MT_editor_menus"); + SPACE_MENU_MAP(SPACE_ACTION, + (((const SpaceAction *)sl)->mode == SACTCONT_TIMELINE) ? + "TIME_MT_editor_menus" : + "DOPESHEET_MT_editor_menus"); + SPACE_MENU_MAP(SPACE_NLA, "NLA_MT_editor_menus"); + SPACE_MENU_MAP(SPACE_NODE, "NODE_MT_editor_menus"); + SPACE_MENU_MAP(SPACE_CONSOLE, "CONSOLE_MT_editor_menus"); + SPACE_MENU_MAP(SPACE_USERPREF, "USERPREF_MT_editor_menus"); + SPACE_MENU_MAP(SPACE_CLIP, + (((const SpaceClip *)sl)->mode == SC_MODE_TRACKING) ? + "CLIP_MT_tracking_editor_menus" : + "CLIP_MT_masking_editor_menus"); + SPACE_MENU_NOP(SPACE_EMPTY); + SPACE_MENU_NOP(SPACE_SCRIPT); + SPACE_MENU_NOP(SPACE_STATUSBAR); + SPACE_MENU_NOP(SPACE_TOPBAR); + } + } + for (int i = 0; i < idname_array_len; i++) { + MenuType *mt = WM_menutype_find(idname_array[i], false); + if (mt != NULL) { + /* Check if this exists because of 'include_all_areas'. */ + if (BLI_gset_add(menu_tagged, mt)) { + BLI_linklist_prepend(&menu_stack, mt); + } + } + } + } +#undef SPACE_MENU_MAP +#undef SPACE_MENU_NOP + + bool has_keymap_menu_items = false; + + while (menu_stack != NULL) { + MenuType *mt = BLI_linklist_pop(&menu_stack); + if (!WM_menutype_poll(C, mt)) { + continue; + } + + uiBlock *block = UI_block_begin(C, region, __func__, UI_EMBOSS); + uiLayout *layout = UI_block_layout( + block, UI_LAYOUT_VERTICAL, UI_LAYOUT_MENU, 0, 0, 200, 0, UI_MENU_PADDING, style); + + UI_block_flag_enable(block, UI_BLOCK_SHOW_SHORTCUT_ALWAYS); + + uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_REGION_WIN); + UI_menutype_draw(C, mt, layout); + + UI_block_end(C, block); + + LISTBASE_FOREACH (uiBut *, but, &block->buttons) { + MenuType *mt_from_but = NULL; + /* Support menu titles with dynamic from initial labels + * (used by edit-mesh context menu). */ + if (but->type == UI_BTYPE_LABEL) { + + /* Check if the label is the title. */ + uiBut *but_test = but->prev; + while (but_test && but_test->type == UI_BTYPE_SEPR) { + but_test = but_test->prev; + } + + if (but_test == NULL) { + BLI_ghash_insert( + menu_display_name_map, mt, (void *)strdup_memarena(memarena, but->drawstr)); + } + } + else if (menu_items_from_ui_create_item_from_button( + data, memarena, mt, NULL, but, wm_context)) { + /* pass */ + } + else if ((mt_from_but = UI_but_menutype_get(but))) { + + if (BLI_gset_add(menu_tagged, mt_from_but)) { + BLI_linklist_prepend(&menu_stack, mt_from_but); + } + + if (!BLI_ghash_haskey(menu_parent_map, mt_from_but)) { + struct MenuSearch_Parent *menu_parent = BLI_memarena_calloc(memarena, + sizeof(*menu_parent)); + /* Use brackets for menu key shortcuts, + * converting "Text|Some-Shortcut" to "Text (Some-Shortcut)". + * This is needed so we don't right align sub-menu contents + * we only want to do that for the last menu item, not the path that leads to it. + */ + const char *drawstr_sep = but->flag & UI_BUT_HAS_SEP_CHAR ? + strrchr(but->drawstr, UI_SEP_CHAR) : + NULL; + bool drawstr_is_empty = false; + if (drawstr_sep != NULL) { + BLI_assert(BLI_dynstr_get_len(dyn_str) == 0); + /* Detect empty string, fallback to menu name. */ + const char *drawstr = but->drawstr; + int drawstr_len = drawstr_sep - but->drawstr; + if (UNLIKELY(drawstr_len == 0)) { + drawstr = CTX_IFACE_(mt_from_but->translation_context, mt_from_but->label); + drawstr_len = strlen(drawstr); + if (drawstr[0] == '\0') { + drawstr_is_empty = true; + } + } + BLI_dynstr_nappend(dyn_str, drawstr, drawstr_len); + BLI_dynstr_appendf(dyn_str, " (%s)", drawstr_sep + 1); + menu_parent->drawstr = strdup_memarena_from_dynstr(memarena, dyn_str); + BLI_dynstr_clear(dyn_str); + } + else { + const char *drawstr = but->drawstr; + if (UNLIKELY(drawstr[0] == '\0')) { + drawstr = CTX_IFACE_(mt_from_but->translation_context, mt_from_but->label); + if (drawstr[0] == '\0') { + drawstr_is_empty = true; + } + } + menu_parent->drawstr = strdup_memarena(memarena, drawstr); + } + menu_parent->parent_mt = mt; + BLI_ghash_insert(menu_parent_map, mt_from_but, menu_parent); + + if (drawstr_is_empty) { + printf("Warning: '%s' menu has empty 'bl_label'.\n", mt_from_but->idname); + } + } + } + else if (but->menu_create_func != NULL) { + /* A non 'MenuType' menu button. */ + + /* Only expand one level deep, this is mainly for expanding operator menus. */ + const char *drawstr_submenu = but->drawstr; + + /* +1 to avoid overlap with the current 'block'. */ + uiBlock *sub_block = UI_block_begin(C, region, __func__ + 1, UI_EMBOSS); + uiLayout *sub_layout = UI_block_layout( + sub_block, UI_LAYOUT_VERTICAL, UI_LAYOUT_MENU, 0, 0, 200, 0, UI_MENU_PADDING, style); + + UI_block_flag_enable(sub_block, UI_BLOCK_SHOW_SHORTCUT_ALWAYS); + + uiLayoutSetOperatorContext(sub_layout, WM_OP_INVOKE_REGION_WIN); + + but->menu_create_func(C, sub_layout, but->poin); + + UI_block_end(C, sub_block); + + LISTBASE_FOREACH (uiBut *, sub_but, &sub_block->buttons) { + menu_items_from_ui_create_item_from_button( + data, memarena, mt, drawstr_submenu, sub_but, wm_context); + } + + if (region) { + BLI_remlink(®ion->uiblocks, sub_block); + } + UI_block_free(NULL, sub_block); + } + } + if (region) { + BLI_remlink(®ion->uiblocks, block); + } + UI_block_free(NULL, block); + + /* Add key-map items as a second pass, + * so all menus are accessed from the header & top-bar before key shortcuts are expanded. */ + if ((menu_stack == NULL) && (has_keymap_menu_items == false)) { + has_keymap_menu_items = true; + menu_types_add_from_keymap_items( + C, win, area, region, &menu_stack, menu_to_kmi, menu_tagged); + } + } + } + + LISTBASE_FOREACH (struct MenuSearch_Item *, item, &data->items) { + item->menu_parent = BLI_ghash_lookup(menu_parent_map, item->mt); + } + + GHASH_ITER (iter, menu_parent_map) { + struct MenuSearch_Parent *menu_parent = BLI_ghashIterator_getValue(&iter); + menu_parent->parent = BLI_ghash_lookup(menu_parent_map, menu_parent->parent_mt); + } + + /* NOTE: currently this builds the full path for each menu item, + * that could be moved into the parent menu. */ + + /* Set names as full paths. */ + LISTBASE_FOREACH (struct MenuSearch_Item *, item, &data->items) { + BLI_assert(BLI_dynstr_get_len(dyn_str) == 0); + + if (include_all_areas) { + BLI_dynstr_appendf(dyn_str, + "%s: ", + (item->wm_context != NULL) ? + space_type_ui_items[item->wm_context->space_type_ui_index].name : + global_menu_prefix); + } + + if (item->menu_parent != NULL) { + struct MenuSearch_Parent *menu_parent = item->menu_parent; + menu_parent->temp_child = NULL; + while (menu_parent && menu_parent->parent) { + menu_parent->parent->temp_child = menu_parent; + menu_parent = menu_parent->parent; + } + while (menu_parent) { + BLI_dynstr_append(dyn_str, menu_parent->drawstr); + BLI_dynstr_append(dyn_str, " " MENU_SEP " "); + menu_parent = menu_parent->temp_child; + } + } + else { + const char *drawstr = BLI_ghash_lookup(menu_display_name_map, item->mt); + if (drawstr == NULL) { + drawstr = CTX_IFACE_(item->mt->translation_context, item->mt->label); + } + BLI_dynstr_append(dyn_str, drawstr); + + wmKeyMapItem *kmi = BLI_ghash_lookup(menu_to_kmi, item->mt); + if (kmi != NULL) { + char kmi_str[128]; + WM_keymap_item_to_string(kmi, false, kmi_str, sizeof(kmi_str)); + BLI_dynstr_appendf(dyn_str, " (%s)", kmi_str); + } + + BLI_dynstr_append(dyn_str, " " MENU_SEP " "); + } + + /* Optional nested menu. */ + if (item->drawstr_submenu != NULL) { + BLI_dynstr_append(dyn_str, item->drawstr_submenu); + BLI_dynstr_append(dyn_str, " " MENU_SEP " "); + } + + BLI_dynstr_append(dyn_str, item->drawstr); + + item->drawwstr_full = strdup_memarena_from_dynstr(memarena, dyn_str); + BLI_dynstr_clear(dyn_str); + } + BLI_dynstr_free(dyn_str); + + /* Finally sort menu items. + * + * Note: we might want to keep the in-menu order, for now sort all. */ + BLI_listbase_sort(&data->items, menu_item_sort_by_drawstr_full); + + BLI_ghash_free(menu_parent_map, NULL, NULL); + BLI_ghash_free(menu_display_name_map, NULL, NULL); + + BLI_ghash_free(menu_to_kmi, NULL, NULL); + + BLI_gset_free(menu_tagged, NULL); + + data->memarena = memarena; + + if (include_all_areas) { + CTX_wm_area_set(C, area_init); + CTX_wm_region_set(C, region_init); + + if (space_type_ui_items_free) { + MEM_freeN((void *)space_type_ui_items); + } + } + + /* Include all operators for developers, + * since it can be handy to have a quick way to access any operator, + * including operators being developed which haven't yet been added into the interface. + * + * These are added after all menu items so developers still get normal behavior by default, + * unless searching for something that isn't already in a menu (or scroll down). + * + * Keep this behind a developer only check: + * - Many operators need options to be set to give useful results, see: T74157. + * - User who really prefer to list all operators can use #WM_OT_search_operator. + */ + if (U.flag & USER_DEVELOPER_UI) { + menu_items_from_all_operators(C, data); + } + + return data; +} + +static void menu_search_arg_free_fn(void *data_v) +{ + struct MenuSearch_Data *data = data_v; + LISTBASE_FOREACH (struct MenuSearch_Item *, item, &data->items) { + switch (item->type) { + case MENU_SEARCH_TYPE_OP: { + if (item->op.opptr != NULL) { + WM_operator_properties_free(item->op.opptr); + MEM_freeN(item->op.opptr); + } + } + case MENU_SEARCH_TYPE_RNA: { + break; + } + } + } + + BLI_memarena_free(data->memarena); + + MEM_freeN(data); +} + +static void menu_search_exec_fn(bContext *C, void *UNUSED(arg1), void *arg2) +{ + struct MenuSearch_Item *item = arg2; + if (item == NULL) { + return; + } + if (item->state & UI_BUT_DISABLED) { + return; + } + + ScrArea *area_prev = CTX_wm_area(C); + ARegion *region_prev = CTX_wm_region(C); + + if (item->wm_context != NULL) { + CTX_wm_area_set(C, item->wm_context->area); + CTX_wm_region_set(C, item->wm_context->region); + } + + switch (item->type) { + case MENU_SEARCH_TYPE_OP: { + CTX_store_set(C, item->op.context); + WM_operator_name_call_ptr(C, item->op.type, item->op.opcontext, item->op.opptr); + CTX_store_set(C, NULL); + break; + } + case MENU_SEARCH_TYPE_RNA: { + PointerRNA *ptr = &item->rna.ptr; + PropertyRNA *prop = item->rna.prop; + int index = item->rna.index; + const int prop_type = RNA_property_type(prop); + bool changed = false; + + if (prop_type == PROP_BOOLEAN) { + const bool is_array = RNA_property_array_check(prop); + if (is_array) { + const bool value = RNA_property_boolean_get_index(ptr, prop, index); + RNA_property_boolean_set_index(ptr, prop, index, !value); + } + else { + const bool value = RNA_property_boolean_get(ptr, prop); + RNA_property_boolean_set(ptr, prop, !value); + } + changed = true; + } + else if (prop_type == PROP_ENUM) { + RNA_property_enum_set(ptr, prop, item->rna.enum_value); + changed = true; + } + + if (changed) { + RNA_property_update(C, ptr, prop); + } + break; + } + } + + if (item->wm_context != NULL) { + CTX_wm_area_set(C, area_prev); + CTX_wm_region_set(C, region_prev); + } +} + +static void menu_search_update_fn(const bContext *UNUSED(C), + void *arg, + const char *str, + uiSearchItems *items) +{ + struct MenuSearch_Data *data = arg; + const size_t str_len = strlen(str); + const int words_max = (str_len / 2) + 1; + int(*words)[2] = BLI_array_alloca(words, words_max); + + const int words_len = BLI_string_find_split_words(str, str_len, ' ', words, words_max); + + for (struct MenuSearch_Item *item = data->items.first; item; item = item->next) { + int index; + + /* match name against all search words */ + for (index = 0; index < words_len; index++) { + if (!ui_str_has_word_prefix(item->drawwstr_full, str + words[index][0], words[index][1])) { + break; + } + } + + if (index == words_len) { + if (!UI_search_item_add(items, item->drawwstr_full, item, item->icon, item->state)) { + break; + } + } + } +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Context Menu + * + * This uses a fake button to create a context menu, + * if this ever causes hard to solve bugs we may need to create + * a separate context menu just for the search, however this is fairly involved. + * \{ */ + +static bool ui_search_menu_create_context_menu(struct bContext *C, + void *arg, + void *active, + const struct wmEvent *UNUSED(event)) +{ + struct MenuSearch_Data *data = arg; + struct MenuSearch_Item *item = active; + bool has_menu = false; + + memset(&data->context_menu_data, 0x0, sizeof(data->context_menu_data)); + uiBut *but = &data->context_menu_data.but; + uiBlock *block = &data->context_menu_data.block; + + but->block = block; + + if (menu_items_to_ui_button(item, but)) { + ScrArea *area_prev = CTX_wm_area(C); + ARegion *region_prev = CTX_wm_region(C); + + if (item->wm_context != NULL) { + CTX_wm_area_set(C, item->wm_context->area); + CTX_wm_region_set(C, item->wm_context->region); + } + + if (ui_popup_context_menu_for_button(C, but)) { + has_menu = true; + } + + if (item->wm_context != NULL) { + CTX_wm_area_set(C, area_prev); + CTX_wm_region_set(C, region_prev); + } + } + + return has_menu; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Tooltip + * \{ */ + +static struct ARegion *ui_search_menu_create_tooltip(struct bContext *C, + struct ARegion *region, + void *arg, + void *active) +{ + struct MenuSearch_Data *data = arg; + struct MenuSearch_Item *item = active; + + memset(&data->context_menu_data, 0x0, sizeof(data->context_menu_data)); + uiBut *but = &data->context_menu_data.but; + uiBlock *block = &data->context_menu_data.block; + unit_m4(block->winmat); + block->aspect = 1; + + but->block = block; + + /* Place the fake button at the cursor so the tool-tip is places properly. */ + float tip_init[2]; + const wmEvent *event = CTX_wm_window(C)->eventstate; + tip_init[0] = event->x; + tip_init[1] = event->y - (UI_UNIT_Y / 2); + ui_window_to_block_fl(region, block, &tip_init[0], &tip_init[1]); + + but->rect.xmin = tip_init[0]; + but->rect.xmax = tip_init[0]; + but->rect.ymin = tip_init[1]; + but->rect.ymax = tip_init[1]; + + if (menu_items_to_ui_button(item, but)) { + ScrArea *area_prev = CTX_wm_area(C); + ARegion *region_prev = CTX_wm_region(C); + + if (item->wm_context != NULL) { + CTX_wm_area_set(C, item->wm_context->area); + CTX_wm_region_set(C, item->wm_context->region); + } + + ARegion *region_tip = UI_tooltip_create_from_button(C, region, but, false); + + if (item->wm_context != NULL) { + CTX_wm_area_set(C, area_prev); + CTX_wm_region_set(C, region_prev); + } + return region_tip; + } + + return NULL; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Menu Search Template Public API + * \{ */ + +void UI_but_func_menu_search(uiBut *but) +{ + bContext *C = but->block->evil_C; + wmWindow *win = CTX_wm_window(C); + ScrArea *area = CTX_wm_area(C); + ARegion *region = CTX_wm_region(C); + /* When run from top-bar scan all areas in the current window. */ + bool include_all_areas = (area && (area->spacetype == SPACE_TOPBAR)); + struct MenuSearch_Data *data = menu_items_from_ui_create( + C, win, area, region, include_all_areas); + UI_but_func_search_set(but, + /* Generic callback. */ + ui_searchbox_create_menu, + menu_search_update_fn, + data, + menu_search_arg_free_fn, + menu_search_exec_fn, + NULL); + + UI_but_func_search_set_context_menu(but, ui_search_menu_create_context_menu); + UI_but_func_search_set_tooltip(but, ui_search_menu_create_tooltip); + UI_but_func_search_set_sep_string(but, MENU_SEP); +} + +void uiTemplateMenuSearch(uiLayout *layout) +{ + uiBlock *block; + uiBut *but; + static char search[256] = ""; + + block = uiLayoutGetBlock(layout); + UI_block_layout_set_current(block, layout); + + but = uiDefSearchBut( + block, search, 0, ICON_VIEWZOOM, sizeof(search), 0, 0, UI_UNIT_X * 6, UI_UNIT_Y, 0, 0, ""); + UI_but_func_menu_search(but); +} + +#undef MENU_SEP + +/** \} */ diff --git a/source/blender/editors/interface/interface_template_search_operator.c b/source/blender/editors/interface/interface_template_search_operator.c new file mode 100644 index 00000000000..cdf87103587 --- /dev/null +++ b/source/blender/editors/interface/interface_template_search_operator.c @@ -0,0 +1,151 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup edinterface + * + * Search available operators by scanning all and checking their poll function. + * accessed via the #WM_OT_search_operator operator. + */ + +#include <string.h> + +#include "DNA_gpencil_modifier_types.h" +#include "DNA_node_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" +#include "DNA_shader_fx_types.h" +#include "DNA_texture_types.h" + +#include "BLI_alloca.h" +#include "BLI_ghash.h" +#include "BLI_string.h" +#include "BLI_utildefines.h" + +#include "BLT_translation.h" + +#include "BKE_context.h" +#include "BKE_global.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "UI_interface.h" +#include "interface_intern.h" + +/* -------------------------------------------------------------------- */ +/** \name Operator Search Template Implementation + * \{ */ + +static void operator_search_exec_fn(bContext *C, void *UNUSED(arg1), void *arg2) +{ + wmOperatorType *ot = arg2; + + if (ot) { + WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, NULL); + } +} + +static void operator_search_update_fn(const bContext *C, + void *UNUSED(arg), + const char *str, + uiSearchItems *items) +{ + GHashIterator iter; + const size_t str_len = strlen(str); + const int words_max = (str_len / 2) + 1; + int(*words)[2] = BLI_array_alloca(words, words_max); + + const int words_len = BLI_string_find_split_words(str, str_len, ' ', words, words_max); + + for (WM_operatortype_iter(&iter); !BLI_ghashIterator_done(&iter); + BLI_ghashIterator_step(&iter)) { + wmOperatorType *ot = BLI_ghashIterator_getValue(&iter); + const char *ot_ui_name = CTX_IFACE_(ot->translation_context, ot->name); + int index; + + if ((ot->flag & OPTYPE_INTERNAL) && (G.debug & G_DEBUG_WM) == 0) { + continue; + } + + /* match name against all search words */ + for (index = 0; index < words_len; index++) { + if (!ui_str_has_word_prefix(ot_ui_name, str + words[index][0], words[index][1])) { + break; + } + } + + if (index == words_len) { + if (WM_operator_poll((bContext *)C, ot)) { + char name[256]; + int len = strlen(ot_ui_name); + + /* display name for menu, can hold hotkey */ + BLI_strncpy(name, ot_ui_name, sizeof(name)); + + /* check for hotkey */ + if (len < sizeof(name) - 6) { + if (WM_key_event_operator_string(C, + ot->idname, + WM_OP_EXEC_DEFAULT, + NULL, + true, + &name[len + 1], + sizeof(name) - len - 1)) { + name[len] = UI_SEP_CHAR; + } + } + + if (!UI_search_item_add(items, name, ot, ICON_NONE, 0)) { + break; + } + } + } + } +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Operator Search Template API + * \{ */ + +void UI_but_func_operator_search(uiBut *but) +{ + UI_but_func_search_set(but, + ui_searchbox_create_operator, + operator_search_update_fn, + NULL, + false, + operator_search_exec_fn, + NULL); +} + +void uiTemplateOperatorSearch(uiLayout *layout) +{ + uiBlock *block; + uiBut *but; + static char search[256] = ""; + + block = uiLayoutGetBlock(layout); + UI_block_layout_set_current(block, layout); + + but = uiDefSearchBut( + block, search, 0, ICON_VIEWZOOM, sizeof(search), 0, 0, UI_UNIT_X * 6, UI_UNIT_Y, 0, 0, ""); + UI_but_func_operator_search(but); +} + +/** \} */ diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index ca9f12a4219..0e67f943ee6 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -37,18 +37,12 @@ #include "DNA_shader_fx_types.h" #include "DNA_texture_types.h" -#include "BLI_alloca.h" -#include "BLI_dynstr.h" #include "BLI_fnmatch.h" -#include "BLI_ghash.h" -#include "BLI_linklist.h" #include "BLI_listbase.h" #include "BLI_math.h" -#include "BLI_memarena.h" #include "BLI_path_util.h" #include "BLI_rect.h" #include "BLI_string.h" -#include "BLI_string_utils.h" #include "BLI_timecode.h" #include "BLI_utildefines.h" @@ -73,7 +67,6 @@ #include "BKE_modifier.h" #include "BKE_object.h" #include "BKE_packedFile.h" -#include "BKE_paint.h" #include "BKE_particle.h" #include "BKE_report.h" #include "BKE_scene.h" @@ -103,9 +96,6 @@ #include "PIL_time.h" -/* For key-map item access. */ -#include "wm_event_system.h" - // #define USE_OP_RESET_BUT // we may want to make this optional, disable for now. /* defines for templateID/TemplateSearch */ @@ -213,9 +203,9 @@ static void template_add_button_search_menu(const bContext *C, static uiBlock *template_common_search_menu(const bContext *C, ARegion *region, - uiButSearchFunc search_func, + uiButSearchUpdateFn search_update_fn, void *search_arg, - uiButHandleFunc handle_func, + uiButHandleFunc search_exec_fn, void *active_item, const int preview_rows, const int preview_cols, @@ -289,11 +279,10 @@ static uiBlock *template_common_search_menu(const bContext *C, } UI_but_func_search_set(but, ui_searchbox_create_generic, - search_func, + search_update_fn, search_arg, NULL, - handle_func, - NULL, + search_exec_fn, active_item); UI_block_bounds_set_normal(block, 0.3f * U.widget_unit); @@ -326,7 +315,7 @@ typedef struct TemplateID { } TemplateID; /* Search browse menu, assign */ -static void template_ID_set_property_cb(bContext *C, void *arg_template, void *item) +static void template_ID_set_property_exec_fn(bContext *C, void *arg_template, void *item) { TemplateID *template_ui = (TemplateID *)arg_template; @@ -461,7 +450,8 @@ static uiBlock *id_search_menu(bContext *C, ARegion *region, void *arg_litem) { static TemplateID template_ui; PointerRNA active_item_ptr; - void (*id_search_cb_p)(const bContext *, void *, const char *, uiSearchItems *) = id_search_cb; + void (*id_search_update_fn)( + const bContext *, void *, const char *, uiSearchItems *) = id_search_cb; /* arg_litem is malloced, can be freed by parent button */ template_ui = *((TemplateID *)arg_litem); @@ -471,16 +461,16 @@ static uiBlock *id_search_menu(bContext *C, ARegion *region, void *arg_litem) /* Currently only used for objects. */ if (template_ui.idcode == ID_OB) { if (template_ui.filter == UI_TEMPLATE_ID_FILTER_AVAILABLE) { - id_search_cb_p = id_search_cb_objects_from_scene; + id_search_update_fn = id_search_cb_objects_from_scene; } } } return template_common_search_menu(C, region, - id_search_cb_p, + id_search_update_fn, &template_ui, - template_ID_set_property_cb, + template_ID_set_property_exec_fn, active_item_ptr.data, template_ui.prv_rows, template_ui.prv_cols, @@ -688,6 +678,8 @@ static const char *template_id_browse_tip(const StructRNA *type) return N_("Browse Point Cloud Data to be linked"); case ID_VO: return N_("Browse Volume Data to be linked"); + case ID_SIM: + return N_("Browse Simulation to be linked"); } } return N_("Browse ID data to be linked"); @@ -705,6 +697,8 @@ static const char *template_id_context(StructRNA *type) } return BLT_I18NCONTEXT_DEFAULT; } +#else +# define template_id_context(type) 0 #endif static uiBut *template_id_def_new_but(uiBlock *block, @@ -753,7 +747,8 @@ static uiBut *template_id_def_new_but(uiBlock *block, BLT_I18NCONTEXT_ID_LIGHTPROBE, BLT_I18NCONTEXT_ID_HAIR, BLT_I18NCONTEXT_ID_POINTCLOUD, - BLT_I18NCONTEXT_ID_VOLUME, ); + BLT_I18NCONTEXT_ID_VOLUME, + BLT_I18NCONTEXT_ID_SIMULATION, ); /* Note: BLT_I18N_MSGID_MULTI_CTXT takes a maximum number of parameters, * check the definition to see if a new call must be added when the limit * is exceeded. */ @@ -1187,7 +1182,7 @@ static void template_ID_tabs(bContext *C, 0.0f, 0.0f, ""); - UI_but_funcN_set(&tab->but, template_ID_set_property_cb, MEM_dupallocN(template), id); + UI_but_funcN_set(&tab->but, template_ID_set_property_exec_fn, MEM_dupallocN(template), id); tab->but.custom_data = (void *)id; tab->but.dragpoin = id; tab->menu = mt; @@ -1533,7 +1528,7 @@ typedef struct TemplateSearch { int preview_rows, preview_cols; } TemplateSearch; -static void template_search_handle_cb(bContext *C, void *arg_template, void *item) +static void template_search_exec_fn(bContext *C, void *arg_template, void *item) { TemplateSearch *template_search = arg_template; uiRNACollectionSearch *coll_search = &template_search->search_data; @@ -1557,9 +1552,9 @@ static uiBlock *template_search_menu(bContext *C, ARegion *region, void *arg_tem return template_common_search_menu(C, region, - ui_rna_collection_search_cb, + ui_rna_collection_search_update_fn, &template_search, - template_search_handle_cb, + template_search_exec_fn, active_ptr.data, template_search.preview_rows, template_search.preview_cols, @@ -1823,14 +1818,14 @@ static void modifiers_convertToReal(bContext *C, void *ob_v, void *md_v) { Object *ob = ob_v; ModifierData *md = md_v; - ModifierData *nmd = modifier_new(md->type); + ModifierData *nmd = BKE_modifier_new(md->type); - modifier_copyData(md, nmd); + BKE_modifier_copydata(md, nmd); nmd->mode &= ~eModifierMode_Virtual; BLI_addhead(&ob->modifiers, nmd); - modifier_unique_name(&ob->modifiers, nmd); + BKE_modifier_unique_name(&ob->modifiers, nmd); ob->partype = PAROBJECT; @@ -1840,20 +1835,26 @@ static void modifiers_convertToReal(bContext *C, void *ob_v, void *md_v) ED_undo_push(C, "Modifier convert to real"); } -static int modifier_can_delete(ModifierData *md) +static bool modifier_can_delete(ModifierData *md) { /* fluid particle modifier can't be deleted here */ if (md->type == eModifierType_ParticleSystem) { short particle_type = ((ParticleSystemModifierData *)md)->psys->part->type; - if (particle_type == PART_FLUID || particle_type == PART_FLUID_FLIP || - particle_type == PART_FLUID_FOAM || particle_type == PART_FLUID_SPRAY || - particle_type == PART_FLUID_BUBBLE || particle_type == PART_FLUID_TRACER || - particle_type == PART_FLUID_SPRAYFOAM || particle_type == PART_FLUID_SPRAYBUBBLE || - particle_type == PART_FLUID_FOAMBUBBLE || particle_type == PART_FLUID_SPRAYFOAMBUBBLE) { - return 0; + if (ELEM(particle_type, + PART_FLUID, + PART_FLUID_FLIP, + PART_FLUID_FOAM, + PART_FLUID_SPRAY, + PART_FLUID_BUBBLE, + PART_FLUID_TRACER, + PART_FLUID_SPRAYFOAM, + PART_FLUID_SPRAYBUBBLE, + PART_FLUID_FOAMBUBBLE, + PART_FLUID_SPRAYFOAMBUBBLE)) { + return false; } } - return 1; + return true; } /* Check whether Modifier is a simulation or not, @@ -1888,7 +1889,7 @@ static uiLayout *draw_modifier(uiLayout *layout, int cageIndex, int lastCageIndex) { - const ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); PointerRNA ptr; uiBut *but; uiBlock *block; @@ -1982,9 +1983,9 @@ static uiLayout *draw_modifier(uiLayout *layout, } if (ob->type == OB_MESH) { - if (modifier_supportsCage(scene, md) && (index <= lastCageIndex)) { + if (BKE_modifier_supports_cage(scene, md) && (index <= lastCageIndex)) { sub = uiLayoutRow(row, true); - if (index < cageIndex || !modifier_couldBeCage(scene, md)) { + if (index < cageIndex || !BKE_modifier_couldbe_cage(scene, md)) { uiLayoutSetActive(sub, false); } uiItemR(sub, &ptr, "show_on_cage", 0, "", ICON_NONE); @@ -2080,7 +2081,7 @@ static uiLayout *draw_modifier(uiLayout *layout, "apply_as", MODIFIER_APPLY_DATA); - if (modifier_isSameTopology(md) && !modifier_isNonGeometrical(md)) { + if (BKE_modifier_is_same_topology(md) && !BKE_modifier_is_non_geometrical(md)) { uiItemEnumO(row, "OBJECT_OT_modifier_apply", CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Apply as Shape Key"), @@ -2147,10 +2148,10 @@ uiLayout *uiTemplateModifier(uiLayout *layout, bContext *C, PointerRNA *ptr) UI_block_lock_set(uiLayoutGetBlock(layout), (ob && ID_IS_LINKED(ob)), ERROR_LIBDATA_MESSAGE); /* find modifier and draw it */ - cageIndex = modifiers_getCageIndex(scene, ob, &lastCageIndex, 0); + cageIndex = BKE_modifiers_get_cage_index(scene, ob, &lastCageIndex, 0); /* XXX virtual modifiers are not accessible for python */ - vmd = modifiers_getVirtualModifierList(ob, &virtualModifierData); + vmd = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData); for (i = 0; vmd; i++, vmd = vmd->next) { if (md == vmd) { @@ -2172,7 +2173,7 @@ uiLayout *uiTemplateModifier(uiLayout *layout, bContext *C, PointerRNA *ptr) static uiLayout *gpencil_draw_modifier(uiLayout *layout, Object *ob, GpencilModifierData *md) { - const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type); + const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type); PointerRNA ptr; uiBlock *block; uiLayout *box, *column, *row, *sub; @@ -2315,7 +2316,7 @@ uiLayout *uiTemplateGpencilModifier(uiLayout *layout, bContext *UNUSED(C), Point static uiLayout *gpencil_draw_shaderfx(uiLayout *layout, Object *ob, ShaderFxData *md) { - const ShaderFxTypeInfo *mti = BKE_shaderfxType_getInfo(md->type); + const ShaderFxTypeInfo *mti = BKE_shaderfx_get_info(md->type); PointerRNA ptr; uiBlock *block; uiLayout *box, *column, *row, *sub; @@ -2432,21 +2433,196 @@ uiLayout *uiTemplateShaderFx(uiLayout *layout, bContext *UNUSED(C), PointerRNA * /** \} */ /* -------------------------------------------------------------------- */ -/** \name Operator Redo Buttons Template +/** \name Operator Property Buttons Template * \{ */ -static void template_operator_redo_property_buts_draw( - const bContext *C, wmOperator *op, uiLayout *layout, int layout_flags, bool *r_has_advanced) +typedef struct uiTemplateOperatorPropertyPollParam { + const bContext *C; + wmOperator *op; + short flag; +} uiTemplateOperatorPropertyPollParam; + +#ifdef USE_OP_RESET_BUT +static void ui_layout_operator_buts__reset_cb(bContext *UNUSED(C), + void *op_pt, + void *UNUSED(arg_dummy2)) +{ + WM_operator_properties_reset((wmOperator *)op_pt); +} +#endif + +static bool ui_layout_operator_buts_poll_property(struct PointerRNA *UNUSED(ptr), + struct PropertyRNA *prop, + void *user_data) +{ + uiTemplateOperatorPropertyPollParam *params = user_data; + + if ((params->flag & UI_TEMPLATE_OP_PROPS_HIDE_ADVANCED) && + (RNA_property_tags(prop) & OP_PROP_TAG_ADVANCED)) { + return false; + } + return params->op->type->poll_property(params->C, params->op, prop); +} + +static eAutoPropButsReturn template_operator_property_buts_draw_single( + const bContext *C, + wmOperator *op, + uiLayout *layout, + const eButLabelAlign label_align, + int layout_flags) +{ + uiBlock *block = uiLayoutGetBlock(layout); + eAutoPropButsReturn return_info = 0; + + if (!op->properties) { + IDPropertyTemplate val = {0}; + op->properties = IDP_New(IDP_GROUP, &val, "wmOperatorProperties"); + } + + /* poll() on this operator may still fail, + * at the moment there is no nice feedback when this happens just fails silently. */ + if (!WM_operator_repeat_check(C, op)) { + UI_block_lock_set(block, true, "Operator can't' redo"); + return return_info; + } + else { + /* useful for macros where only one of the steps can't be re-done */ + UI_block_lock_clear(block); + } + + if (layout_flags & UI_TEMPLATE_OP_PROPS_SHOW_TITLE) { + uiItemL(layout, WM_operatortype_name(op->type, op->ptr), ICON_NONE); + } + + /* menu */ + if (op->type->flag & OPTYPE_PRESET) { + /* XXX, no simple way to get WM_MT_operator_presets.bl_label + * from python! Label remains the same always! */ + PointerRNA op_ptr; + uiLayout *row; + + block->ui_operator = op; + + row = uiLayoutRow(layout, true); + uiItemM(row, "WM_MT_operator_presets", NULL, ICON_NONE); + + wmOperatorType *ot = WM_operatortype_find("WM_OT_operator_preset_add", false); + uiItemFullO_ptr(row, ot, "", ICON_ADD, NULL, WM_OP_INVOKE_DEFAULT, 0, &op_ptr); + RNA_string_set(&op_ptr, "operator", op->type->idname); + + uiItemFullO_ptr(row, ot, "", ICON_REMOVE, NULL, WM_OP_INVOKE_DEFAULT, 0, &op_ptr); + RNA_string_set(&op_ptr, "operator", op->type->idname); + RNA_boolean_set(&op_ptr, "remove_active", true); + } + + if (op->type->ui) { + op->layout = layout; + op->type->ui((bContext *)C, op); + op->layout = NULL; + + /* UI_LAYOUT_OP_SHOW_EMPTY ignored. retun_info is ignored too. We could + * allow ot.ui callback to return this, but not needed right now. */ + } + else { + wmWindowManager *wm = CTX_wm_manager(C); + PointerRNA ptr; + uiTemplateOperatorPropertyPollParam user_data = {.C = C, .op = op, .flag = layout_flags}; + const bool use_prop_split = (layout_flags & UI_TEMPLATE_OP_PROPS_NO_SPLIT_LAYOUT) == 0; + + RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr); + + uiLayoutSetPropSep(layout, use_prop_split); + uiLayoutSetPropDecorate(layout, false); + + /* main draw call */ + return_info = uiDefAutoButsRNA( + layout, + &ptr, + op->type->poll_property ? ui_layout_operator_buts_poll_property : NULL, + op->type->poll_property ? &user_data : NULL, + op->type->prop, + label_align, + (layout_flags & UI_TEMPLATE_OP_PROPS_COMPACT)); + + if ((return_info & UI_PROP_BUTS_NONE_ADDED) && + (layout_flags & UI_TEMPLATE_OP_PROPS_SHOW_EMPTY)) { + uiItemL(layout, IFACE_("No Properties"), ICON_NONE); + } + } + +#ifdef USE_OP_RESET_BUT + /* its possible that reset can do nothing if all have PROP_SKIP_SAVE enabled + * but this is not so important if this button is drawn in those cases + * (which isn't all that likely anyway) - campbell */ + if (op->properties->len) { + uiBut *but; + uiLayout *col; /* needed to avoid alignment errors with previous buttons */ + + col = uiLayoutColumn(layout, false); + block = uiLayoutGetBlock(col); + but = uiDefIconTextBut(block, + UI_BTYPE_BUT, + 0, + ICON_FILE_REFRESH, + IFACE_("Reset"), + 0, + 0, + UI_UNIT_X, + UI_UNIT_Y, + NULL, + 0.0, + 0.0, + 0.0, + 0.0, + TIP_("Reset operator defaults")); + UI_but_func_set(but, ui_layout_operator_buts__reset_cb, op, NULL); + } +#endif + + /* set various special settings for buttons */ + + /* Only do this if we're not refreshing an existing UI. */ + if (block->oldblock == NULL) { + const bool is_popup = (block->flag & UI_BLOCK_KEEP_OPEN) != 0; + uiBut *but; + + for (but = block->buttons.first; but; but = but->next) { + /* no undo for buttons for operator redo panels */ + UI_but_flag_disable(but, UI_BUT_UNDO); + + /* only for popups, see [#36109] */ + + /* if button is operator's default property, and a text-field, enable focus for it + * - this is used for allowing operators with popups to rename stuff with fewer clicks + */ + if (is_popup) { + if ((but->rnaprop == op->type->prop) && (but->type == UI_BTYPE_TEXT)) { + UI_but_focus_on_enter_event(CTX_wm_window(C), but); + } + } + } + } + + return return_info; +} + +static void template_operator_property_buts_draw_recursive(const bContext *C, + wmOperator *op, + uiLayout *layout, + const eButLabelAlign label_align, + int layout_flags, + bool *r_has_advanced) { if (op->type->flag & OPTYPE_MACRO) { LISTBASE_FOREACH (wmOperator *, macro_op, &op->macro) { - template_operator_redo_property_buts_draw(C, macro_op, layout, layout_flags, r_has_advanced); + template_operator_property_buts_draw_recursive( + C, macro_op, layout, label_align, layout_flags, r_has_advanced); } } else { /* Might want to make label_align adjustable somehow. */ - eAutoPropButsReturn return_info = uiTemplateOperatorPropertyButs( - C, layout, op, UI_BUT_LABEL_ALIGN_NONE, layout_flags); + eAutoPropButsReturn return_info = template_operator_property_buts_draw_single( + C, op, layout, label_align, layout_flags); if (return_info & UI_PROP_BUTS_ANY_FAILED_CHECK) { if (r_has_advanced) { *r_has_advanced = true; @@ -2455,6 +2631,61 @@ static void template_operator_redo_property_buts_draw( } } +static bool ui_layout_operator_properties_only_booleans(const bContext *C, + wmWindowManager *wm, + wmOperator *op, + int layout_flags) +{ + if (op->type->flag & OPTYPE_MACRO) { + LISTBASE_FOREACH (wmOperator *, macro_op, &op->macro) { + if (!ui_layout_operator_properties_only_booleans(C, wm, macro_op, layout_flags)) { + return false; + } + } + } + else { + uiTemplateOperatorPropertyPollParam user_data = {.C = C, .op = op, .flag = layout_flags}; + PointerRNA ptr; + + RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr); + + RNA_STRUCT_BEGIN (&ptr, prop) { + if (RNA_property_flag(prop) & PROP_HIDDEN) { + continue; + } + if (op->type->poll_property && + !ui_layout_operator_buts_poll_property(&ptr, prop, &user_data)) { + continue; + } + if (RNA_property_type(prop) != PROP_BOOLEAN) { + return false; + } + } + RNA_STRUCT_END; + } + + return true; +} + +/** + * Draw Operator property buttons for redoing execution with different settings. + * This function does not initialize the layout, + * functions can be called on the layout before and after. + */ +void uiTemplateOperatorPropertyButs( + const bContext *C, uiLayout *layout, wmOperator *op, eButLabelAlign label_align, short flag) +{ + wmWindowManager *wm = CTX_wm_manager(C); + + /* If there are only checkbox items, don't use split layout by default. It looks weird if the + * checkboxes only use half the width. */ + if (ui_layout_operator_properties_only_booleans(C, wm, op, flag)) { + flag |= UI_TEMPLATE_OP_PROPS_NO_SPLIT_LAYOUT; + } + + template_operator_property_buts_draw_recursive(C, op, layout, label_align, flag, NULL); +} + void uiTemplateOperatorRedoProperties(uiLayout *layout, const bContext *C) { wmOperator *op = WM_operator_last_redo(C); @@ -2487,8 +2718,8 @@ void uiTemplateOperatorRedoProperties(uiLayout *layout, const bContext *C) #endif UI_block_func_handle_set(block, ED_undo_operator_repeat_cb_evt, op); - template_operator_redo_property_buts_draw( - C, op, layout, layout_flags, NULL /* &has_advanced */); + template_operator_property_buts_draw_recursive( + C, op, layout, UI_BUT_LABEL_ALIGN_NONE, layout_flags, NULL /* &has_advanced */); /* Warning! this leaves the handle function for any other users of this block. */ #if 0 @@ -6583,952 +6814,6 @@ void uiTemplateList(uiLayout *layout, /** \} */ /* -------------------------------------------------------------------- */ -/** \name Operator Search Template - * \{ */ - -static void operator_call_cb(bContext *C, void *UNUSED(arg1), void *arg2) -{ - wmOperatorType *ot = arg2; - - if (ot) { - WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, NULL); - } -} - -static bool has_word_prefix(const char *haystack, const char *needle, size_t needle_len) -{ - const char *match = BLI_strncasestr(haystack, needle, needle_len); - if (match) { - if ((match == haystack) || (*(match - 1) == ' ') || ispunct(*(match - 1))) { - return true; - } - else { - return has_word_prefix(match + 1, needle, needle_len); - } - } - else { - return false; - } -} - -static void operator_search_cb(const bContext *C, - void *UNUSED(arg), - const char *str, - uiSearchItems *items) -{ - GHashIterator iter; - const size_t str_len = strlen(str); - const int words_max = (str_len / 2) + 1; - int(*words)[2] = BLI_array_alloca(words, words_max); - - const int words_len = BLI_string_find_split_words(str, str_len, ' ', words, words_max); - - for (WM_operatortype_iter(&iter); !BLI_ghashIterator_done(&iter); - BLI_ghashIterator_step(&iter)) { - wmOperatorType *ot = BLI_ghashIterator_getValue(&iter); - const char *ot_ui_name = CTX_IFACE_(ot->translation_context, ot->name); - int index; - - if ((ot->flag & OPTYPE_INTERNAL) && (G.debug & G_DEBUG_WM) == 0) { - continue; - } - - /* match name against all search words */ - for (index = 0; index < words_len; index++) { - if (!has_word_prefix(ot_ui_name, str + words[index][0], words[index][1])) { - break; - } - } - - if (index == words_len) { - if (WM_operator_poll((bContext *)C, ot)) { - char name[256]; - int len = strlen(ot_ui_name); - - /* display name for menu, can hold hotkey */ - BLI_strncpy(name, ot_ui_name, sizeof(name)); - - /* check for hotkey */ - if (len < sizeof(name) - 6) { - if (WM_key_event_operator_string(C, - ot->idname, - WM_OP_EXEC_DEFAULT, - NULL, - true, - &name[len + 1], - sizeof(name) - len - 1)) { - name[len] = UI_SEP_CHAR; - } - } - - if (!UI_search_item_add(items, name, ot, ICON_NONE, 0)) { - break; - } - } - } - } -} - -void UI_but_func_operator_search(uiBut *but) -{ - UI_but_func_search_set(but, - ui_searchbox_create_operator, - operator_search_cb, - NULL, - false, - operator_call_cb, - NULL, - NULL); -} - -void uiTemplateOperatorSearch(uiLayout *layout) -{ - uiBlock *block; - uiBut *but; - static char search[256] = ""; - - block = uiLayoutGetBlock(layout); - UI_block_layout_set_current(block, layout); - - but = uiDefSearchBut( - block, search, 0, ICON_VIEWZOOM, sizeof(search), 0, 0, UI_UNIT_X * 6, UI_UNIT_Y, 0, 0, ""); - UI_but_func_operator_search(but); -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Menu Search Template - * \{ */ - -/* Unicode arrow. */ -#define MENU_SEP "\xe2\x96\xb6" - -struct MenuSearch_Parent { - struct MenuSearch_Parent *parent; - MenuType *parent_mt; - /* Set while writing menu items only. */ - struct MenuSearch_Parent *temp_child; - const char *drawstr; -}; - -struct MenuSearch_Item { - struct MenuSearch_Item *next, *prev; - const char *drawstr; - const char *drawwstr_full; - /** Support a single level sub-menu nesting (for operator buttons that expand). */ - const char *drawstr_submenu; - int icon; - int state; - - struct MenuSearch_Parent *menu_parent; - MenuType *mt; - - enum { - MENU_SEARCH_TYPE_OP = 1, - MENU_SEARCH_TYPE_RNA = 2, - } type; - - union { - /* Operator menu item. */ - struct { - wmOperatorType *type; - PointerRNA *opptr; - short opcontext; - bContextStore *context; - } op; - - /* Property (only for check-boxe/boolean). */ - struct { - PointerRNA ptr; - PropertyRNA *prop; - int index; - /** Only for enum buttons. */ - int enum_value; - } rna; - }; -}; - -struct MenuSearch_Data { - /** MenuSearch_Item */ - ListBase items; - /** Use for all small allocations. */ - MemArena *memarena; -}; - -static int menu_item_sort_by_drawstr_full(const void *menu_item_a_v, const void *menu_item_b_v) -{ - const struct MenuSearch_Item *menu_item_a = menu_item_a_v; - const struct MenuSearch_Item *menu_item_b = menu_item_b_v; - return strcmp(menu_item_a->drawwstr_full, menu_item_b->drawwstr_full); -} - -static const char *strdup_memarena(MemArena *memarena, const char *str) -{ - const uint str_size = strlen(str) + 1; - char *str_dst = BLI_memarena_alloc(memarena, str_size); - memcpy(str_dst, str, str_size); - return str_dst; -} - -static const char *strdup_memarena_from_dynstr(MemArena *memarena, DynStr *dyn_str) -{ - const uint str_size = BLI_dynstr_get_len(dyn_str) + 1; - char *str_dst = BLI_memarena_alloc(memarena, str_size); - BLI_dynstr_get_cstring_ex(dyn_str, str_dst); - return str_dst; -} - -static bool menu_items_from_ui_create_item_from_button(struct MenuSearch_Data *data, - MemArena *memarena, - struct MenuType *mt, - const char *drawstr_submenu, - uiBut *but) -{ - struct MenuSearch_Item *item = NULL; - if (but->optype != NULL) { - item = BLI_memarena_calloc(memarena, sizeof(*item)); - item->type = MENU_SEARCH_TYPE_OP; - - item->op.type = but->optype; - item->op.opcontext = but->opcontext; - item->op.context = but->context; - item->op.opptr = but->opptr; - but->opptr = NULL; - } - else if (but->rnaprop != NULL) { - const int prop_type = RNA_property_type(but->rnaprop); - if (!ELEM(prop_type, PROP_BOOLEAN, PROP_ENUM)) { - /* Note that these buttons are not prevented, - * but aren't typically used in menus. */ - printf("Button '%s' in menu '%s' is a menu item with unsupported RNA type %d\n", - but->drawstr, - mt->idname, - prop_type); - } - else { - item = BLI_memarena_calloc(memarena, sizeof(*item)); - item->type = MENU_SEARCH_TYPE_RNA; - - item->rna.ptr = but->rnapoin; - item->rna.prop = but->rnaprop; - item->rna.index = but->rnaindex; - - if (prop_type == PROP_ENUM) { - item->rna.enum_value = (int)but->hardmax; - } - } - } - - if (item != NULL) { - /* Handle shared settings. */ - item->drawstr = strdup_memarena(memarena, but->drawstr); - item->icon = ui_but_icon(but); - item->state = (but->flag & (UI_BUT_DISABLED | UI_BUT_INACTIVE | UI_BUT_REDALERT)); - item->mt = mt; - item->drawstr_submenu = drawstr_submenu ? strdup_memarena(memarena, drawstr_submenu) : NULL; - BLI_addtail(&data->items, item); - return true; - } - - return false; -} - -/** - * Populate \a menu_stack with menus from inspecting active key-maps for this context. - */ -static void menu_types_add_from_keymap_items(bContext *C, - wmWindow *win, - ScrArea *area, - ARegion *region, - LinkNode **menuid_stack_p, - GHash *menu_to_kmi, - GSet *menu_tagged) -{ - wmWindowManager *wm = CTX_wm_manager(C); - ListBase *handlers[] = { - region ? ®ion->handlers : NULL, - area ? &area->handlers : NULL, - &win->handlers, - }; - - for (int handler_index = 0; handler_index < ARRAY_SIZE(handlers); handler_index++) { - if (handlers[handler_index] == NULL) { - continue; - } - LISTBASE_FOREACH (wmEventHandler *, handler_base, handlers[handler_index]) { - /* During this loop, ui handlers for nested menus can tag multiple handlers free. */ - if (handler_base->flag & WM_HANDLER_DO_FREE) { - continue; - } - if (handler_base->type != WM_HANDLER_TYPE_KEYMAP) { - continue; - } - - else if (handler_base->poll == NULL || handler_base->poll(region, win->eventstate)) { - wmEventHandler_Keymap *handler = (wmEventHandler_Keymap *)handler_base; - wmKeyMap *keymap = WM_event_get_keymap_from_handler(wm, handler); - if (keymap && WM_keymap_poll(C, keymap)) { - LISTBASE_FOREACH (wmKeyMapItem *, kmi, &keymap->items) { - if (kmi->flag & KMI_INACTIVE) { - continue; - } - if (STR_ELEM(kmi->idname, "WM_OT_call_menu", "WM_OT_call_menu_pie")) { - char menu_idname[MAX_NAME]; - RNA_string_get(kmi->ptr, "name", menu_idname); - MenuType *mt = WM_menutype_find(menu_idname, false); - - if (mt && BLI_gset_add(menu_tagged, mt)) { - /* Unlikely, but possible this will be included twice. */ - BLI_linklist_prepend(menuid_stack_p, mt); - - void **kmi_p; - if (!BLI_ghash_ensure_p(menu_to_kmi, mt, &kmi_p)) { - *kmi_p = kmi; - } - } - } - } - } - } - } - } -} - -/** - * Create #MenuSearch_Data by inspecting the current context, this uses two methods: - * - * - Look-up pre-defined editor-menus. - * - Look-up key-map items which call menus. - */ -static struct MenuSearch_Data *menu_items_from_ui_create(bContext *C, - wmWindow *win, - ScrArea *area, - ARegion *region) -{ - MemArena *memarena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); - /** Map (#MenuType to #MenuSearch_Parent) */ - GHash *menu_parent_map = BLI_ghash_ptr_new(__func__); - GHash *menu_display_name_map = BLI_ghash_ptr_new(__func__); - const uiStyle *style = UI_style_get_dpi(); - - /* Convert into non-ui structure. */ - struct MenuSearch_Data *data = MEM_callocN(sizeof(*data), __func__); - - DynStr *dyn_str = BLI_dynstr_new_memarena(); - - /* Use a stack of menus to handle and discover new menus in passes. */ - LinkNode *menu_stack = NULL; - - /* Tag menu types not to add, either because they have already been added - * or they have been blacklisted. - * Set of #MenuType. */ - GSet *menu_tagged = BLI_gset_ptr_new(__func__); - /** Map (#MenuType -> #wmKeyMapItem). */ - GHash *menu_to_kmi = BLI_ghash_ptr_new(__func__); - - /* Blacklist menus we don't want to show. */ - { - const char *idname_array[] = { - /* While we could include this, it's just showing filenames to load. */ - "TOPBAR_MT_file_open_recent", - }; - for (int i = 0; i < ARRAY_SIZE(idname_array); i++) { - MenuType *mt = WM_menutype_find(idname_array[i], false); - if (mt != NULL) { - BLI_gset_add(menu_tagged, mt); - } - } - } - - /* Populate menus from the editors, - * note that we could create a fake header, draw the header and extract the menus - * from the buttons, however this is quite involved and can be avoided as by convention - * each space-type has a single root-menu that headers use. */ - { - const char *idname_array[] = { - "TOPBAR_MT_editor_menus", - /* Optional second menu for the space-type. */ - NULL, - }; - int idname_array_len = 1; - -#define SPACE_MENU_MAP(space_type, menu_id) \ - case space_type: \ - idname_array[idname_array_len++] = menu_id; \ - break -#define SPACE_MENU_NOP(space_type) \ - case space_type: \ - break - - if (area != NULL) { - switch (area->spacetype) { - SPACE_MENU_MAP(SPACE_VIEW3D, "VIEW3D_MT_editor_menus"); - SPACE_MENU_MAP(SPACE_GRAPH, "GRAPH_MT_editor_menus"); - SPACE_MENU_MAP(SPACE_OUTLINER, "OUTLINER_MT_editor_menus"); - SPACE_MENU_NOP(SPACE_PROPERTIES); - SPACE_MENU_MAP(SPACE_FILE, "FILE_MT_editor_menus"); - SPACE_MENU_MAP(SPACE_IMAGE, "IMAGE_MT_editor_menus"); - SPACE_MENU_MAP(SPACE_INFO, "INFO_MT_editor_menus"); - SPACE_MENU_MAP(SPACE_SEQ, "SEQUENCER_MT_editor_menus"); - SPACE_MENU_MAP(SPACE_TEXT, "TEXT_MT_editor_menus"); - SPACE_MENU_MAP(SPACE_ACTION, "DOPESHEET_MT_editor_menus"); - SPACE_MENU_MAP(SPACE_NLA, "NLA_MT_editor_menus"); - SPACE_MENU_MAP(SPACE_NODE, "NODE_MT_editor_menus"); - SPACE_MENU_MAP(SPACE_CONSOLE, "CONSOLE_MT_editor_menus"); - SPACE_MENU_MAP(SPACE_USERPREF, "USERPREF_MT_editor_menus"); - SPACE_MENU_MAP(SPACE_CLIP, - (((const SpaceClip *)area->spacedata.first)->mode == SC_MODE_TRACKING) ? - "CLIP_MT_tracking_editor_menus" : - "CLIP_MT_masking_editor_menus"); - SPACE_MENU_NOP(SPACE_TOPBAR); - SPACE_MENU_NOP(SPACE_STATUSBAR); - default: - printf("Unknown space type '%d'\n", area->spacetype); - } - } - for (int i = 0; i < idname_array_len; i++) { - MenuType *mt = WM_menutype_find(idname_array[i], false); - if (mt != NULL) { - BLI_linklist_prepend(&menu_stack, mt); - BLI_gset_add(menu_tagged, mt); - } - } - } -#undef SPACE_MENU_MAP -#undef SPACE_MENU_NOP - - bool has_keymap_menu_items = false; - - GHashIterator iter; - - while (menu_stack != NULL) { - MenuType *mt = BLI_linklist_pop(&menu_stack); - if (!WM_menutype_poll(C, mt)) { - continue; - } - - uiBlock *block = UI_block_begin(C, region, __func__, UI_EMBOSS); - uiLayout *layout = UI_block_layout( - block, UI_LAYOUT_VERTICAL, UI_LAYOUT_MENU, 0, 0, 200, 0, UI_MENU_PADDING, style); - - UI_block_flag_enable(block, UI_BLOCK_SHOW_SHORTCUT_ALWAYS); - - uiLayoutSetOperatorContext(layout, WM_OP_INVOKE_REGION_WIN); - UI_menutype_draw(C, mt, layout); - - UI_block_end(C, block); - - LISTBASE_FOREACH (uiBut *, but, &block->buttons) { - MenuType *mt_from_but = NULL; - /* Support menu titles with dynamic from initial labels - * (used by edit-mesh context menu). */ - if (but->type == UI_BTYPE_LABEL) { - - /* Check if the label is the title. */ - uiBut *but_test = but->prev; - while (but_test && but_test->type == UI_BTYPE_SEPR) { - but_test = but_test->prev; - } - - if (but_test == NULL) { - BLI_ghash_insert( - menu_display_name_map, mt, (void *)strdup_memarena(memarena, but->drawstr)); - } - } - else if (menu_items_from_ui_create_item_from_button(data, memarena, mt, NULL, but)) { - /* pass */ - } - else if ((mt_from_but = UI_but_menutype_get(but))) { - - if (BLI_gset_add(menu_tagged, mt_from_but)) { - BLI_linklist_prepend(&menu_stack, mt_from_but); - } - - if (!BLI_ghash_haskey(menu_parent_map, mt_from_but)) { - struct MenuSearch_Parent *menu_parent = BLI_memarena_calloc(memarena, - sizeof(*menu_parent)); - /* Use brackets for menu key shortcuts, - * converting "Text|Some-Shortcut" to "Text (Some-Shortcut)". - * This is needed so we don't right align sub-menu contents - * we only want to do that for the last menu item, not the path that leads to it. - */ - const char *drawstr_sep = but->flag & UI_BUT_HAS_SEP_CHAR ? - strrchr(but->drawstr, UI_SEP_CHAR) : - NULL; - bool drawstr_is_empty = false; - if (drawstr_sep != NULL) { - BLI_assert(BLI_dynstr_get_len(dyn_str) == 0); - /* Detect empty string, fallback to menu name. */ - const char *drawstr = but->drawstr; - int drawstr_len = drawstr_sep - but->drawstr; - if (UNLIKELY(drawstr_len == 0)) { - drawstr = CTX_IFACE_(mt_from_but->translation_context, mt_from_but->label); - drawstr_len = strlen(drawstr); - if (drawstr[0] == '\0') { - drawstr_is_empty = true; - } - } - BLI_dynstr_nappend(dyn_str, drawstr, drawstr_len); - BLI_dynstr_appendf(dyn_str, " (%s)", drawstr_sep + 1); - menu_parent->drawstr = strdup_memarena_from_dynstr(memarena, dyn_str); - BLI_dynstr_clear(dyn_str); - } - else { - const char *drawstr = but->drawstr; - if (UNLIKELY(drawstr[0] == '\0')) { - drawstr = CTX_IFACE_(mt_from_but->translation_context, mt_from_but->label); - if (drawstr[0] == '\0') { - drawstr_is_empty = true; - } - } - menu_parent->drawstr = strdup_memarena(memarena, drawstr); - } - menu_parent->parent_mt = mt; - BLI_ghash_insert(menu_parent_map, mt_from_but, menu_parent); - - if (drawstr_is_empty) { - printf("Warning: '%s' menu has empty 'bl_label'.\n", mt_from_but->idname); - } - } - } - else if (but->menu_create_func != NULL) { - /* A non 'MenuType' menu button. */ - - /* Only expand one level deep, this is mainly for expanding operator menus. */ - const char *drawstr_submenu = but->drawstr; - - /* +1 to avoid overlap with the current 'block'. */ - uiBlock *sub_block = UI_block_begin(C, region, __func__ + 1, UI_EMBOSS); - uiLayout *sub_layout = UI_block_layout( - sub_block, UI_LAYOUT_VERTICAL, UI_LAYOUT_MENU, 0, 0, 200, 0, UI_MENU_PADDING, style); - - UI_block_flag_enable(sub_block, UI_BLOCK_SHOW_SHORTCUT_ALWAYS); - - uiLayoutSetOperatorContext(sub_layout, WM_OP_INVOKE_REGION_WIN); - - but->menu_create_func(C, sub_layout, but->poin); - - UI_block_end(C, sub_block); - - LISTBASE_FOREACH (uiBut *, sub_but, &sub_block->buttons) { - menu_items_from_ui_create_item_from_button(data, memarena, mt, drawstr_submenu, sub_but); - } - - if (region) { - BLI_remlink(®ion->uiblocks, sub_block); - } - UI_block_free(NULL, sub_block); - } - } - if (region) { - BLI_remlink(®ion->uiblocks, block); - } - UI_block_free(NULL, block); - - /* Add key-map items as a second pass, - * so all menus are accessed from the header & top-bar before key shortcuts are expanded. */ - if ((menu_stack == NULL) && (has_keymap_menu_items == false)) { - has_keymap_menu_items = true; - menu_types_add_from_keymap_items( - C, win, area, region, &menu_stack, menu_to_kmi, menu_tagged); - } - } - - LISTBASE_FOREACH (struct MenuSearch_Item *, item, &data->items) { - item->menu_parent = BLI_ghash_lookup(menu_parent_map, item->mt); - } - - GHASH_ITER (iter, menu_parent_map) { - struct MenuSearch_Parent *menu_parent = BLI_ghashIterator_getValue(&iter); - menu_parent->parent = BLI_ghash_lookup(menu_parent_map, menu_parent->parent_mt); - } - - /* NOTE: currently this builds the full path for each menu item, - * that could be moved into the parent menu. */ - - /* Set names as full paths. */ - LISTBASE_FOREACH (struct MenuSearch_Item *, item, &data->items) { - if (item->menu_parent != NULL) { - struct MenuSearch_Parent *menu_parent = item->menu_parent; - menu_parent->temp_child = NULL; - while (menu_parent && menu_parent->parent) { - menu_parent->parent->temp_child = menu_parent; - menu_parent = menu_parent->parent; - } - BLI_assert(BLI_dynstr_get_len(dyn_str) == 0); - while (menu_parent) { - BLI_dynstr_append(dyn_str, menu_parent->drawstr); - BLI_dynstr_append(dyn_str, " " MENU_SEP " "); - menu_parent = menu_parent->temp_child; - } - } - else { - BLI_assert(BLI_dynstr_get_len(dyn_str) == 0); - const char *drawstr = BLI_ghash_lookup(menu_display_name_map, item->mt); - if (drawstr == NULL) { - drawstr = CTX_IFACE_(item->mt->translation_context, item->mt->label); - } - BLI_dynstr_append(dyn_str, drawstr); - - wmKeyMapItem *kmi = BLI_ghash_lookup(menu_to_kmi, item->mt); - if (kmi != NULL) { - char kmi_str[128]; - WM_keymap_item_to_string(kmi, false, kmi_str, sizeof(kmi_str)); - BLI_dynstr_appendf(dyn_str, " (%s)", kmi_str); - } - - BLI_dynstr_append(dyn_str, " " MENU_SEP " "); - } - - /* Optional nested menu. */ - if (item->drawstr_submenu != NULL) { - BLI_dynstr_append(dyn_str, item->drawstr_submenu); - BLI_dynstr_append(dyn_str, " " MENU_SEP " "); - } - - BLI_dynstr_append(dyn_str, item->drawstr); - - item->drawwstr_full = strdup_memarena_from_dynstr(memarena, dyn_str); - BLI_dynstr_clear(dyn_str); - } - BLI_dynstr_free(dyn_str); - - /* Finally sort menu items. - * - * Note: we might want to keep the in-menu order, for now sort all. */ - BLI_listbase_sort(&data->items, menu_item_sort_by_drawstr_full); - - BLI_ghash_free(menu_parent_map, NULL, NULL); - BLI_ghash_free(menu_display_name_map, NULL, NULL); - - BLI_ghash_free(menu_to_kmi, NULL, NULL); - - BLI_gset_free(menu_tagged, NULL); - - data->memarena = memarena; - - return data; -} - -static void menu_items_from_ui_destroy(void *data_v) -{ - struct MenuSearch_Data *data = data_v; - LISTBASE_FOREACH (struct MenuSearch_Item *, item, &data->items) { - switch (item->type) { - case MENU_SEARCH_TYPE_OP: { - if (item->op.opptr != NULL) { - WM_operator_properties_free(item->op.opptr); - MEM_freeN(item->op.opptr); - } - } - case MENU_SEARCH_TYPE_RNA: { - break; - } - } - } - - BLI_memarena_free(data->memarena); - - MEM_freeN(data); -} - -static void menu_call_fn(bContext *C, void *UNUSED(arg1), void *arg2) -{ - struct MenuSearch_Item *item = arg2; - if (item == NULL) { - return; - } - if (item->state & UI_BUT_DISABLED) { - return; - } - - switch (item->type) { - case MENU_SEARCH_TYPE_OP: { - CTX_store_set(C, item->op.context); - WM_operator_name_call_ptr(C, item->op.type, item->op.opcontext, item->op.opptr); - CTX_store_set(C, NULL); - break; - } - case MENU_SEARCH_TYPE_RNA: { - PointerRNA *ptr = &item->rna.ptr; - PropertyRNA *prop = item->rna.prop; - int index = item->rna.index; - const int prop_type = RNA_property_type(prop); - bool changed = false; - - if (prop_type == PROP_BOOLEAN) { - const bool is_array = RNA_property_array_check(prop); - if (is_array) { - const bool value = RNA_property_boolean_get_index(ptr, prop, index); - RNA_property_boolean_set_index(ptr, prop, index, !value); - } - else { - const bool value = RNA_property_boolean_get(ptr, prop); - RNA_property_boolean_set(ptr, prop, !value); - } - changed = true; - } - else if (prop_type == PROP_ENUM) { - RNA_property_enum_set(ptr, prop, item->rna.enum_value); - changed = true; - } - - if (changed) { - RNA_property_update(C, ptr, prop); - } - break; - } - } -} - -static void menu_search_cb(const bContext *UNUSED(C), - void *arg, - const char *str, - uiSearchItems *items) -{ - struct MenuSearch_Data *data = arg; - const size_t str_len = strlen(str); - const int words_max = (str_len / 2) + 1; - int(*words)[2] = BLI_array_alloca(words, words_max); - - const int words_len = BLI_string_find_split_words(str, str_len, ' ', words, words_max); - - for (struct MenuSearch_Item *item = data->items.first; item; item = item->next) { - int index; - - /* match name against all search words */ - for (index = 0; index < words_len; index++) { - if (!has_word_prefix(item->drawwstr_full, str + words[index][0], words[index][1])) { - break; - } - } - - if (index == words_len) { - if (!UI_search_item_add(items, item->drawwstr_full, item, item->icon, item->state)) { - break; - } - } - } -} - -void UI_but_func_menu_search(uiBut *but) -{ - bContext *C = but->block->evil_C; - wmWindow *win = CTX_wm_window(C); - ScrArea *area = CTX_wm_area(C); - ARegion *region = CTX_wm_region(C); - struct MenuSearch_Data *data = menu_items_from_ui_create(C, win, area, region); - UI_but_func_search_set(but, - ui_searchbox_create_menu, - menu_search_cb, - data, - menu_items_from_ui_destroy, - menu_call_fn, - MENU_SEP, - NULL); -} - -void uiTemplateMenuSearch(uiLayout *layout) -{ - uiBlock *block; - uiBut *but; - static char search[256] = ""; - - block = uiLayoutGetBlock(layout); - UI_block_layout_set_current(block, layout); - - but = uiDefSearchBut( - block, search, 0, ICON_VIEWZOOM, sizeof(search), 0, 0, UI_UNIT_X * 6, UI_UNIT_Y, 0, 0, ""); - UI_but_func_menu_search(but); -} - -#undef MENU_SEP - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Operator Redo Properties Template - * \{ */ - -#ifdef USE_OP_RESET_BUT -static void ui_layout_operator_buts__reset_cb(bContext *UNUSED(C), - void *op_pt, - void *UNUSED(arg_dummy2)) -{ - WM_operator_properties_reset((wmOperator *)op_pt); -} -#endif - -struct uiTemplateOperatorPropertyPollParam { - const bContext *C; - wmOperator *op; - short flag; -}; - -static bool ui_layout_operator_buts_poll_property(struct PointerRNA *UNUSED(ptr), - struct PropertyRNA *prop, - void *user_data) -{ - struct uiTemplateOperatorPropertyPollParam *params = user_data; - if ((params->flag & UI_TEMPLATE_OP_PROPS_HIDE_ADVANCED) && - (RNA_property_tags(prop) & OP_PROP_TAG_ADVANCED)) { - return false; - } - return params->op->type->poll_property(params->C, params->op, prop); -} - -/** - * Draw Operator property buttons for redoing execution with different settings. - * This function does not initialize the layout, - * functions can be called on the layout before and after. - */ -eAutoPropButsReturn uiTemplateOperatorPropertyButs(const bContext *C, - uiLayout *layout, - wmOperator *op, - const eButLabelAlign label_align, - const short flag) -{ - uiBlock *block = uiLayoutGetBlock(layout); - eAutoPropButsReturn return_info = 0; - - if (!op->properties) { - IDPropertyTemplate val = {0}; - op->properties = IDP_New(IDP_GROUP, &val, "wmOperatorProperties"); - } - - /* poll() on this operator may still fail, - * at the moment there is no nice feedback when this happens just fails silently. */ - if (!WM_operator_repeat_check(C, op)) { - UI_block_lock_set(block, true, "Operator can't' redo"); - return return_info; - } - else { - /* useful for macros where only one of the steps can't be re-done */ - UI_block_lock_clear(block); - } - - if (flag & UI_TEMPLATE_OP_PROPS_SHOW_TITLE) { - uiItemL(layout, WM_operatortype_name(op->type, op->ptr), ICON_NONE); - } - - /* menu */ - if (op->type->flag & OPTYPE_PRESET) { - /* XXX, no simple way to get WM_MT_operator_presets.bl_label - * from python! Label remains the same always! */ - PointerRNA op_ptr; - uiLayout *row; - - block->ui_operator = op; - - row = uiLayoutRow(layout, true); - uiItemM(row, "WM_MT_operator_presets", NULL, ICON_NONE); - - wmOperatorType *ot = WM_operatortype_find("WM_OT_operator_preset_add", false); - uiItemFullO_ptr(row, ot, "", ICON_ADD, NULL, WM_OP_INVOKE_DEFAULT, 0, &op_ptr); - RNA_string_set(&op_ptr, "operator", op->type->idname); - - uiItemFullO_ptr(row, ot, "", ICON_REMOVE, NULL, WM_OP_INVOKE_DEFAULT, 0, &op_ptr); - RNA_string_set(&op_ptr, "operator", op->type->idname); - RNA_boolean_set(&op_ptr, "remove_active", true); - } - - if (op->type->ui) { - op->layout = layout; - op->type->ui((bContext *)C, op); - op->layout = NULL; - - /* UI_LAYOUT_OP_SHOW_EMPTY ignored. return_info is ignored too. We could - * allow ot.ui callback to return this, but not needed right now. */ - } - else { - wmWindowManager *wm = CTX_wm_manager(C); - PointerRNA ptr; - struct uiTemplateOperatorPropertyPollParam user_data = { - .C = C, - .op = op, - .flag = flag, - }; - - RNA_pointer_create(&wm->id, op->type->srna, op->properties, &ptr); - - uiLayoutSetPropSep(layout, true); - uiLayoutSetPropDecorate(layout, false); - - /* main draw call */ - return_info = uiDefAutoButsRNA( - layout, - &ptr, - op->type->poll_property ? ui_layout_operator_buts_poll_property : NULL, - op->type->poll_property ? &user_data : NULL, - op->type->prop, - label_align, - (flag & UI_TEMPLATE_OP_PROPS_COMPACT)); - - if ((return_info & UI_PROP_BUTS_NONE_ADDED) && (flag & UI_TEMPLATE_OP_PROPS_SHOW_EMPTY)) { - uiItemL(layout, IFACE_("No Properties"), ICON_NONE); - } - } - -#ifdef USE_OP_RESET_BUT - /* its possible that reset can do nothing if all have PROP_SKIP_SAVE enabled - * but this is not so important if this button is drawn in those cases - * (which isn't all that likely anyway) - campbell */ - if (op->properties->len) { - uiBut *but; - uiLayout *col; /* needed to avoid alignment errors with previous buttons */ - - col = uiLayoutColumn(layout, false); - block = uiLayoutGetBlock(col); - but = uiDefIconTextBut(block, - UI_BTYPE_BUT, - 0, - ICON_FILE_REFRESH, - IFACE_("Reset"), - 0, - 0, - UI_UNIT_X, - UI_UNIT_Y, - NULL, - 0.0, - 0.0, - 0.0, - 0.0, - TIP_("Reset operator defaults")); - UI_but_func_set(but, ui_layout_operator_buts__reset_cb, op, NULL); - } -#endif - - /* set various special settings for buttons */ - - /* Only do this if we're not refreshing an existing UI. */ - if (block->oldblock == NULL) { - const bool is_popup = (block->flag & UI_BLOCK_KEEP_OPEN) != 0; - uiBut *but; - - for (but = block->buttons.first; but; but = but->next) { - /* no undo for buttons for operator redo panels */ - UI_but_flag_disable(but, UI_BUT_UNDO); - - /* only for popups, see [#36109] */ - - /* if button is operator's default property, and a text-field, enable focus for it - * - this is used for allowing operators with popups to rename stuff with fewer clicks - */ - if (is_popup) { - if ((but->rnaprop == op->type->prop) && (but->type == UI_BTYPE_TEXT)) { - UI_but_focus_on_enter_event(CTX_wm_window(C), but); - } - } - } - } - - return return_info; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ /** \name Running Jobs Template * \{ */ diff --git a/source/blender/editors/interface/interface_undo.c b/source/blender/editors/interface/interface_undo.c new file mode 100644 index 00000000000..016bc4159db --- /dev/null +++ b/source/blender/editors/interface/interface_undo.c @@ -0,0 +1,139 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright (C) 2020 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup edinterface + * + * Undo stack to use for UI widgets that manage their own editing state. + */ + +#include <string.h> + +#include "BLI_listbase.h" + +#include "DNA_listBase.h" + +#include "MEM_guardedalloc.h" + +#include "interface_intern.h" + +/* -------------------------------------------------------------------- */ +/** \name Text Field Undo Stack + * \{ */ + +typedef struct uiUndoStack_Text_State { + struct uiUndoStack_Text_State *next, *prev; + int cursor_index; + char text[0]; +} uiUndoStack_Text_State; + +typedef struct uiUndoStack_Text { + ListBase states; + uiUndoStack_Text_State *current; +} uiUndoStack_Text; + +static const char *ui_textedit_undo_impl(uiUndoStack_Text *stack, int *r_cursor_index) +{ + /* Don't undo if no data has been pushed yet. */ + if (stack->current == NULL) { + return NULL; + } + + /* Travel backwards in the stack and copy information to the caller. */ + if (stack->current->prev != NULL) { + stack->current = stack->current->prev; + + *r_cursor_index = stack->current->cursor_index; + return stack->current->text; + } + return NULL; +} + +static const char *ui_textedit_redo_impl(uiUndoStack_Text *stack, int *r_cursor_index) +{ + /* Don't redo if no data has been pushed yet. */ + if (stack->current == NULL) { + return NULL; + } + + /* Only redo if new data has not been entered since the last undo. */ + if (stack->current->next) { + stack->current = stack->current->next; + + *r_cursor_index = stack->current->cursor_index; + return stack->current->text; + } + return NULL; +} + +const char *ui_textedit_undo(uiUndoStack_Text *stack, int direction, int *r_cursor_index) +{ + BLI_assert(ELEM(direction, -1, 1)); + if (direction < 0) { + return ui_textedit_undo_impl(stack, r_cursor_index); + } + else { + return ui_textedit_redo_impl(stack, r_cursor_index); + } +} + +/** + * Push the information in the arguments to a new state in the undo stack. + * + * \note Currently the total length of the undo stack is not limited. + */ +void ui_textedit_undo_push(uiUndoStack_Text *stack, const char *text, int cursor_index) +{ + /* Clear all redo actions from the current state. */ + if (stack->current != NULL) { + while (stack->current->next) { + uiUndoStack_Text_State *state = stack->current->next; + BLI_remlink(&stack->states, state); + MEM_freeN(state); + } + } + + /* Create the new state */ + const int text_size = strlen(text) + 1; + stack->current = MEM_mallocN(sizeof(uiUndoStack_Text_State) + text_size, __func__); + stack->current->cursor_index = cursor_index; + memcpy(stack->current->text, text, text_size); + BLI_addtail(&stack->states, stack->current); +} +/** + * Start the undo stack. + * + * \note The current state should be pushed immediately after calling this. + */ +uiUndoStack_Text *ui_textedit_undo_stack_create(void) +{ + uiUndoStack_Text *stack = MEM_mallocN(sizeof(uiUndoStack_Text), __func__); + stack->current = NULL; + BLI_listbase_clear(&stack->states); + + return stack; +} + +void ui_textedit_undo_stack_destroy(uiUndoStack_Text *stack) +{ + BLI_freelistN(&stack->states); + MEM_freeN(stack); +} + +/** \} */ diff --git a/source/blender/editors/interface/interface_utils.c b/source/blender/editors/interface/interface_utils.c index 781c8f73b0a..4013e962ce5 100644 --- a/source/blender/editors/interface/interface_utils.c +++ b/source/blender/editors/interface/interface_utils.c @@ -22,6 +22,7 @@ */ #include <assert.h> +#include <ctype.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -51,6 +52,22 @@ #include "interface_intern.h" +bool ui_str_has_word_prefix(const char *haystack, const char *needle, size_t needle_len) +{ + const char *match = BLI_strncasestr(haystack, needle, needle_len); + if (match) { + if ((match == haystack) || (*(match - 1) == ' ') || ispunct(*(match - 1))) { + return true; + } + else { + return ui_str_has_word_prefix(match + 1, needle, needle_len); + } + } + else { + return false; + } +} + /*************************** RNA Utilities ******************************/ uiBut *uiDefAutoButR(uiBlock *block, @@ -294,7 +311,7 @@ eAutoPropButsReturn uiDefAutoButsRNA(uiLayout *layout, const bool compact) { eAutoPropButsReturn return_info = UI_PROP_BUTS_NONE_ADDED; - uiLayout *split, *col; + uiLayout *col; const char *name; RNA_STRUCT_BEGIN (ptr, prop) { @@ -325,19 +342,11 @@ eAutoPropButsReturn uiDefAutoButsRNA(uiLayout *layout, } else { BLI_assert(label_align == UI_BUT_LABEL_ALIGN_SPLIT_COLUMN); - split = uiLayoutSplit(layout, 0.5f, false); - - col = uiLayoutColumn(split, false); - uiItemL(col, (is_boolean) ? "" : name, ICON_NONE); - col = uiLayoutColumn(split, false); + col = uiLayoutColumn(layout, true); + /* Let uiItemFullR() create the split layout. */ + uiLayoutSetPropSep(col, true); } - /* May need to add more cases here. - * don't override enum flag names */ - - /* name is shown above, empty name for button below */ - name = (flag & PROP_ENUM_FLAG || is_boolean) ? NULL : ""; - break; } case UI_BUT_LABEL_ALIGN_NONE: @@ -390,10 +399,10 @@ static int sort_search_items_list(const void *a, const void *b) } } -void ui_rna_collection_search_cb(const struct bContext *C, - void *arg, - const char *str, - uiSearchItems *items) +void ui_rna_collection_search_update_fn(const struct bContext *C, + void *arg, + const char *str, + uiSearchItems *items) { uiRNACollectionSearch *data = arg; int i = 0, iconid = 0, flag = RNA_property_flag(data->target_prop); diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index ed0f50f4113..4706be205e1 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -41,6 +41,8 @@ #include "BLF_api.h" +#include "ED_node.h" + #include "UI_interface.h" #include "UI_interface_icons.h" @@ -2092,15 +2094,18 @@ static void widget_draw_text_ime_underline(const uiFontStyle *fstyle, #endif /* WITH_INPUT_IME */ static bool widget_draw_text_underline_calc_center_x(const char *UNUSED(str), - const size_t str_ofs, - const rcti *glyph_bounds, - const int glyph_advance_x, + const size_t str_step_ofs, + const rcti *glyph_step_bounds, + const int UNUSED(glyph_advance_x), + const rctf *glyph_bounds, + const int glyph_bearing[2], void *user_data) { /* The index of the character to get, set to the x-position. */ int *ul_data = user_data; - if (ul_data[0] == (int)str_ofs) { - ul_data[1] = glyph_bounds->xmin + (glyph_advance_x / 2); + if (ul_data[0] == (int)str_step_ofs) { + ul_data[1] = glyph_step_bounds->xmin + glyph_bearing[0] + + (BLI_rctf_size_x(glyph_bounds) / 2.0f); /* Early exit. */ return false; } @@ -2418,6 +2423,30 @@ static void widget_draw_extra_icons(const uiWidgetColors *wcol, } } +static void widget_draw_node_link_socket(const uiWidgetColors *wcol, + const rcti *rect, + uiBut *but, + float alpha) +{ + /* Node socket pointer can be passed as custom_data, see UI_but_node_link_set(). */ + if (but->custom_data) { + const float scale = 0.9f / but->block->aspect; + + float col[4]; + rgba_uchar_to_float(col, but->col); + col[3] *= alpha; + + GPU_blend(true); + UI_widgetbase_draw_cache_flush(); + GPU_blend(false); + + ED_node_socket_draw(but->custom_data, rect, col, scale); + } + else { + widget_draw_icon(but, ICON_LAYER_USED, alpha, rect, wcol->text); + } +} + /* draws text and icons for buttons */ static void widget_draw_text_icon(const uiFontStyle *fstyle, const uiWidgetColors *wcol, @@ -2427,15 +2456,27 @@ static void widget_draw_text_icon(const uiFontStyle *fstyle, const bool show_menu_icon = ui_but_draw_menu_icon(but); float alpha = (float)wcol->text[3] / 255.0f; char password_str[UI_MAX_DRAW_STR]; + bool no_text_padding = but->drawflag & UI_BUT_NO_TEXT_PADDING; ui_but_text_password_hide(password_str, but, false); /* check for button text label */ if (ELEM(but->type, UI_BTYPE_MENU, UI_BTYPE_POPOVER) && (but->flag & UI_BUT_NODE_LINK)) { rcti temp = *rect; - temp.xmin = rect->xmax - BLI_rcti_size_y(rect) - 1; - widget_draw_icon(but, ICON_LAYER_USED, alpha, &temp, wcol->text); - rect->xmax = temp.xmin; + const int size = BLI_rcti_size_y(rect) + 1; /* Not the icon size! */ + + if (but->drawflag & UI_BUT_ICON_LEFT) { + temp.xmax = rect->xmin + size; + rect->xmin = temp.xmax; + /* Further padding looks off. */ + no_text_padding = true; + } + else { + temp.xmin = rect->xmax - size; + rect->xmax = temp.xmin; + } + + widget_draw_node_link_socket(wcol, &temp, but, alpha); } /* If there's an icon too (made with uiDefIconTextBut) then draw the icon @@ -2520,28 +2561,30 @@ static void widget_draw_text_icon(const uiFontStyle *fstyle, rect->xmin += icon_size + icon_padding; } - int text_padding = (UI_TEXT_MARGIN_X * U.widget_unit) / but->block->aspect; - if (but->editstr) { - rect->xmin += text_padding; - } - else if (but->flag & UI_BUT_DRAG_MULTI) { - bool text_is_edited = ui_but_drag_multi_edit_get(but) != NULL; - if (text_is_edited) { + if (!no_text_padding) { + int text_padding = (UI_TEXT_MARGIN_X * U.widget_unit) / but->block->aspect; + if (but->editstr) { rect->xmin += text_padding; } - } - else if (but->drawflag & UI_BUT_TEXT_LEFT) { - - /* Reduce the left padding for labels without an icon. */ - if ((but->type == UI_BTYPE_LABEL) && !(but->flag & UI_HAS_ICON) && - !ui_block_is_menu(but->block)) { - text_padding /= 2; + else if (but->flag & UI_BUT_DRAG_MULTI) { + bool text_is_edited = ui_but_drag_multi_edit_get(but) != NULL; + if (text_is_edited) { + rect->xmin += text_padding; + } } + else if (but->drawflag & UI_BUT_TEXT_LEFT) { - rect->xmin += text_padding; - } - else if (but->drawflag & UI_BUT_TEXT_RIGHT) { - rect->xmax -= text_padding; + /* Reduce the left padding for labels without an icon. */ + if ((but->type == UI_BTYPE_LABEL) && !(but->flag & UI_HAS_ICON) && + !ui_block_is_menu(but->block)) { + text_padding /= 2; + } + + rect->xmin += text_padding; + } + else if (but->drawflag & UI_BUT_TEXT_RIGHT) { + rect->xmax -= text_padding; + } } /* Menu contains sub-menu items with triangle icon on their right. Shortcut @@ -4145,10 +4188,10 @@ static void widget_optionbut(uiWidgetColors *wcol, /* smaller */ delta = 1 + BLI_rcti_size_y(&recttemp) / 8; - recttemp.xmin += delta; - recttemp.ymin += delta; - recttemp.xmax -= delta; - recttemp.ymax -= delta; + BLI_rcti_resize( + &recttemp, BLI_rcti_size_x(&recttemp) - delta * 2, BLI_rcti_size_y(&recttemp) - delta * 2); + /* Keep one edge in place. */ + BLI_rcti_translate(&recttemp, text_before_widget ? delta : -delta, 0); rad = wcol->roundness * BLI_rcti_size_y(&recttemp); round_box_edges(&wtb, UI_CNR_ALL, &recttemp, rad); @@ -4160,13 +4203,13 @@ static void widget_optionbut(uiWidgetColors *wcol, widgetbase_draw(&wtb, wcol); - /* text space */ - const float offset = BLI_rcti_size_y(rect) * 0.7 + delta; + /* Text space - factor is really just eyeballed. */ + const float offset = delta * 0.9; if (text_before_widget) { - rect->xmax -= offset; + rect->xmax = recttemp.xmin - offset; } else { - rect->xmin += offset; + rect->xmin = recttemp.xmax + offset; } } @@ -4723,9 +4766,14 @@ void ui_draw_but(const bContext *C, struct ARegion *region, uiStyle *style, uiBu case UI_BTYPE_CHECKBOX_N: if (!(but->flag & UI_HAS_ICON)) { wt = widget_type(UI_WTYPE_CHECKBOX); + if ((but->drawflag & (UI_BUT_TEXT_LEFT | UI_BUT_TEXT_RIGHT)) == 0) { but->drawflag |= UI_BUT_TEXT_LEFT; } + /* widget_optionbut() carefully sets the text rectangle for fine tuned paddings. If the + * text drawing were to add its own padding, DPI and zoom factor would be applied twice + * in the final padding, so it's difficult to control it. */ + but->drawflag |= UI_BUT_NO_TEXT_PADDING; } else { wt = widget_type(UI_WTYPE_TOGGLE); @@ -5279,15 +5327,23 @@ void ui_draw_tooltip_background(const uiStyle *UNUSED(style), uiBlock *UNUSED(bl wt->draw(&wt->wcol, rect, 0, 0); } -/* helper call to draw a menu item without button */ -/* state: UI_ACTIVE or 0 */ +/** + * Helper call to draw a menu item without a button. + * + * \param state: The state of the button, + * typically #UI_ACTIVE, #UI_BUT_DISABLED, #UI_BUT_INACTIVE. + * \param use_sep: When true, characters after the last #UI_SEP_CHAR are right aligned, + * use for displaying key shortcuts. + * \param r_xmax: The right hand position of the text, this takes into the icon, + * padding and text clipping when there is not enough room to display the full text. + */ void ui_draw_menu_item(const uiFontStyle *fstyle, rcti *rect, const char *name, int iconid, int state, bool use_sep, - int *r_name_width) + int *r_xmax) { uiWidgetType *wt = widget_type(UI_WTYPE_MENU_ITEM); rcti _rect = *rect; @@ -5350,23 +5406,8 @@ void ui_draw_menu_item(const uiFontStyle *fstyle, &xofs, &yofs, &info); - if (r_name_width != NULL) { - *r_name_width = xofs + info.width; - } - } - - /* part text right aligned */ - if (use_sep) { - if (cpoin) { - rect->xmax = _rect.xmax - 5; - UI_fontstyle_draw(fstyle, - rect, - cpoin + 1, - wt->wcol.text, - &(struct uiFontStyleDraw_Params){ - .align = UI_STYLE_TEXT_RIGHT, - }); - *cpoin = UI_SEP_CHAR; + if (r_xmax != NULL) { + *r_xmax = xofs + info.width; } } @@ -5386,6 +5427,24 @@ void ui_draw_menu_item(const uiFontStyle *fstyle, UI_icon_draw_ex(xs, ys, iconid, aspect, 1.0f, 0.0f, wt->wcol.text, false); GPU_blend(false); } + + /* part text right aligned */ + if (use_sep) { + if (cpoin) { + /* Set inactive state for grayed out text. */ + wt->state(wt, state | UI_BUT_INACTIVE, 0); + + rect->xmax = _rect.xmax - 5; + UI_fontstyle_draw(fstyle, + rect, + cpoin + 1, + wt->wcol.text, + &(struct uiFontStyleDraw_Params){ + .align = UI_STYLE_TEXT_RIGHT, + }); + *cpoin = UI_SEP_CHAR; + } + } } void ui_draw_preview_item( diff --git a/source/blender/editors/interface/view2d.c b/source/blender/editors/interface/view2d.c index c07166b9ad2..f8419ba3eba 100644 --- a/source/blender/editors/interface/view2d.c +++ b/source/blender/editors/interface/view2d.c @@ -60,7 +60,7 @@ #include "interface_intern.h" -static void ui_view2d_curRect_validate_resize(View2D *v2d, bool resize, bool mask_scrollers); +static void ui_view2d_curRect_validate_resize(View2D *v2d, bool resize); /* -------------------------------------------------------------------- */ /** \name Internal Utilities @@ -134,7 +134,7 @@ void UI_view2d_mask_from_win(const View2D *v2d, rcti *r_mask) * * \param mask_scroll: Optionally clamp scrollbars by this region. */ -static void view2d_masks(View2D *v2d, bool check_scrollers, const rcti *mask_scroll) +static void view2d_masks(View2D *v2d, const rcti *mask_scroll) { int scroll; @@ -144,26 +144,24 @@ static void view2d_masks(View2D *v2d, bool check_scrollers, const rcti *mask_scr mask_scroll = &v2d->mask; } - if (check_scrollers) { - /* check size if hiding flag is set: */ - if (v2d->scroll & V2D_SCROLL_HORIZONTAL_HIDE) { - if (!(v2d->scroll & V2D_SCROLL_HORIZONTAL_HANDLES)) { - if (BLI_rctf_size_x(&v2d->tot) > BLI_rctf_size_x(&v2d->cur)) { - v2d->scroll &= ~V2D_SCROLL_HORIZONTAL_FULLR; - } - else { - v2d->scroll |= V2D_SCROLL_HORIZONTAL_FULLR; - } + /* check size if hiding flag is set: */ + if (v2d->scroll & V2D_SCROLL_HORIZONTAL_HIDE) { + if (!(v2d->scroll & V2D_SCROLL_HORIZONTAL_HANDLES)) { + if (BLI_rctf_size_x(&v2d->tot) > BLI_rctf_size_x(&v2d->cur)) { + v2d->scroll &= ~V2D_SCROLL_HORIZONTAL_FULLR; + } + else { + v2d->scroll |= V2D_SCROLL_HORIZONTAL_FULLR; } } - if (v2d->scroll & V2D_SCROLL_VERTICAL_HIDE) { - if (!(v2d->scroll & V2D_SCROLL_VERTICAL_HANDLES)) { - if (BLI_rctf_size_y(&v2d->tot) + 0.01f > BLI_rctf_size_y(&v2d->cur)) { - v2d->scroll &= ~V2D_SCROLL_VERTICAL_FULLR; - } - else { - v2d->scroll |= V2D_SCROLL_VERTICAL_FULLR; - } + } + if (v2d->scroll & V2D_SCROLL_VERTICAL_HIDE) { + if (!(v2d->scroll & V2D_SCROLL_VERTICAL_HANDLES)) { + if (BLI_rctf_size_y(&v2d->tot) + 0.01f > BLI_rctf_size_y(&v2d->cur)) { + v2d->scroll &= ~V2D_SCROLL_VERTICAL_FULLR; + } + else { + v2d->scroll |= V2D_SCROLL_VERTICAL_FULLR; } } } @@ -385,8 +383,7 @@ void UI_view2d_region_reinit(View2D *v2d, short type, int winx, int winy) v2d->winx = winx; v2d->winy = winy; - /* set masks (always do), but leave scroller scheck to totrect_set */ - view2d_masks(v2d, 0, NULL); + view2d_masks(v2d, NULL); if (do_init) { /* Visible by default. */ @@ -394,13 +391,12 @@ void UI_view2d_region_reinit(View2D *v2d, short type, int winx, int winy) } /* set 'tot' rect before setting cur? */ - /* XXX confusing stuff here still - - * I made this function not check scroller hide - that happens in totrect_set */ + /* XXX confusing stuff here still */ if (tot_changed) { UI_view2d_totRect_set_resize(v2d, winx, winy, !do_init); } else { - ui_view2d_curRect_validate_resize(v2d, !do_init, 0); + ui_view2d_curRect_validate_resize(v2d, !do_init); } } @@ -409,7 +405,7 @@ void UI_view2d_region_reinit(View2D *v2d, short type, int winx, int winy) * 'cur' is not allowed to be: larger than max, smaller than min, or outside of 'tot' */ // XXX pre2.5 -> this used to be called test_view2d() -static void ui_view2d_curRect_validate_resize(View2D *v2d, bool resize, bool mask_scrollers) +static void ui_view2d_curRect_validate_resize(View2D *v2d, bool resize) { float totwidth, totheight, curwidth, curheight, width, height; float winx, winy; @@ -851,12 +847,12 @@ static void ui_view2d_curRect_validate_resize(View2D *v2d, bool resize, bool mas } /* set masks */ - view2d_masks(v2d, mask_scrollers, NULL); + view2d_masks(v2d, NULL); } void UI_view2d_curRect_validate(View2D *v2d) { - ui_view2d_curRect_validate_resize(v2d, 0, 1); + ui_view2d_curRect_validate_resize(v2d, false); } /* ------------------ */ @@ -982,22 +978,10 @@ void UI_view2d_curRect_reset(View2D *v2d) /* Change the size of the maximum viewable area (i.e. 'tot' rect) */ void UI_view2d_totRect_set_resize(View2D *v2d, int width, int height, bool resize) { - // int scroll = view2d_scroll_mapped(v2d->scroll); - /* don't do anything if either value is 0 */ width = abs(width); height = abs(height); - /* hrumf! */ - /* XXX: there are work arounds for this in the panel and file browse code. */ - /* round to int, because this is called with width + V2D_SCROLL_WIDTH */ - // if (scroll & V2D_SCROLL_HORIZONTAL) { - // width -= (int)V2D_SCROLL_WIDTH; - // } - // if (scroll & V2D_SCROLL_VERTICAL) { - // height -= (int)V2D_SCROLL_HEIGHT; - // } - if (ELEM(0, width, height)) { if (G.debug & G_DEBUG) { printf("Error: View2D totRect set exiting: v2d=%p width=%d height=%d\n", @@ -1047,20 +1031,12 @@ void UI_view2d_totRect_set_resize(View2D *v2d, int width, int height, bool resiz } /* make sure that 'cur' rect is in a valid state as a result of these changes */ - ui_view2d_curRect_validate_resize(v2d, resize, 1); + ui_view2d_curRect_validate_resize(v2d, resize); } void UI_view2d_totRect_set(View2D *v2d, int width, int height) { - int scroll = view2d_scroll_mapped(v2d->scroll); - - UI_view2d_totRect_set_resize(v2d, width, height, 0); - - /* solve bad recursion... if scroller state changed, - * mask is different, so you get different rects */ - if (scroll != view2d_scroll_mapped(v2d->scroll)) { - UI_view2d_totRect_set_resize(v2d, width, height, 0); - } + UI_view2d_totRect_set_resize(v2d, width, height, false); } bool UI_view2d_tab_set(View2D *v2d, int tab) @@ -1258,7 +1234,7 @@ void UI_view2d_view_restore(const bContext *C) * \{ */ /* Draw a constant grid in given 2d-region */ -void UI_view2d_constant_grid_draw(View2D *v2d, float step) +void UI_view2d_constant_grid_draw(const View2D *v2d, float step) { float start_x, start_y; int count_x, count_y; @@ -1330,7 +1306,8 @@ void UI_view2d_constant_grid_draw(View2D *v2d, float step) } /* Draw a multi-level grid in given 2d-region */ -void UI_view2d_multi_grid_draw(View2D *v2d, int colorid, float step, int level_size, int totlevels) +void UI_view2d_multi_grid_draw( + const View2D *v2d, int colorid, float step, int level_size, int totlevels) { /* Exit if there is nothing to draw */ if (totlevels == 0) { @@ -1448,7 +1425,7 @@ View2DScrollers *UI_view2d_scrollers_calc(View2D *v2d, const rcti *mask_custom) scrollers = MEM_callocN(sizeof(View2DScrollers), "View2DScrollers"); /* Always update before drawing (for dynamically sized scrollers). */ - view2d_masks(v2d, false, mask_custom); + view2d_masks(v2d, mask_custom); vert = v2d->vert; hor = v2d->hor; @@ -1801,7 +1778,8 @@ bool UI_view2d_view_to_region_clip( * \param x, y: Coordinates to convert. * \param r_region_x, r_region_y: Resultant coordinates. */ -void UI_view2d_view_to_region(View2D *v2d, float x, float y, int *r_region_x, int *r_region_y) +void UI_view2d_view_to_region( + const View2D *v2d, float x, float y, int *r_region_x, int *r_region_y) { /* step 1: express given coordinates as proportional values */ x = (x - v2d->cur.xmin) / BLI_rctf_size_x(&v2d->cur); @@ -1817,7 +1795,7 @@ void UI_view2d_view_to_region(View2D *v2d, float x, float y, int *r_region_x, in } void UI_view2d_view_to_region_fl( - View2D *v2d, float x, float y, float *r_region_x, float *r_region_y) + const View2D *v2d, float x, float y, float *r_region_x, float *r_region_y) { /* express given coordinates as proportional values */ x = (x - v2d->cur.xmin) / BLI_rctf_size_x(&v2d->cur); @@ -1828,7 +1806,7 @@ void UI_view2d_view_to_region_fl( *r_region_y = v2d->mask.ymin + (y * BLI_rcti_size_y(&v2d->mask)); } -void UI_view2d_view_to_region_rcti(View2D *v2d, const rctf *rect_src, rcti *rect_dst) +void UI_view2d_view_to_region_rcti(const View2D *v2d, const rctf *rect_src, rcti *rect_dst) { const float cur_size[2] = {BLI_rctf_size_x(&v2d->cur), BLI_rctf_size_y(&v2d->cur)}; const float mask_size[2] = {BLI_rcti_size_x(&v2d->mask), BLI_rcti_size_y(&v2d->mask)}; @@ -1849,7 +1827,7 @@ void UI_view2d_view_to_region_rcti(View2D *v2d, const rctf *rect_src, rcti *rect clamp_rctf_to_rcti(rect_dst, &rect_tmp); } -void UI_view2d_view_to_region_m4(View2D *v2d, float matrix[4][4]) +void UI_view2d_view_to_region_m4(const View2D *v2d, float matrix[4][4]) { rctf mask; unit_m4(matrix); @@ -1857,7 +1835,7 @@ void UI_view2d_view_to_region_m4(View2D *v2d, float matrix[4][4]) BLI_rctf_transform_calc_m4_pivot_min(&v2d->cur, &mask, matrix); } -bool UI_view2d_view_to_region_rcti_clip(View2D *v2d, const rctf *rect_src, rcti *rect_dst) +bool UI_view2d_view_to_region_rcti_clip(const View2D *v2d, const rctf *rect_src, rcti *rect_dst) { const float cur_size[2] = {BLI_rctf_size_x(&v2d->cur), BLI_rctf_size_y(&v2d->cur)}; const float mask_size[2] = {BLI_rcti_size_x(&v2d->mask), BLI_rcti_size_y(&v2d->mask)}; @@ -1983,7 +1961,7 @@ float UI_view2d_scale_get_y(const View2D *v2d) /** * Same as ``UI_view2d_scale_get() - 1.0f / x, y`` */ -void UI_view2d_scale_get_inverse(View2D *v2d, float *r_x, float *r_y) +void UI_view2d_scale_get_inverse(const View2D *v2d, float *r_x, float *r_y) { if (r_x) { *r_x = BLI_rctf_size_x(&v2d->cur) / BLI_rcti_size_x(&v2d->mask); @@ -1997,7 +1975,7 @@ void UI_view2d_scale_get_inverse(View2D *v2d, float *r_x, float *r_y) * Simple functions for consistent center offset access. * Used by node editor to shift view center for each individual node tree. */ -void UI_view2d_center_get(struct View2D *v2d, float *r_x, float *r_y) +void UI_view2d_center_get(const struct View2D *v2d, float *r_x, float *r_y) { /* get center */ if (r_x) { diff --git a/source/blender/editors/io/io_alembic.c b/source/blender/editors/io/io_alembic.c index af17303466b..551f7989d53 100644 --- a/source/blender/editors/io/io_alembic.c +++ b/source/blender/editors/io/io_alembic.c @@ -10,7 +10,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, + * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * The Original Code is Copyright (C) 2016 Blender Foundation. diff --git a/source/blender/editors/io/io_alembic.h b/source/blender/editors/io/io_alembic.h index 881712fe630..ecd8c1818f8 100644 --- a/source/blender/editors/io/io_alembic.h +++ b/source/blender/editors/io/io_alembic.h @@ -10,7 +10,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, + * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * The Original Code is Copyright (C) 2016 Blender Foundation. diff --git a/source/blender/editors/io/io_cache.c b/source/blender/editors/io/io_cache.c index 6c5abf60272..045a293f71b 100644 --- a/source/blender/editors/io/io_cache.c +++ b/source/blender/editors/io/io_cache.c @@ -10,7 +10,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, + * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * The Original Code is Copyright (C) 2016 Blender Foundation. diff --git a/source/blender/editors/io/io_cache.h b/source/blender/editors/io/io_cache.h index 25548dcdbce..c6fc50a236e 100644 --- a/source/blender/editors/io/io_cache.h +++ b/source/blender/editors/io/io_cache.h @@ -10,7 +10,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, + * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * The Original Code is Copyright (C) 2016 Blender Foundation. diff --git a/source/blender/editors/io/io_usd.c b/source/blender/editors/io/io_usd.c index bb527ee6a3f..262b15c63e5 100644 --- a/source/blender/editors/io/io_usd.c +++ b/source/blender/editors/io/io_usd.c @@ -10,7 +10,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, + * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * The Original Code is Copyright (C) 2019 Blender Foundation. diff --git a/source/blender/editors/io/io_usd.h b/source/blender/editors/io/io_usd.h index 4738e1c348d..c794dc744df 100644 --- a/source/blender/editors/io/io_usd.h +++ b/source/blender/editors/io/io_usd.h @@ -10,7 +10,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, + * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * The Original Code is Copyright (C) 2019 Blender Foundation. diff --git a/source/blender/editors/mask/mask_select.c b/source/blender/editors/mask/mask_select.c index a6dece91eb0..c8cddced99c 100644 --- a/source/blender/editors/mask/mask_select.c +++ b/source/blender/editors/mask/mask_select.c @@ -521,8 +521,8 @@ void MASK_OT_select_box(wmOperatorType *ot) * \{ */ static bool do_lasso_select_mask(bContext *C, - const int mcords[][2], - short moves, + const int mcoords[][2], + const int mcoords_len, const eSelectOp sel_op) { ScrArea *area = CTX_wm_area(C); @@ -540,7 +540,7 @@ static bool do_lasso_select_mask(bContext *C, } /* get rectangle from operator */ - BLI_lasso_boundbox(&rect, mcords, moves); + BLI_lasso_boundbox(&rect, mcoords, mcoords_len); /* do actual selection */ LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) { @@ -573,7 +573,7 @@ static bool do_lasso_select_mask(bContext *C, &screen_co[1]); if (BLI_rcti_isect_pt(&rect, screen_co[0], screen_co[1]) && - BLI_lasso_is_point_inside(mcords, moves, screen_co[0], screen_co[1], INT_MAX)) { + BLI_lasso_is_point_inside(mcoords, mcoords_len, screen_co[0], screen_co[1], INT_MAX)) { BKE_mask_point_select_set(point, select); BKE_mask_point_select_set_handle(point, MASK_WHICH_HANDLE_BOTH, select); changed = true; @@ -594,14 +594,14 @@ static bool do_lasso_select_mask(bContext *C, static int clip_lasso_select_exec(bContext *C, wmOperator *op) { - int mcords_tot; - const int(*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot); + int mcoords_len; + const int(*mcoords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcoords_len); - if (mcords) { + if (mcoords) { const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode"); - do_lasso_select_mask(C, mcords, mcords_tot, sel_op); + do_lasso_select_mask(C, mcoords, mcoords_len, sel_op); - MEM_freeN((void *)mcords); + MEM_freeN((void *)mcoords); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/mesh/editmesh_extrude.c b/source/blender/editors/mesh/editmesh_extrude.c index 23f622ac359..bf6c5a2f829 100644 --- a/source/blender/editors/mesh/editmesh_extrude.c +++ b/source/blender/editors/mesh/editmesh_extrude.c @@ -226,6 +226,7 @@ static bool edbm_extrude_ex(Object *obedit, char htype, const char hflag, const bool use_normal_flip, + const bool use_dissolve_ortho_edges, const bool use_mirror, const bool use_select_history) { @@ -241,6 +242,7 @@ static bool edbm_extrude_ex(Object *obedit, BMO_op_init(bm, &extop, BMO_FLAG_DEFAULTS, "extrude_face_region"); BMO_slot_bool_set(extop.slots_in, "use_normal_flip", use_normal_flip); + BMO_slot_bool_set(extop.slots_in, "use_dissolve_ortho_edges", use_dissolve_ortho_edges); BMO_slot_bool_set(extop.slots_in, "use_select_history", use_select_history); BMO_slot_buffer_from_enabled_hflag(bm, &extop, extop.slots_in, "geom", htype, hflag); @@ -312,7 +314,7 @@ static int edbm_extrude_repeat_exec(bContext *C, wmOperator *op) mul_v3_m3v3(offset_local, tmat, offset); for (int a = 0; a < steps; a++) { - edbm_extrude_ex(obedit, em, BM_ALL_NOLOOP, BM_ELEM_SELECT, false, false, true); + edbm_extrude_ex(obedit, em, BM_ALL_NOLOOP, BM_ELEM_SELECT, false, false, false, true); BMO_op_callf( em->bm, BMO_FLAG_DEFAULTS, "translate vec=%v verts=%hv", offset_local, BM_ELEM_SELECT); } @@ -359,6 +361,7 @@ void MESH_OT_extrude_repeat(wmOperatorType *ot) static bool edbm_extrude_mesh(Object *obedit, BMEditMesh *em, wmOperator *op) { const bool use_normal_flip = RNA_boolean_get(op->ptr, "use_normal_flip"); + const bool use_dissolve_ortho_edges = RNA_boolean_get(op->ptr, "use_dissolve_ortho_edges"); const char htype = edbm_extrude_htype_from_em_select(em); enum { NONE = 0, ELEM_FLAG, VERT_ONLY, EDGE_ONLY } nr; bool changed = false; @@ -401,7 +404,14 @@ static bool edbm_extrude_mesh(Object *obedit, BMEditMesh *em, wmOperator *op) case NONE: return false; case ELEM_FLAG: - changed = edbm_extrude_ex(obedit, em, htype, BM_ELEM_SELECT, use_normal_flip, true, true); + changed = edbm_extrude_ex(obedit, + em, + htype, + BM_ELEM_SELECT, + use_normal_flip, + use_dissolve_ortho_edges, + true, + true); break; case VERT_ONLY: changed = edbm_extrude_verts_indiv(em, op, BM_ELEM_SELECT); @@ -465,6 +475,7 @@ void MESH_OT_extrude_region(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; RNA_def_boolean(ot->srna, "use_normal_flip", false, "Flip Normals", ""); + RNA_def_boolean(ot->srna, "use_dissolve_ortho_edges", false, "Dissolve Orthogonal Edges", ""); Transform_Properties(ot, P_NO_DEFAULTS | P_MIRROR_DUMMY); } @@ -519,6 +530,7 @@ void MESH_OT_extrude_context(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; RNA_def_boolean(ot->srna, "use_normal_flip", false, "Flip Normals", ""); + RNA_def_boolean(ot->srna, "use_dissolve_ortho_edges", false, "Dissolve Orthogonal Edges", ""); Transform_Properties(ot, P_NO_DEFAULTS | P_MIRROR_DUMMY); } @@ -840,7 +852,7 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w } } - edbm_extrude_ex(vc.obedit, vc.em, extrude_htype, BM_ELEM_SELECT, false, true, true); + edbm_extrude_ex(vc.obedit, vc.em, extrude_htype, BM_ELEM_SELECT, false, false, true, true); EDBM_op_callf( vc.em, op, "rotate verts=%hv cent=%v matrix=%m3", BM_ELEM_SELECT, local_center, mat); EDBM_op_callf(vc.em, op, "translate verts=%hv vec=%v", BM_ELEM_SELECT, ofs); diff --git a/source/blender/editors/mesh/editmesh_loopcut.c b/source/blender/editors/mesh/editmesh_loopcut.c index 37bacb4af55..3861676c2cf 100644 --- a/source/blender/editors/mesh/editmesh_loopcut.c +++ b/source/blender/editors/mesh/editmesh_loopcut.c @@ -372,7 +372,8 @@ static int loopcut_init(bContext *C, wmOperator *op, const wmEvent *event) if (is_interactive) { for (uint base_index = 0; base_index < bases_len; base_index++) { Object *ob_iter = bases[base_index]->object; - if (modifiers_isDeformedByLattice(ob_iter) || modifiers_isDeformedByArmature(ob_iter)) { + if (BKE_modifiers_is_deformed_by_lattice(ob_iter) || + BKE_modifiers_is_deformed_by_armature(ob_iter)) { BKE_report( op->reports, RPT_WARNING, "Loop cut does not work well on deformed edit mesh display"); break; diff --git a/source/blender/editors/mesh/editmesh_mask_extract.c b/source/blender/editors/mesh/editmesh_mask_extract.c index c02ef9835a0..739bc5bdf7c 100644 --- a/source/blender/editors/mesh/editmesh_mask_extract.c +++ b/source/blender/editors/mesh/editmesh_mask_extract.c @@ -224,7 +224,7 @@ static int paint_mask_extract_exec(bContext *C, wmOperator *op) if (RNA_boolean_get(op->ptr, "add_solidify")) { ED_object_modifier_add( op->reports, bmain, scene, new_ob, "mask_extract_solidify", eModifierType_Solidify); - SolidifyModifierData *sfmd = (SolidifyModifierData *)modifiers_findByName( + SolidifyModifierData *sfmd = (SolidifyModifierData *)BKE_modifiers_findby_name( new_ob, "mask_extract_solidify"); if (sfmd) { sfmd->offset = -0.05f; diff --git a/source/blender/editors/mesh/editmesh_select_similar.c b/source/blender/editors/mesh/editmesh_select_similar.c index 5106108a16c..365c5b5d264 100644 --- a/source/blender/editors/mesh/editmesh_select_similar.c +++ b/source/blender/editors/mesh/editmesh_select_similar.c @@ -1059,7 +1059,7 @@ static int similar_vert_select_exec(bContext *C, wmOperator *op) if (type == SIMVERT_VGROUP) { /* We store the names of the vertex groups, so we can select - * vertex groups with the same name in different objects. */ + * vertex groups with the same name in different objects. */ const int dvert_tot = BLI_listbase_count(&ob->defbase); for (int i = 0; i < dvert_tot; i++) { if (dvert_selected & (1 << i)) { diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index 5c7c95b59d7..684bb73dc0e 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -1970,6 +1970,84 @@ void MESH_OT_duplicate(wmOperatorType *ot) RNA_def_int(ot->srna, "mode", TFM_TRANSLATION, 0, INT_MAX, "Mode", "", 0, INT_MAX); } +static BMLoopNorEditDataArray *flip_custom_normals_init_data(BMesh *bm) +{ + BMLoopNorEditDataArray *lnors_ed_arr = NULL; + if (CustomData_has_layer(&bm->ldata, CD_CUSTOMLOOPNORMAL)) { + /* The mesh has custom normal data, update these too. + * Otherwise they will be left in a mangled state. + */ + BM_lnorspace_update(bm); + lnors_ed_arr = BM_loop_normal_editdata_array_init(bm, true); + } + + return lnors_ed_arr; +} + +static bool flip_custom_normals(BMesh *bm, BMLoopNorEditDataArray *lnors_ed_arr) +{ + if (!lnors_ed_arr) { + return false; + } + + if (lnors_ed_arr->totloop == 0) { + /* No loops normals to flip, exit early! */ + return false; + } + + bm->spacearr_dirty |= BM_SPACEARR_DIRTY_ALL; + BM_lnorspace_update(bm); + + /* We need to recreate the custom normal array because the clnors_data will + * be mangled because we swapped the loops around when we flipped the faces. */ + BMLoopNorEditDataArray *lnors_ed_arr_new_full = BM_loop_normal_editdata_array_init(bm, true); + + { + /* We need to recalculate all loop normals in the affected area. Even the ones that are not + * going to be flipped because the clnors data is mangled. */ + + BMLoopNorEditData *lnor_ed_new_full = lnors_ed_arr_new_full->lnor_editdata; + for (int i = 0; i < lnors_ed_arr_new_full->totloop; i++, lnor_ed_new_full++) { + + BMLoopNorEditData *lnor_ed = + lnors_ed_arr->lidx_to_lnor_editdata[lnor_ed_new_full->loop_index]; + + BLI_assert(lnor_ed != NULL); + + BKE_lnor_space_custom_normal_to_data( + bm->lnor_spacearr->lspacearr[lnor_ed_new_full->loop_index], + lnor_ed->nloc, + lnor_ed_new_full->clnors_data); + } + } + + BMFace *f; + BMLoop *l; + BMIter iter_f, iter_l; + BM_ITER_MESH (f, &iter_f, bm, BM_FACES_OF_MESH) { + if (!BM_elem_flag_test(f, BM_ELEM_SELECT)) { + continue; + } + /* Flip all the custom loop normals on the selected faces. */ + + BM_ITER_ELEM (l, &iter_l, f, BM_LOOPS_OF_FACE) { + + int loop_index = BM_elem_index_get(l); + + BMLoopNorEditData *lnor_ed = lnors_ed_arr->lidx_to_lnor_editdata[loop_index]; + BMLoopNorEditData *lnor_ed_new = lnors_ed_arr_new_full->lidx_to_lnor_editdata[loop_index]; + BLI_assert(lnor_ed != NULL && lnor_ed_new != NULL); + + negate_v3(lnor_ed->nloc); + + BKE_lnor_space_custom_normal_to_data( + bm->lnor_spacearr->lspacearr[loop_index], lnor_ed->nloc, lnor_ed_new->clnors_data); + } + } + BM_loop_normal_editdata_array_free(lnors_ed_arr_new_full); + return true; +} + /** \} */ /* -------------------------------------------------------------------- */ @@ -1977,6 +2055,8 @@ void MESH_OT_duplicate(wmOperatorType *ot) * \{ */ static int edbm_flip_normals_exec(bContext *C, wmOperator *op) { + const bool only_clnors = RNA_boolean_get(op->ptr, "only_clnors"); + 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( @@ -1986,15 +2066,48 @@ static int edbm_flip_normals_exec(bContext *C, wmOperator *op) Object *obedit = objects[ob_index]; BMEditMesh *em = BKE_editmesh_from_object(obedit); - if (em->bm->totfacesel == 0) { + if (only_clnors) { + if (CustomData_has_layer(&em->bm->ldata, CD_CUSTOMLOOPNORMAL)) { + /* The mesh has custom normal data, flip them. */ + BMesh *bm = em->bm; + + BM_lnorspace_update(bm); + BMLoopNorEditDataArray *lnors_ed_arr = BM_loop_normal_editdata_array_init(bm, false); + BMLoopNorEditData *lnor_ed = lnors_ed_arr->lnor_editdata; + + for (int i = 0; i < lnors_ed_arr->totloop; i++, lnor_ed++) { + negate_v3(lnor_ed->nloc); + + BKE_lnor_space_custom_normal_to_data(bm->lnor_spacearr->lspacearr[lnor_ed->loop_index], + lnor_ed->nloc, + lnor_ed->clnors_data); + } + BM_loop_normal_editdata_array_free(lnors_ed_arr); + EDBM_update_generic(obedit->data, true, false); + } continue; } - if (!EDBM_op_callf(em, op, "reverse_faces faces=%hf flip_multires=%b", BM_ELEM_SELECT, true)) { + if (em->bm->totfacesel == 0) { continue; } - EDBM_update_generic(obedit->data, true, false); + bool has_flipped_faces = false; + + /* See if we have any custom normals to flip. */ + BMLoopNorEditDataArray *lnors_ed_arr = flip_custom_normals_init_data(em->bm); + + if (EDBM_op_callf(em, op, "reverse_faces faces=%hf flip_multires=%b", BM_ELEM_SELECT, true)) { + has_flipped_faces = true; + } + + if (flip_custom_normals(em->bm, lnors_ed_arr) || has_flipped_faces) { + EDBM_update_generic(obedit->data, true, false); + } + + if (lnors_ed_arr != NULL) { + BM_loop_normal_editdata_array_free(lnors_ed_arr); + } } MEM_freeN(objects); @@ -2014,6 +2127,12 @@ void MESH_OT_flip_normals(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + RNA_def_boolean(ot->srna, + "only_clnors", + false, + "Custom Normals Only", + "Only flip the custom loop normals of the selected elements"); } /** \} */ @@ -2276,6 +2395,7 @@ void MESH_OT_reveal(wmOperatorType *ot) static int edbm_normals_make_consistent_exec(bContext *C, wmOperator *op) { ViewLayer *view_layer = CTX_data_view_layer(C); + const bool inside = RNA_boolean_get(op->ptr, "inside"); uint objects_len = 0; Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( @@ -2288,11 +2408,23 @@ static int edbm_normals_make_consistent_exec(bContext *C, wmOperator *op) continue; } + BMLoopNorEditDataArray *lnors_ed_arr = NULL; + + if (inside) { + /* Save custom normal data for later so we can flip them correctly. */ + lnors_ed_arr = flip_custom_normals_init_data(em->bm); + } + if (!EDBM_op_callf(em, op, "recalc_face_normals faces=%hf", BM_ELEM_SELECT)) { continue; } - if (RNA_boolean_get(op->ptr, "inside")) { + + if (inside) { EDBM_op_callf(em, op, "reverse_faces faces=%hf flip_multires=%b", BM_ELEM_SELECT, true); + flip_custom_normals(em->bm, lnors_ed_arr); + if (lnors_ed_arr != NULL) { + BM_loop_normal_editdata_array_free(lnors_ed_arr); + } } EDBM_update_generic(obedit->data, true, false); diff --git a/source/blender/editors/mesh/editmesh_undo.c b/source/blender/editors/mesh/editmesh_undo.c index 48ec41027ff..e4ecfa9c680 100644 --- a/source/blender/editors/mesh/editmesh_undo.c +++ b/source/blender/editors/mesh/editmesh_undo.c @@ -397,9 +397,7 @@ struct UMArrayData { UndoMesh *um; const UndoMesh *um_ref; /* can be NULL */ }; -static void um_arraystore_compact_cb(TaskPool *__restrict UNUSED(pool), - void *taskdata, - int UNUSED(threadid)) +static void um_arraystore_compact_cb(TaskPool *__restrict UNUSED(pool), void *taskdata) { struct UMArrayData *um_data = taskdata; um_arraystore_compact_with_info(um_data->um, um_data->um_ref); @@ -541,9 +539,7 @@ static void *undomesh_from_editmesh(UndoMesh *um, BMEditMesh *em, Key *key) # ifdef USE_ARRAY_STORE_THREAD if (um_arraystore.task_pool == NULL) { - TaskScheduler *scheduler = BLI_task_scheduler_get(); - um_arraystore.task_pool = BLI_task_pool_create_background( - scheduler, NULL, TASK_PRIORITY_LOW); + um_arraystore.task_pool = BLI_task_pool_create_background(NULL, TASK_PRIORITY_LOW); } struct UMArrayData *um_data = MEM_mallocN(sizeof(*um_data), __func__); diff --git a/source/blender/editors/mesh/mesh_ops.c b/source/blender/editors/mesh/mesh_ops.c index 66b2c66f2aa..c52a5956ac4 100644 --- a/source/blender/editors/mesh/mesh_ops.c +++ b/source/blender/editors/mesh/mesh_ops.c @@ -277,6 +277,18 @@ void ED_operatormacros_mesh(void) RNA_boolean_set(otmacro->ptr, "use_proportional_edit", false); RNA_boolean_set(otmacro->ptr, "mirror", false); + ot = WM_operatortype_append_macro( + "MESH_OT_extrude_region_dissolve_move_intersect", + "Extrude, Dissolve, Move and Intersect", + "Extrude, dissolves edges whose faces form a flat surface and intersect new edges", + OPTYPE_UNDO | OPTYPE_REGISTER); + otmacro = WM_operatortype_macro_define(ot, "MESH_OT_extrude_region"); + RNA_boolean_set(otmacro->ptr, "use_dissolve_ortho_edges", true); + otmacro = WM_operatortype_macro_define(ot, "TRANSFORM_OT_translate"); + RNA_boolean_set(otmacro->ptr, "use_proportional_edit", false); + RNA_boolean_set(otmacro->ptr, "mirror", false); + RNA_boolean_set(otmacro->ptr, "use_automerge_and_split", true); + ot = WM_operatortype_append_macro("MESH_OT_extrude_context_move", "Extrude Region and Move", "Extrude region together along the average normal", diff --git a/source/blender/editors/object/CMakeLists.txt b/source/blender/editors/object/CMakeLists.txt index c2c25e47908..fb273cf49a8 100644 --- a/source/blender/editors/object/CMakeLists.txt +++ b/source/blender/editors/object/CMakeLists.txt @@ -17,8 +17,8 @@ set(INC ../include - ../../blenkernel ../../blenfont + ../../blenkernel ../../blenlib ../../blentranslation ../../bmesh @@ -34,6 +34,7 @@ set(INC ../../shader_fx ../../render/extern/include ../../windowmanager + ../../../../intern/clog ../../../../intern/glew-mx ../../../../intern/guardedalloc ) diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index 6e342b7ed47..2ee98f39306 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -64,7 +64,7 @@ #include "BKE_duplilist.h" #include "BKE_effect.h" #include "BKE_font.h" -#include "BKE_gpencil_geom.h" +#include "BKE_gpencil_curve.h" #include "BKE_hair.h" #include "BKE_key.h" #include "BKE_lattice.h" @@ -146,7 +146,7 @@ static const EnumPropertyItem field_type_items[] = { {PFIELD_BOID, "BOID", ICON_FORCE_BOID, "Boid", ""}, {PFIELD_TURBULENCE, "TURBULENCE", ICON_FORCE_TURBULENCE, "Turbulence", ""}, {PFIELD_DRAG, "DRAG", ICON_FORCE_DRAG, "Drag", ""}, - {PFIELD_SMOKEFLOW, "SMOKE", ICON_FORCE_SMOKEFLOW, "Smoke Flow", ""}, + {PFIELD_FLUIDFLOW, "FLUID", ICON_FORCE_FLUIDFLOW, "Fluid Flow", ""}, {0, NULL, 0, NULL, NULL}, }; @@ -1365,6 +1365,7 @@ static int collection_instance_add_exec(bContext *C, wmOperator *op) Object *ob = ED_object_add_type( C, OB_EMPTY, collection->id.name + 2, loc, rot, false, local_view_bits); ob->instance_collection = collection; + ob->empty_drawsize = U.collection_instance_empty_size; ob->transflag |= OB_DUPLICOLLECTION; id_us_plus(&collection->id); @@ -2547,7 +2548,12 @@ static int convert_exec(bContext *C, wmOperator *op) } if (!keep_original && (ob->flag & OB_DONE)) { - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + /* NOTE: Tag transform for update because object parenting to curve with path is handled + * differently from all other cases. Converting curve to mesh and mesh to curve will likely + * affect the way children are evaluated. + * It is not enough to tag only geometry and rely on the curve parenting relations because + * this relation is lost when curve is converted to mesh. */ + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY | ID_RECALC_TRANSFORM); ((ID *)ob->data)->tag &= ~LIB_TAG_DOIT; /* flag not to convert this datablock again */ } } diff --git a/source/blender/editors/object/object_bake.c b/source/blender/editors/object/object_bake.c index 2cb0229126d..baa24ab2f4e 100644 --- a/source/blender/editors/object/object_bake.c +++ b/source/blender/editors/object/object_bake.c @@ -156,7 +156,7 @@ static bool multiresbake_check(bContext *C, wmOperator *op) ok = mmd->totlvl > 0; for (md = (ModifierData *)mmd->modifier.next; md && ok; md = md->next) { - if (modifier_isEnabled(scene, md, eModifierMode_Realtime)) { + if (BKE_modifier_is_enabled(scene, md, eModifierMode_Realtime)) { ok = false; } } diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c index debad321583..e84dbca2469 100644 --- a/source/blender/editors/object/object_bake_api.c +++ b/source/blender/editors/object/object_bake_api.c @@ -96,6 +96,7 @@ typedef struct BakeAPIRender { bool is_cage; float cage_extrusion; + float max_ray_distance; int normal_space; eBakeNormalSwizzle normal_swizzle[3]; @@ -737,6 +738,7 @@ static int bake(Render *re, const bool is_selected_to_active, const bool is_cage, const float cage_extrusion, + const float max_ray_distance, const int normal_space, const eBakeNormalSwizzle normal_swizzle[], const char *custom_cage, @@ -895,7 +897,7 @@ static int bake(Render *re, /* for multires bake, use linear UV subdivision to match low res UVs */ if (pass_type == SCE_PASS_NORMAL && normal_space == R_BAKE_SPACE_TANGENT && !is_selected_to_active) { - mmd_low = (MultiresModifierData *)modifiers_findByType(ob_low, eModifierType_Multires); + mmd_low = (MultiresModifierData *)BKE_modifiers_findby_type(ob_low, eModifierType_Multires); if (mmd_low) { mmd_flags_low = mmd_low->flags; mmd_low->uv_smooth = SUBSURF_UV_SMOOTH_NONE; @@ -945,7 +947,7 @@ static int bake(Render *re, if (md->type == eModifierType_EdgeSplit) { BLI_remlink(&ob_low_eval->modifiers, md); - modifier_free(md); + BKE_modifier_free(md); is_changed = true; } md = md_next; @@ -1010,6 +1012,7 @@ static int bake(Render *re, num_pixels, ob_cage != NULL, cage_extrusion, + max_ray_distance, ob_low_eval->obmat, (ob_cage ? ob_cage->obmat : ob_low_eval->obmat), me_cage)) { @@ -1024,7 +1027,7 @@ static int bake(Render *re, highpoly[i].ob, i, pixel_array_high, - num_pixels, + &bake_images, depth, pass_type, pass_filter, @@ -1046,7 +1049,7 @@ static int bake(Render *re, ob_low_eval, 0, pixel_array_low, - num_pixels, + &bake_images, depth, pass_type, pass_filter, @@ -1096,7 +1099,7 @@ static int bake(Render *re, int mode; BKE_object_eval_reset(ob_low_eval); - md = modifiers_findByType(ob_low_eval, eModifierType_Multires); + md = BKE_modifiers_findby_type(ob_low_eval, eModifierType_Multires); if (md) { mode = md->mode; @@ -1305,6 +1308,7 @@ static void bake_init_api_data(wmOperator *op, bContext *C, BakeAPIRender *bkr) bkr->is_selected_to_active = RNA_boolean_get(op->ptr, "use_selected_to_active"); bkr->is_cage = RNA_boolean_get(op->ptr, "use_cage"); bkr->cage_extrusion = RNA_float_get(op->ptr, "cage_extrusion"); + bkr->max_ray_distance = RNA_float_get(op->ptr, "max_ray_distance"); bkr->normal_space = RNA_enum_get(op->ptr, "normal_space"); bkr->normal_swizzle[0] = RNA_enum_get(op->ptr, "normal_r"); @@ -1394,6 +1398,7 @@ static int bake_exec(bContext *C, wmOperator *op) true, bkr.is_cage, bkr.cage_extrusion, + bkr.max_ray_distance, bkr.normal_space, bkr.normal_swizzle, bkr.custom_cage, @@ -1426,6 +1431,7 @@ static int bake_exec(bContext *C, wmOperator *op) false, bkr.is_cage, bkr.cage_extrusion, + bkr.max_ray_distance, bkr.normal_space, bkr.normal_swizzle, bkr.custom_cage, @@ -1495,6 +1501,7 @@ static void bake_startjob(void *bkv, short *UNUSED(stop), short *do_update, floa true, bkr->is_cage, bkr->cage_extrusion, + bkr->max_ray_distance, bkr->normal_space, bkr->normal_swizzle, bkr->custom_cage, @@ -1527,6 +1534,7 @@ static void bake_startjob(void *bkv, short *UNUSED(stop), short *do_update, floa false, bkr->is_cage, bkr->cage_extrusion, + bkr->max_ray_distance, bkr->normal_space, bkr->normal_swizzle, bkr->custom_cage, @@ -1586,6 +1594,11 @@ static void bake_set_props(wmOperator *op, Scene *scene) RNA_property_boolean_set(op->ptr, prop, (bake->flag & R_BAKE_TO_ACTIVE) != 0); } + prop = RNA_struct_find_property(op->ptr, "max_ray_distance"); + if (!RNA_property_is_set(op->ptr, prop)) { + RNA_property_float_set(op->ptr, prop, bake->max_ray_distance); + } + prop = RNA_struct_find_property(op->ptr, "cage_extrusion"); if (!RNA_property_is_set(op->ptr, prop)) { RNA_property_float_set(op->ptr, prop, bake->cage_extrusion); @@ -1766,12 +1779,23 @@ void OBJECT_OT_bake(wmOperatorType *ot) "Selected to Active", "Bake shading on the surface of selected objects to the active object"); RNA_def_float(ot->srna, + "max_ray_distance", + 0.0f, + 0.0f, + FLT_MAX, + "Max Ray Distance", + "The maximum ray distance for matching points between the active and selected " + "objects. If zero, there is no limit", + 0.0f, + 1.0f); + RNA_def_float(ot->srna, "cage_extrusion", 0.0f, 0.0f, FLT_MAX, "Cage Extrusion", - "Distance to use for the inward ray cast when using selected to active", + "Inflate the active object by the specified distance for baking. This helps " + "matching to points nearer to the outside of the selected object meshes", 0.0f, 1.0f); RNA_def_string(ot->srna, diff --git a/source/blender/editors/object/object_collection.c b/source/blender/editors/object/object_collection.c index e266899cc9f..7a83d582299 100644 --- a/source/blender/editors/object/object_collection.c +++ b/source/blender/editors/object/object_collection.c @@ -495,7 +495,7 @@ static int collection_link_exec(bContext *C, wmOperator *op) /* Adding object to collection which is used as dupli-collection for self is bad idea. * - * It is also bad idea to add object to collection which is in collection which + * It is also bad idea to add object to collection which is in collection which * contains our current object. */ if (BKE_collection_object_cyclic_check(bmain, ob, collection)) { diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c index c6ed64ac7c3..53a557c5871 100644 --- a/source/blender/editors/object/object_edit.c +++ b/source/blender/editors/object/object_edit.c @@ -100,6 +100,8 @@ #include "RNA_define.h" #include "RNA_enum_types.h" +#include "CLG_log.h" + /* for menu/popup icons etc etc*/ #include "UI_interface.h" @@ -112,21 +114,17 @@ #include "object_intern.h" // own include +static CLG_LogRef LOG = {"ed.object.edit"}; + /* prototypes */ typedef struct MoveToCollectionData MoveToCollectionData; static void move_to_collection_menus_items(struct uiLayout *layout, struct MoveToCollectionData *menu); static ListBase selected_objects_get(bContext *C); -/* ************* XXX **************** */ -static void error(const char *UNUSED(arg)) -{ -} - -/* port over here */ -static void error_libdata(void) -{ -} +/* -------------------------------------------------------------------- */ +/** \name Internal Utilities + * \{ */ Object *ED_object_context(bContext *C) { @@ -147,7 +145,11 @@ Object *ED_object_active_context(bContext *C) return ob; } -/* ********************** object hiding *************************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Hide Operator + * \{ */ static bool object_hide_poll(bContext *C) { @@ -401,7 +403,11 @@ void OBJECT_OT_hide_collection(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN); } -/* ******************* toggle editmode operator ***************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Toggle Edit-Mode Operator + * \{ */ static bool mesh_needs_keyindex(Main *bmain, const Mesh *me) { @@ -441,7 +447,11 @@ static bool ED_object_editmode_load_ex(Main *bmain, Object *obedit, const bool f } if (me->edit_mesh->bm->totvert > MESH_MAX_VERTS) { - error("Too many vertices"); + /* This used to be warned int the UI, we could warn again although it's quite rare. */ + CLOG_WARN(&LOG, + "Too many vertices for mesh '%s' (%d)", + me->id.name + 2, + me->edit_mesh->bm->totvert); return false; } @@ -600,7 +610,8 @@ bool ED_object_editmode_enter_ex(Main *bmain, Scene *scene, Object *ob, int flag } if (BKE_object_obdata_is_libdata(ob)) { - error_libdata(); + /* Ideally the caller should check this. */ + CLOG_WARN(&LOG, "Unable to enter edit-mode on library data for object '%s'", ob->id.name + 2); return false; } @@ -777,7 +788,11 @@ void OBJECT_OT_editmode_toggle(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* *************************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Toggle Pose-Mode Operator + * \{ */ static int posemode_exec(bContext *C, wmOperator *op) { @@ -861,12 +876,16 @@ void OBJECT_OT_posemode_toggle(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* ******************* force field toggle operator ***************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Force Field Toggle Operator + * \{ */ void ED_object_check_force_modifiers(Main *bmain, Scene *scene, Object *object) { PartDeflect *pd = object->pd; - ModifierData *md = modifiers_findByType(object, eModifierType_Surface); + ModifierData *md = BKE_modifiers_findby_type(object, eModifierType_Surface); /* add/remove modifier as needed */ if (!md) { @@ -924,8 +943,11 @@ void OBJECT_OT_forcefield_toggle(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* ********************************************** */ -/* Motion Paths */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Calculate Motion Paths Operator + * \{ */ static eAnimvizCalcRange object_path_convert_range(eObjectPathCalcRange range) { @@ -1019,7 +1041,7 @@ static int object_calculate_paths_invoke(bContext *C, wmOperator *op, const wmEv } /* show popup dialog to allow editing of range... */ - /* FIXME: hardcoded dimensions here are just arbitrary */ + /* FIXME: hard-coded dimensions here are just arbitrary. */ return WM_operator_props_dialog_popup(C, op, 200); } @@ -1088,7 +1110,11 @@ void OBJECT_OT_paths_calculate(wmOperatorType *ot) MAXFRAME / 2.0); } -/* --------- */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Update Motion Paths Operator + * \{ */ static bool object_update_paths_poll(bContext *C) { @@ -1132,7 +1158,11 @@ void OBJECT_OT_paths_update(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* --------- */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Clear Motion Paths Operator + * \{ */ /* Helper for ED_objects_clear_paths() */ static void object_clear_mpath(Object *ob) @@ -1151,14 +1181,14 @@ static void object_clear_mpath(Object *ob) void ED_objects_clear_paths(bContext *C, bool only_selected) { if (only_selected) { - /* loop over all selected + sedtiable objects in scene */ + /* Loop over all selected + editable objects in scene. */ CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) { object_clear_mpath(ob); } CTX_DATA_END; } else { - /* loop over all edtiable objects in scene */ + /* Loop over all editable objects in scene. */ CTX_DATA_BEGIN (C, Object *, ob, editable_objects) { object_clear_mpath(ob); } @@ -1210,13 +1240,17 @@ void OBJECT_OT_paths_clear(wmOperatorType *ot) RNA_def_property_flag(ot->prop, PROP_SKIP_SAVE); } -/* --------- */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Update Motion Paths Range from Scene Operator + * \{ */ static int object_update_paths_range_exec(bContext *C, wmOperator *UNUSED(op)) { Scene *scene = CTX_data_scene(C); - /* loop over all edtiable objects in scene */ + /* Loop over all editable objects in scene. */ CTX_DATA_BEGIN (C, Object *, ob, editable_objects) { /* use Preview Range or Full Frame Range - whichever is in use */ ob->avs.path_sf = PSFRA; @@ -1246,63 +1280,99 @@ void OBJECT_OT_paths_range_update(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/********************** Smooth/Flat *********************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Object Shade Smooth/Flat Operator + * \{ */ static int shade_smooth_exec(bContext *C, wmOperator *op) { - ID *data; - Curve *cu; - Nurb *nu; - int clear = (STREQ(op->idname, "OBJECT_OT_shade_flat")); - bool done = false, linked_data = false; + const bool use_smooth = STREQ(op->idname, "OBJECT_OT_shade_smooth"); + bool changed_multi = false; + bool has_linked_data = false; - CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) { - data = ob->data; + ListBase ctx_objects = {NULL, NULL}; + CollectionPointerLink ctx_ob_single_active = {NULL}; + + /* For modes that only use an active object, don't handle the whole selection. */ + { + ViewLayer *view_layer = CTX_data_view_layer(C); + Object *obact = OBACT(view_layer); + if (obact && ((obact->mode & OB_MODE_ALL_PAINT))) { + ctx_ob_single_active.ptr.data = obact; + BLI_addtail(&ctx_objects, &ctx_ob_single_active); + } + } + + if (ctx_objects.first != &ctx_ob_single_active) { + CTX_data_selected_editable_objects(C, &ctx_objects); + } + + for (CollectionPointerLink *ctx_ob = ctx_objects.first; ctx_ob; ctx_ob = ctx_ob->next) { + Object *ob = ctx_ob->ptr.data; + ID *data = ob->data; + if (data != NULL) { + data->tag |= LIB_TAG_DOIT; + } + } + + for (CollectionPointerLink *ctx_ob = ctx_objects.first; ctx_ob; ctx_ob = ctx_ob->next) { + /* Always un-tag all object data-blocks irrespective of our ability to operate on them. */ + Object *ob = ctx_ob->ptr.data; + ID *data = ob->data; + if ((data == NULL) || ((data->tag & LIB_TAG_DOIT) == 0)) { + continue; + } + data->tag &= ~LIB_TAG_DOIT; + /* Finished un-tagging, continue with regular logic. */ if (data && ID_IS_LINKED(data)) { - linked_data = true; + has_linked_data = true; continue; } + bool changed = false; if (ob->type == OB_MESH) { - BKE_mesh_smooth_flag_set(ob->data, !clear); - + BKE_mesh_smooth_flag_set(ob->data, use_smooth); BKE_mesh_batch_cache_dirty_tag(ob->data, BKE_MESH_BATCH_DIRTY_ALL); - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); - - done = true; + changed = true; } else if (ELEM(ob->type, OB_SURF, OB_CURVE)) { - cu = ob->data; + BKE_curve_smooth_flag_set(ob->data, use_smooth); + changed = true; + } - for (nu = cu->nurb.first; nu; nu = nu->next) { - if (!clear) { - nu->flag |= ME_SMOOTH; - } - else { - nu->flag &= ~ME_SMOOTH; - } - } + if (changed) { + changed_multi = true; DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); - - done = true; } } - CTX_DATA_END; - if (linked_data) { + if (ctx_objects.first != &ctx_ob_single_active) { + BLI_freelistN(&ctx_objects); + } + + if (has_linked_data) { BKE_report(op->reports, RPT_WARNING, "Can't edit linked mesh or curve data"); } - return (done) ? OPERATOR_FINISHED : OPERATOR_CANCELLED; + return (changed_multi) ? OPERATOR_FINISHED : OPERATOR_CANCELLED; } static bool shade_poll(bContext *C) { - return (CTX_data_edit_object(C) == NULL); + ViewLayer *view_layer = CTX_data_view_layer(C); + Object *obact = OBACT(view_layer); + if (obact != NULL) { + /* Doesn't handle edit-data, sculpt dynamic-topology, or their undo systems. */ + if (obact->mode & (OB_MODE_EDIT | OB_MODE_SCULPT)) { + return false; + } + } + return true; } void OBJECT_OT_shade_flat(wmOperatorType *ot) @@ -1335,7 +1405,11 @@ void OBJECT_OT_shade_smooth(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* ********************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Object Mode Set Operator + * \{ */ static const EnumPropertyItem *object_mode_set_itemsf(bContext *C, PointerRNA *UNUSED(ptr), @@ -1355,7 +1429,8 @@ static const EnumPropertyItem *object_mode_set_itemsf(bContext *C, if (ob) { const bool use_mode_particle_edit = (BLI_listbase_is_empty(&ob->particlesystem) == false) || (ob->soft != NULL) || - (modifiers_findByType(ob, eModifierType_Cloth) != NULL); + (BKE_modifiers_findby_type(ob, eModifierType_Cloth) != + NULL); while (input->identifier) { if ((input->value == OB_MODE_EDIT && OB_TYPE_SUPPORT_EDITMODE(ob->type)) || (input->value == OB_MODE_POSE && (ob->type == OB_ARMATURE)) || @@ -1513,6 +1588,12 @@ void OBJECT_OT_mode_set_with_submode(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Object Link/Move to Collection Operator + * \{ */ + static ListBase selected_objects_get(bContext *C) { ListBase objects = {NULL}; @@ -1853,3 +1934,5 @@ void OBJECT_OT_link_to_collection(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_SKIP_SAVE); ot->prop = prop; } + +/** \} */ diff --git a/source/blender/editors/object/object_gpencil_modifier.c b/source/blender/editors/object/object_gpencil_modifier.c index 5bf5c4bd95a..6d0f53cfa1e 100644 --- a/source/blender/editors/object/object_gpencil_modifier.c +++ b/source/blender/editors/object/object_gpencil_modifier.c @@ -65,7 +65,7 @@ GpencilModifierData *ED_object_gpencil_modifier_add( ReportList *reports, Main *bmain, Scene *UNUSED(scene), Object *ob, const char *name, int type) { GpencilModifierData *new_md = NULL; - const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(type); + const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(type); if (ob->type != OB_GPENCIL) { BKE_reportf(reports, RPT_WARNING, "Modifiers cannot be added to object '%s'", ob->id.name + 2); @@ -73,7 +73,7 @@ GpencilModifierData *ED_object_gpencil_modifier_add( } if (mti->flags & eGpencilModifierTypeFlag_Single) { - if (BKE_gpencil_modifiers_findByType(ob, type)) { + if (BKE_gpencil_modifiers_findby_type(ob, type)) { BKE_report(reports, RPT_WARNING, "Only one modifier of this type is allowed"); return NULL; } @@ -214,7 +214,7 @@ int ED_object_gpencil_modifier_move_down(ReportList *UNUSED(reports), static int gpencil_modifier_apply_obdata( ReportList *reports, Main *bmain, Depsgraph *depsgraph, Object *ob, GpencilModifierData *md) { - const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type); + const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type); if (mti->isDisabled && mti->isDisabled(md, 0)) { BKE_report(reports, RPT_ERROR, "Modifier is disabled, skipping apply"); @@ -281,18 +281,18 @@ int ED_object_gpencil_modifier_apply(Main *bmain, int ED_object_gpencil_modifier_copy(ReportList *reports, Object *ob, GpencilModifierData *md) { GpencilModifierData *nmd; - const GpencilModifierTypeInfo *mti = BKE_gpencil_modifierType_getInfo(md->type); + const GpencilModifierTypeInfo *mti = BKE_gpencil_modifier_get_info(md->type); GpencilModifierType type = md->type; if (mti->flags & eGpencilModifierTypeFlag_Single) { - if (BKE_gpencil_modifiers_findByType(ob, type)) { + if (BKE_gpencil_modifiers_findby_type(ob, type)) { BKE_report(reports, RPT_WARNING, "Only one modifier of this type is allowed"); return 0; } } nmd = BKE_gpencil_modifier_new(md->type); - BKE_gpencil_modifier_copyData(md, nmd); + BKE_gpencil_modifier_copydata(md, nmd); BLI_insertlinkafter(&ob->greasepencil_modifiers, md, nmd); BKE_gpencil_modifier_unique_name(&ob->greasepencil_modifiers, nmd); @@ -335,7 +335,7 @@ static const EnumPropertyItem *gpencil_modifier_add_itemf(bContext *C, for (a = 0; rna_enum_object_greasepencil_modifier_type_items[a].identifier; a++) { md_item = &rna_enum_object_greasepencil_modifier_type_items[a]; if (md_item->identifier[0]) { - mti = BKE_gpencil_modifierType_getInfo(md_item->value); + mti = BKE_gpencil_modifier_get_info(md_item->value); if (mti->flags & eGpencilModifierTypeFlag_NoUserAdd) { continue; @@ -455,7 +455,7 @@ static GpencilModifierData *gpencil_edit_modifier_property_get(wmOperator *op, GpencilModifierData *md; RNA_string_get(op->ptr, "modifier", modifier_name); - md = BKE_gpencil_modifiers_findByName(ob, modifier_name); + md = BKE_gpencil_modifiers_findby_name(ob, modifier_name); if (md && type != 0 && md->type != type) { md = NULL; diff --git a/source/blender/editors/object/object_hook.c b/source/blender/editors/object/object_hook.c index 4414acff115..9d2e5e74352 100644 --- a/source/blender/editors/object/object_hook.c +++ b/source/blender/editors/object/object_hook.c @@ -552,14 +552,14 @@ static int add_hook_object(const bContext *C, } md = obedit->modifiers.first; - while (md && modifierType_getInfo(md->type)->type == eModifierTypeType_OnlyDeform) { + while (md && BKE_modifier_get_info(md->type)->type == eModifierTypeType_OnlyDeform) { md = md->next; } - hmd = (HookModifierData *)modifier_new(eModifierType_Hook); + hmd = (HookModifierData *)BKE_modifier_new(eModifierType_Hook); BLI_insertlinkbefore(&obedit->modifiers, md, hmd); BLI_snprintf(hmd->modifier.name, sizeof(hmd->modifier.name), "Hook-%s", ob->id.name + 2); - modifier_unique_name(&obedit->modifiers, (ModifierData *)hmd); + BKE_modifier_unique_name(&obedit->modifiers, (ModifierData *)hmd); hmd->object = ob; hmd->indexar = indexar; @@ -725,7 +725,7 @@ static int object_hook_remove_exec(bContext *C, wmOperator *op) /* remove functionality */ BLI_remlink(&ob->modifiers, (ModifierData *)hmd); - modifier_free((ModifierData *)hmd); + BKE_modifier_free((ModifierData *)hmd); DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h index d8ba270073e..d7a7b4ca110 100644 --- a/source/blender/editors/object/object_intern.h +++ b/source/blender/editors/object/object_intern.h @@ -169,6 +169,8 @@ void OBJECT_OT_multires_subdivide(struct wmOperatorType *ot); void OBJECT_OT_multires_reshape(struct wmOperatorType *ot); void OBJECT_OT_multires_higher_levels_delete(struct wmOperatorType *ot); void OBJECT_OT_multires_base_apply(struct wmOperatorType *ot); +void OBJECT_OT_multires_unsubdivide(struct wmOperatorType *ot); +void OBJECT_OT_multires_rebuild_subdiv(struct wmOperatorType *ot); void OBJECT_OT_multires_external_save(struct wmOperatorType *ot); void OBJECT_OT_multires_external_pack(struct wmOperatorType *ot); void OBJECT_OT_correctivesmooth_bind(struct wmOperatorType *ot); diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c index a24f3ba2269..9398a5f2ce7 100644 --- a/source/blender/editors/object/object_modifier.c +++ b/source/blender/editors/object/object_modifier.c @@ -135,23 +135,24 @@ static void object_force_modifier_bind_simple_options(Depsgraph *depsgraph, Object *object, ModifierData *md) { - ModifierData *md_eval = (ModifierData *)modifier_get_evaluated(depsgraph, object, md); + ModifierData *md_eval = (ModifierData *)BKE_modifier_get_evaluated(depsgraph, object, md); const int mode = md_eval->mode; md_eval->mode |= eModifierMode_Realtime; object_force_modifier_update_for_bind(depsgraph, object); md_eval->mode = mode; } -/** Add a modifier to given object, including relevant extra processing needed by some physics - * types (particles, simulations...). +/** + * Add a modifier to given object, including relevant extra processing needed by some physics types + * (particles, simulations...). * - * \param scene is only used to set current frame in some cases, and may be NULL. + * \param scene: is only used to set current frame in some cases, and may be NULL. */ ModifierData *ED_object_modifier_add( ReportList *reports, Main *bmain, Scene *scene, Object *ob, const char *name, int type) { ModifierData *md = NULL, *new_md = NULL; - const ModifierTypeInfo *mti = modifierType_getInfo(type); + const ModifierTypeInfo *mti = BKE_modifier_get_info(type); /* Check compatibility of modifier [T25291, T50373]. */ if (!BKE_object_support_modifier_type_check(ob, type)) { @@ -160,7 +161,7 @@ ModifierData *ED_object_modifier_add( } if (mti->flags & eModifierTypeFlag_Single) { - if (modifiers_findByType(ob, type)) { + if (BKE_modifiers_findby_type(ob, type)) { BKE_report(reports, RPT_WARNING, "Only one modifier of this type is allowed"); return NULL; } @@ -174,12 +175,12 @@ ModifierData *ED_object_modifier_add( } else { /* get new modifier data to add */ - new_md = modifier_new(type); + new_md = BKE_modifier_new(type); if (mti->flags & eModifierTypeFlag_RequiresOriginalData) { md = ob->modifiers.first; - while (md && modifierType_getInfo(md->type)->type == eModifierTypeType_OnlyDeform) { + while (md && BKE_modifier_get_info(md->type)->type == eModifierTypeType_OnlyDeform) { md = md->next; } @@ -195,7 +196,7 @@ ModifierData *ED_object_modifier_add( /* make sure modifier data has unique name */ - modifier_unique_name(&ob->modifiers, new_md); + BKE_modifier_unique_name(&ob->modifiers, new_md); /* special cases */ if (type == eModifierType_Softbody) { @@ -382,7 +383,7 @@ static bool object_modifier_remove(Main *bmain, } BLI_remlink(&ob->modifiers, md); - modifier_free(md); + BKE_modifier_free(md); BKE_object_free_derived_caches(ob); return 1; @@ -432,10 +433,10 @@ void ED_object_modifier_clear(Main *bmain, Object *ob) int ED_object_modifier_move_up(ReportList *reports, Object *ob, ModifierData *md) { if (md->prev) { - const ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); if (mti->type != eModifierTypeType_OnlyDeform) { - const ModifierTypeInfo *nmti = modifierType_getInfo(md->prev->type); + const ModifierTypeInfo *nmti = BKE_modifier_get_info(md->prev->type); if (nmti->flags & eModifierTypeFlag_RequiresOriginalData) { BKE_report(reports, RPT_WARNING, "Cannot move above a modifier requiring original data"); @@ -453,10 +454,10 @@ int ED_object_modifier_move_up(ReportList *reports, Object *ob, ModifierData *md int ED_object_modifier_move_down(ReportList *reports, Object *ob, ModifierData *md) { if (md->next) { - const ModifierTypeInfo *mti = modifierType_getInfo(md->type); + const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); if (mti->flags & eModifierTypeFlag_RequiresOriginalData) { - const ModifierTypeInfo *nmti = modifierType_getInfo(md->next->type); + const ModifierTypeInfo *nmti = BKE_modifier_get_info(md->next->type); if (nmti->type != eModifierTypeType_OnlyDeform) { BKE_report(reports, RPT_WARNING, "Cannot move beyond a non-deforming modifier"); @@ -619,7 +620,7 @@ static int modifier_apply_shape(Main *bmain, Object *ob, ModifierData *md_eval) { - const ModifierTypeInfo *mti = modifierType_getInfo(md_eval->type); + const ModifierTypeInfo *mti = BKE_modifier_get_info(md_eval->type); if (mti->isDisabled && mti->isDisabled(scene, md_eval, 0)) { BKE_report(reports, RPT_ERROR, "Modifier is disabled, skipping apply"); @@ -643,7 +644,7 @@ static int modifier_apply_shape(Main *bmain, Key *key = me->key; KeyBlock *kb; - if (!modifier_isSameTopology(md_eval) || mti->type == eModifierTypeType_NonGeometrical) { + if (!BKE_modifier_is_same_topology(md_eval) || mti->type == eModifierTypeType_NonGeometrical) { BKE_report(reports, RPT_ERROR, "Only deforming modifiers can be applied to shapes"); return 0; } @@ -679,7 +680,7 @@ static int modifier_apply_shape(Main *bmain, static int modifier_apply_obdata( ReportList *reports, Depsgraph *depsgraph, Scene *scene, Object *ob, ModifierData *md_eval) { - const ModifierTypeInfo *mti = modifierType_getInfo(md_eval->type); + const ModifierTypeInfo *mti = BKE_modifier_get_info(md_eval->type); if (mti->isDisabled && mti->isDisabled(scene, md_eval, 0)) { BKE_report(reports, RPT_ERROR, "Modifier is disabled, skipping apply"); @@ -790,7 +791,7 @@ bool ED_object_modifier_apply(Main *bmain, return false; } else if ((ob->mode & OB_MODE_SCULPT) && (find_multires_modifier_before(scene, md)) && - (modifier_isSameTopology(md) == false)) { + (BKE_modifier_is_same_topology(md) == false)) { BKE_report(reports, RPT_ERROR, "Constructive modifier cannot be applied to multi-res data in sculpt mode"); @@ -804,7 +805,7 @@ bool ED_object_modifier_apply(Main *bmain, /* Get evaluated modifier, so object links pointer to evaluated data, * but still use original object it is applied to the original mesh. */ Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob); - ModifierData *md_eval = (ob_eval) ? modifiers_findByName(ob_eval, md->name) : md; + ModifierData *md_eval = (ob_eval) ? BKE_modifiers_findby_name(ob_eval, md->name) : md; /* allow apply of a not-realtime modifier, by first re-enabling realtime. */ prev_mode = md_eval->mode; @@ -825,7 +826,7 @@ bool ED_object_modifier_apply(Main *bmain, md_eval->mode = prev_mode; BLI_remlink(&ob->modifiers, md); - modifier_free(md); + BKE_modifier_free(md); BKE_object_free_derived_caches(ob); @@ -836,10 +837,10 @@ int ED_object_modifier_copy(ReportList *UNUSED(reports), Object *ob, ModifierDat { ModifierData *nmd; - nmd = modifier_new(md->type); - modifier_copyData(md, nmd); + nmd = BKE_modifier_new(md->type); + BKE_modifier_copydata(md, nmd); BLI_insertlinkafter(&ob->modifiers, md, nmd); - modifier_unique_name(&ob->modifiers, nmd); + BKE_modifier_unique_name(&ob->modifiers, nmd); return 1; } @@ -885,7 +886,7 @@ static const EnumPropertyItem *modifier_add_itemf(bContext *C, md_item = &rna_enum_object_modifier_type_items[a]; if (md_item->identifier[0]) { - mti = modifierType_getInfo(md_item->value); + mti = BKE_modifier_get_info(md_item->value); if (mti->flags & eModifierTypeFlag_NoUserAdd) { continue; @@ -1019,7 +1020,7 @@ ModifierData *edit_modifier_property_get(wmOperator *op, Object *ob, int type) ModifierData *md; RNA_string_get(op->ptr, "modifier", modifier_name); - md = modifiers_findByName(ob, modifier_name); + md = BKE_modifiers_findby_name(ob, modifier_name); if (md && type != 0 && md->type != type) { md = NULL; @@ -1199,7 +1200,7 @@ static bool modifier_apply_poll(bContext *C) } else if (md != NULL) { if ((ob->mode & OB_MODE_SCULPT) && (find_multires_modifier_before(scene, md)) && - (modifier_isSameTopology(md) == false)) { + (BKE_modifier_is_same_topology(md) == false)) { CTX_wm_operator_poll_msg_set( C, "Constructive modifier cannot be applied to multi-res data in sculpt mode"); return false; @@ -1432,6 +1433,25 @@ void OBJECT_OT_multires_higher_levels_delete(wmOperatorType *ot) /** \name Multires Subdivide Operator * \{ */ +static EnumPropertyItem prop_multires_subdivide_mode_type[] = { + {MULTIRES_SUBDIVIDE_CATMULL_CLARK, + "CATMULL_CLARK", + 0, + "Catmull-Clark", + "Create a new level using Catmull-Clark subdivisions"}, + {MULTIRES_SUBDIVIDE_SIMPLE, + "SIMPLE", + 0, + "Simple", + "Create a new level using simple subdivisions"}, + {MULTIRES_SUBDIVIDE_LINEAR, + "LINEAR", + 0, + "Linear", + "Create a new level using linear interpolation of the sculpted displacement"}, + {0, NULL, 0, NULL, NULL}, +}; + static int multires_subdivide_exec(bContext *C, wmOperator *op) { Object *object = ED_object_active_context(C); @@ -1442,7 +1462,9 @@ static int multires_subdivide_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - multiresModifier_subdivide(object, mmd); + const eMultiresSubdivideModeType subdivide_mode = (eMultiresSubdivideModeType)( + RNA_enum_get(op->ptr, "mode")); + multiresModifier_subdivide(object, mmd, subdivide_mode); ED_object_iter_other( CTX_data_main(C), object, true, ED_object_multires_update_totlevels_cb, &mmd->totlvl); @@ -1481,6 +1503,12 @@ void OBJECT_OT_multires_subdivide(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; edit_modifier_properties(ot); + RNA_def_enum(ot->srna, + "mode", + prop_multires_subdivide_mode_type, + MULTIRES_SUBDIVIDE_CATMULL_CLARK, + "Subdivision Mode", + "How the mesh is going to be subdivided to create a new level"); } /** \} */ @@ -1738,6 +1766,119 @@ void OBJECT_OT_multires_base_apply(wmOperatorType *ot) /** \} */ /* ------------------------------------------------------------------- */ +/** \name Multires Unsubdivide + * \{ */ + +static int multires_unsubdivide_exec(bContext *C, wmOperator *op) +{ + Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); + Object *object = ED_object_active_context(C); + MultiresModifierData *mmd = (MultiresModifierData *)edit_modifier_property_get( + op, object, eModifierType_Multires); + + if (!mmd) { + return OPERATOR_CANCELLED; + } + + int new_levels = multiresModifier_rebuild_subdiv(depsgraph, object, mmd, 1, true); + if (new_levels == 0) { + BKE_report(op->reports, RPT_ERROR, "Not valid subdivisions found to rebuild a lower level"); + return OPERATOR_CANCELLED; + } + + DEG_id_tag_update(&object->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, object); + + return OPERATOR_FINISHED; +} + +static int multires_unsubdivide_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + if (edit_modifier_invoke_properties(C, op)) { + return multires_unsubdivide_exec(C, op); + } + else { + return OPERATOR_CANCELLED; + } +} + +void OBJECT_OT_multires_unsubdivide(wmOperatorType *ot) +{ + ot->name = "Unsubdivide"; + ot->description = "Rebuild a lower subdivision level of the current base mesh"; + ot->idname = "OBJECT_OT_multires_unsubdivide"; + + ot->poll = multires_poll; + ot->invoke = multires_unsubdivide_invoke; + ot->exec = multires_unsubdivide_exec; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; + edit_modifier_properties(ot); +} + +/** \} */ + +/* ------------------------------------------------------------------- */ +/** \name Multires Rebuild Subdivisions + * \{ */ + +static int multires_rebuild_subdiv_exec(bContext *C, wmOperator *op) +{ + Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); + Object *object = ED_object_active_context(C); + MultiresModifierData *mmd = (MultiresModifierData *)edit_modifier_property_get( + op, object, eModifierType_Multires); + + if (!mmd) { + return OPERATOR_CANCELLED; + } + + int new_levels = multiresModifier_rebuild_subdiv(depsgraph, object, mmd, INT_MAX, false); + if (new_levels == 0) { + BKE_report(op->reports, RPT_ERROR, "Not valid subdivisions found to rebuild lower levels"); + return OPERATOR_CANCELLED; + } + + BKE_reportf(op->reports, RPT_INFO, "%d new levels rebuilt", new_levels); + + DEG_id_tag_update(&object->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, object); + + return OPERATOR_FINISHED; +} + +static int multires_rebuild_subdiv_invoke(bContext *C, + wmOperator *op, + const wmEvent *UNUSED(event)) +{ + if (edit_modifier_invoke_properties(C, op)) { + return multires_rebuild_subdiv_exec(C, op); + } + else { + return OPERATOR_CANCELLED; + } +} + +void OBJECT_OT_multires_rebuild_subdiv(wmOperatorType *ot) +{ + ot->name = "Rebuild Lower Subdivisions"; + ot->description = + "Rebuilds all possible subdivisions levels to generate a lower resolution base mesh"; + ot->idname = "OBJECT_OT_multires_rebuild_subdiv"; + + ot->poll = multires_poll; + ot->invoke = multires_rebuild_subdiv_invoke; + ot->exec = multires_rebuild_subdiv_exec; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; + edit_modifier_properties(ot); +} + +/** \} */ + +/* ------------------------------------------------------------------- */ /** \name Skin Modifier * \{ */ @@ -2071,7 +2212,7 @@ static int skin_armature_create_exec(bContext *C, wmOperator *op) arm_ob = modifier_skin_armature_create(depsgraph, bmain, scene, ob); /* add a modifier to connect the new armature to the mesh */ - arm_md = (ArmatureModifierData *)modifier_new(eModifierType_Armature); + arm_md = (ArmatureModifierData *)BKE_modifier_new(eModifierType_Armature); if (arm_md) { skin_md = edit_modifier_property_get(op, ob, eModifierType_Skin); BLI_insertlinkafter(&ob->modifiers, skin_md, arm_md); @@ -2135,7 +2276,7 @@ static int correctivesmooth_bind_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - if (!modifier_isEnabled(scene, &csmd->modifier, eModifierMode_Realtime)) { + if (!BKE_modifier_is_enabled(scene, &csmd->modifier, eModifierMode_Realtime)) { BKE_report(op->reports, RPT_ERROR, "Modifier is disabled"); return OPERATOR_CANCELLED; } @@ -2152,7 +2293,7 @@ static int correctivesmooth_bind_exec(bContext *C, wmOperator *op) else { /* Signal to modifier to recalculate. */ CorrectiveSmoothModifierData *csmd_eval = (CorrectiveSmoothModifierData *) - modifier_get_evaluated(depsgraph, ob, &csmd->modifier); + BKE_modifier_get_evaluated(depsgraph, ob, &csmd->modifier); csmd_eval->bind_coords_num = (uint)-1; /* Force modifier to run, it will call binding routine @@ -2231,7 +2372,7 @@ static int meshdeform_bind_exec(bContext *C, wmOperator *op) else { /* Force modifier to run, it will call binding routine * (this has to happen outside of depsgraph evaluation). */ - MeshDeformModifierData *mmd_eval = (MeshDeformModifierData *)modifier_get_evaluated( + MeshDeformModifierData *mmd_eval = (MeshDeformModifierData *)BKE_modifier_get_evaluated( depsgraph, ob, &mmd->modifier); mmd_eval->bindfunc = ED_mesh_deform_bind_callback; object_force_modifier_bind_simple_options(depsgraph, ob, &mmd->modifier); @@ -2436,7 +2577,7 @@ static int ocean_bake_exec(bContext *C, wmOperator *op) } och = BKE_ocean_init_cache(omd->cachepath, - modifier_path_relbase(bmain, ob), + BKE_modifier_path_relbase(bmain, ob), omd->bakestart, omd->bakeend, omd->wave_scale, @@ -2455,7 +2596,7 @@ static int ocean_bake_exec(bContext *C, wmOperator *op) * No drivers or other modifier parameters. */ /* TODO(sergey): This operates on an original data, so no flush is needed. However, baking * usually should happen on an evaluated objects, so this seems to be deeper issue here. */ - BKE_animsys_evaluate_animdata(scene, (ID *)ob, ob->adt, f, ADT_RECALC_ANIM, false); + BKE_animsys_evaluate_animdata((ID *)ob, ob->adt, f, ADT_RECALC_ANIM, false); och->time[i] = omd->time; i++; @@ -2559,8 +2700,8 @@ static int laplaciandeform_bind_exec(bContext *C, wmOperator *op) lmd->flag |= MOD_LAPLACIANDEFORM_BIND; } - LaplacianDeformModifierData *lmd_eval = (LaplacianDeformModifierData *)modifier_get_evaluated( - depsgraph, ob, &lmd->modifier); + LaplacianDeformModifierData *lmd_eval = (LaplacianDeformModifierData *) + BKE_modifier_get_evaluated(depsgraph, ob, &lmd->modifier); lmd_eval->flag = lmd->flag; /* Force modifier to run, it will call binding routine @@ -2638,7 +2779,7 @@ static int surfacedeform_bind_exec(bContext *C, wmOperator *op) smd->flags |= MOD_SDEF_BIND; } - SurfaceDeformModifierData *smd_eval = (SurfaceDeformModifierData *)modifier_get_evaluated( + SurfaceDeformModifierData *smd_eval = (SurfaceDeformModifierData *)BKE_modifier_get_evaluated( depsgraph, ob, &smd->modifier); smd_eval->flags = smd->flags; diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c index fef046169a7..819b6c18a44 100644 --- a/source/blender/editors/object/object_ops.c +++ b/source/blender/editors/object/object_ops.c @@ -137,6 +137,8 @@ void ED_operatortypes_object(void) WM_operatortype_append(OBJECT_OT_multires_reshape); WM_operatortype_append(OBJECT_OT_multires_higher_levels_delete); WM_operatortype_append(OBJECT_OT_multires_base_apply); + WM_operatortype_append(OBJECT_OT_multires_unsubdivide); + WM_operatortype_append(OBJECT_OT_multires_rebuild_subdiv); WM_operatortype_append(OBJECT_OT_multires_external_save); WM_operatortype_append(OBJECT_OT_multires_external_pack); WM_operatortype_append(OBJECT_OT_skin_root_mark); diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index 759af18ed2b..bfceaef4644 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -557,7 +557,7 @@ static void object_remove_parent_deform_modifiers(Object *ob, const Object *par) /* free modifier if match */ if (free) { BLI_remlink(&ob->modifiers, md); - modifier_free(md); + BKE_modifier_free(md); } } } @@ -803,7 +803,7 @@ bool ED_object_parent_set(ReportList *reports, switch (partype) { case PAR_CURVE: /* curve deform */ - if (modifiers_isDeformedByCurve(ob) != par) { + if (BKE_modifiers_is_deformed_by_curve(ob) != par) { md = ED_object_modifier_add(reports, bmain, scene, ob, NULL, eModifierType_Curve); if (md) { ((CurveModifierData *)md)->object = par; @@ -814,7 +814,7 @@ bool ED_object_parent_set(ReportList *reports, } break; case PAR_LATTICE: /* lattice deform */ - if (modifiers_isDeformedByLattice(ob) != par) { + if (BKE_modifiers_is_deformed_by_lattice(ob) != par) { md = ED_object_modifier_add( reports, bmain, scene, ob, NULL, eModifierType_Lattice); if (md) { @@ -823,7 +823,7 @@ bool ED_object_parent_set(ReportList *reports, } break; default: /* armature deform */ - if (modifiers_isDeformedByArmature(ob) != par) { + if (BKE_modifiers_is_deformed_by_armature(ob) != par) { md = ED_object_modifier_add( reports, bmain, scene, ob, NULL, eModifierType_Armature); if (md) { diff --git a/source/blender/editors/object/object_remesh.c b/source/blender/editors/object/object_remesh.c index 9f9179440a8..22869748b22 100644 --- a/source/blender/editors/object/object_remesh.c +++ b/source/blender/editors/object/object_remesh.c @@ -114,7 +114,7 @@ static bool object_remesh_poll(bContext *C) return false; } - if (modifiers_usesMultires(ob)) { + if (BKE_modifiers_uses_multires(ob)) { CTX_wm_operator_poll_msg_set( C, "The remesher cannot run with a Multires modifier in the modifier stack"); return false; diff --git a/source/blender/editors/object/object_shader_fx.c b/source/blender/editors/object/object_shader_fx.c index cd71ab674ba..30fcdfc88bc 100644 --- a/source/blender/editors/object/object_shader_fx.c +++ b/source/blender/editors/object/object_shader_fx.c @@ -66,7 +66,7 @@ ShaderFxData *ED_object_shaderfx_add( ReportList *reports, Main *bmain, Scene *UNUSED(scene), Object *ob, const char *name, int type) { ShaderFxData *new_fx = NULL; - const ShaderFxTypeInfo *fxi = BKE_shaderfxType_getInfo(type); + const ShaderFxTypeInfo *fxi = BKE_shaderfx_get_info(type); if (ob->type != OB_GPENCIL) { BKE_reportf(reports, RPT_WARNING, "Effect cannot be added to object '%s'", ob->id.name + 2); @@ -74,7 +74,7 @@ ShaderFxData *ED_object_shaderfx_add( } if (fxi->flags & eShaderFxTypeFlag_Single) { - if (BKE_shaderfx_findByType(ob, type)) { + if (BKE_shaderfx_findby_type(ob, type)) { BKE_report(reports, RPT_WARNING, "Only one Effect of this type is allowed"); return NULL; } @@ -236,7 +236,7 @@ static const EnumPropertyItem *shaderfx_add_itemf(bContext *C, for (a = 0; rna_enum_object_shaderfx_type_items[a].identifier; a++) { fx_item = &rna_enum_object_shaderfx_type_items[a]; if (fx_item->identifier[0]) { - mti = BKE_shaderfxType_getInfo(fx_item->value); + mti = BKE_shaderfx_get_info(fx_item->value); if (mti->flags & eShaderFxTypeFlag_NoUserAdd) { continue; @@ -356,7 +356,7 @@ static ShaderFxData *edit_shaderfx_property_get(wmOperator *op, Object *ob, int ShaderFxData *fx; RNA_string_get(op->ptr, "shaderfx", shaderfx_name); - fx = BKE_shaderfx_findByName(ob, shaderfx_name); + fx = BKE_shaderfx_findby_name(ob, shaderfx_name); if (fx && type != 0 && fx->type != type) { fx = NULL; diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c index 62a8b46e904..132b530455e 100644 --- a/source/blender/editors/object/object_transform.c +++ b/source/blender/editors/object/object_transform.c @@ -1608,6 +1608,7 @@ struct XFormAxisItem { float rot_mat[3][3]; void *obtfm; float xform_dist; + bool is_z_flip; #ifdef USE_RELATIVE_ROTATION /* use when translating multiple */ @@ -1730,11 +1731,16 @@ static void object_apply_location(Object *ob, const float loc[3]) static bool object_orient_to_location(Object *ob, const float rot_orig[3][3], const float axis[3], - const float location[3]) + const float location[3], + const bool z_flip) { float delta[3]; sub_v3_v3v3(delta, ob->obmat[3], location); if (normalize_v3(delta) != 0.0f) { + if (z_flip) { + negate_v3(delta); + } + if (len_squared_v3v3(delta, axis) > FLT_EPSILON) { float delta_rot[3][3]; float final_rot[3][3]; @@ -1841,6 +1847,11 @@ static int object_transform_axis_target_invoke(bContext *C, wmOperator *op, cons for (int i = 0; i < xfd->object_data_len; i++, item++) { item->obtfm = BKE_object_tfm_backup(item->ob); BKE_object_rot_to_mat3(item->ob, item->rot_mat, true); + + /* Detect negative scale matrix. */ + float full_mat3[3][3]; + BKE_object_to_mat3(item->ob, full_mat3); + item->is_z_flip = dot_v3v3(item->rot_mat[2], full_mat3[2]) < 0.0f; } } @@ -1975,7 +1986,7 @@ static int object_transform_axis_target_modal(bContext *C, wmOperator *op, const } object_orient_to_location( - item->ob, item->rot_mat, item->rot_mat[2], location_world); + item->ob, item->rot_mat, item->rot_mat[2], location_world, item->is_z_flip); DEG_id_tag_update(&item->ob->id, ID_RECALC_TRANSFORM); WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, item->ob); @@ -1989,8 +2000,11 @@ static int object_transform_axis_target_modal(bContext *C, wmOperator *op, const else { struct XFormAxisItem *item = xfd->object_data; for (int i = 0; i < xfd->object_data_len; i++, item++) { - if (object_orient_to_location( - item->ob, item->rot_mat, item->rot_mat[2], location_world)) { + if (object_orient_to_location(item->ob, + item->rot_mat, + item->rot_mat[2], + location_world, + item->is_z_flip)) { DEG_id_tag_update(&item->ob->id, ID_RECALC_TRANSFORM); WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, item->ob); } diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c index 3ec55d42849..fb79cfb910e 100644 --- a/source/blender/editors/object/object_vgroup.c +++ b/source/blender/editors/object/object_vgroup.c @@ -3945,7 +3945,7 @@ static int vgroup_sort_name(const void *def_a_ptr, const void *def_b_ptr) static void vgroup_sort_bone_hierarchy(Object *ob, ListBase *bonebase) { if (bonebase == NULL) { - Object *armobj = modifiers_isDeformedByArmature(ob); + Object *armobj = BKE_modifiers_is_deformed_by_armature(ob); if (armobj != NULL) { bArmature *armature = armobj->data; bonebase = &armature->bonebase; diff --git a/source/blender/editors/physics/dynamicpaint_ops.c b/source/blender/editors/physics/dynamicpaint_ops.c index 37845e8d74e..6922a03b12f 100644 --- a/source/blender/editors/physics/dynamicpaint_ops.c +++ b/source/blender/editors/physics/dynamicpaint_ops.c @@ -72,7 +72,7 @@ static int surface_slot_add_exec(bContext *C, wmOperator *UNUSED(op)) DynamicPaintSurface *surface; /* Make sure we're dealing with a canvas */ - pmd = (DynamicPaintModifierData *)modifiers_findByType(cObject, eModifierType_DynamicPaint); + pmd = (DynamicPaintModifierData *)BKE_modifiers_findby_type(cObject, eModifierType_DynamicPaint); if (!pmd || !pmd->canvas) { return OPERATOR_CANCELLED; } @@ -117,7 +117,7 @@ static int surface_slot_remove_exec(bContext *C, wmOperator *UNUSED(op)) int id = 0; /* Make sure we're dealing with a canvas */ - pmd = (DynamicPaintModifierData *)modifiers_findByType(obj_ctx, eModifierType_DynamicPaint); + pmd = (DynamicPaintModifierData *)BKE_modifiers_findby_type(obj_ctx, eModifierType_DynamicPaint); if (!pmd || !pmd->canvas) { return OPERATOR_CANCELLED; } @@ -162,7 +162,7 @@ static int type_toggle_exec(bContext *C, wmOperator *op) Object *cObject = ED_object_context(C); Scene *scene = CTX_data_scene(C); - DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)modifiers_findByType( + DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)BKE_modifiers_findby_type( cObject, eModifierType_DynamicPaint); int type = RNA_enum_get(op->ptr, "type"); @@ -222,7 +222,7 @@ static int output_toggle_exec(bContext *C, wmOperator *op) { Object *ob = ED_object_context(C); DynamicPaintSurface *surface; - DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)modifiers_findByType( + DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)BKE_modifiers_findby_type( ob, eModifierType_DynamicPaint); int output = RNA_enum_get(op->ptr, "output"); /* currently only 1/0 */ @@ -483,7 +483,7 @@ static int dynamicpaint_bake_exec(struct bContext *C, struct wmOperator *op) /* * Get modifier data */ - DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)modifiers_findByType( + DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)BKE_modifiers_findby_type( object_eval, eModifierType_DynamicPaint); if (pmd == NULL) { BKE_report(op->reports, RPT_ERROR, "Bake failed: no Dynamic Paint modifier found"); diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c index c60f3c37640..306adb36c52 100644 --- a/source/blender/editors/physics/particle_edit.c +++ b/source/blender/editors/physics/particle_edit.c @@ -849,7 +849,6 @@ static void foreach_mouse_hit_key(PEData *data, ForHitKeyMatFunc func, int selec TaskParallelSettings settings; BLI_parallel_range_settings_defaults(&settings); - settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC; BLI_task_parallel_range(0, edit->totpoint, &iter_data, foreach_mouse_hit_key_iter, &settings); } @@ -1229,7 +1228,6 @@ static void pe_deflect_emitter(Scene *scene, Object *ob, PTCacheEdit *edit) TaskParallelSettings settings; BLI_parallel_range_settings_defaults(&settings); - settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC; BLI_task_parallel_range(0, edit->totpoint, &iter_data, deflect_emitter_iter, &settings); } @@ -1278,7 +1276,6 @@ static void PE_apply_lengths(Scene *scene, PTCacheEdit *edit) TaskParallelSettings settings; BLI_parallel_range_settings_defaults(&settings); - settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC; BLI_task_parallel_range(0, edit->totpoint, &iter_data, apply_lengths_iter, &settings); } @@ -1353,7 +1350,6 @@ static void pe_iterate_lengths(Scene *scene, PTCacheEdit *edit) TaskParallelSettings settings; BLI_parallel_range_settings_defaults(&settings); - settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC; BLI_task_parallel_range(0, edit->totpoint, &iter_data, iterate_lengths_iter, &settings); } @@ -2256,7 +2252,7 @@ bool PE_circle_select(bContext *C, const int sel_op, const int mval[2], float ra /************************ lasso select operator ************************/ -int PE_lasso_select(bContext *C, const int mcords[][2], const short moves, const int sel_op) +int PE_lasso_select(bContext *C, const int mcoords[][2], const int mcoords_len, const int sel_op) { Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); Scene *scene = CTX_data_scene(C); @@ -2300,7 +2296,8 @@ int PE_lasso_select(bContext *C, const int mcords[][2], const short moves, const const bool is_inside = ((ED_view3d_project_int_global(region, co, screen_co, V3D_PROJ_TEST_CLIP_WIN) == V3D_PROJ_RET_OK) && - BLI_lasso_is_point_inside(mcords, moves, screen_co[0], screen_co[1], IS_CLIPPED) && + BLI_lasso_is_point_inside( + mcoords, mcoords_len, screen_co[0], screen_co[1], IS_CLIPPED) && key_test_depth(&data, co, screen_co)); const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside); if (sel_op_result != -1) { @@ -2319,7 +2316,8 @@ int PE_lasso_select(bContext *C, const int mcords[][2], const short moves, const const bool is_inside = ((ED_view3d_project_int_global(region, co, screen_co, V3D_PROJ_TEST_CLIP_WIN) == V3D_PROJ_RET_OK) && - BLI_lasso_is_point_inside(mcords, moves, screen_co[0], screen_co[1], IS_CLIPPED) && + BLI_lasso_is_point_inside( + mcoords, mcoords_len, screen_co[0], screen_co[1], IS_CLIPPED) && key_test_depth(&data, co, screen_co)); const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside); if (sel_op_result != -1) { @@ -2833,8 +2831,8 @@ static void remove_tagged_keys(Depsgraph *depsgraph, Object *ob, ParticleSystem if (pe_x_mirror(ob)) { /* mirror key tags */ ParticleSystemModifierData *psmd = psys_get_modifier(ob, psys); - ParticleSystemModifierData *psmd_eval = (ParticleSystemModifierData *)modifier_get_evaluated( - depsgraph, ob, &psmd->modifier); + ParticleSystemModifierData *psmd_eval = (ParticleSystemModifierData *) + BKE_modifier_get_evaluated(depsgraph, ob, &psmd->modifier); LOOP_POINTS { LOOP_TAGGED_KEYS { @@ -4084,7 +4082,6 @@ typedef struct BrushAddCountIterData { short size; float imat[4][4]; ParticleData *add_pars; - int num_added; } BrushAddCountIterData; typedef struct BrushAddCountIterTLSData { @@ -4113,7 +4110,7 @@ static void brush_add_count_iter(void *__restrict iter_data_v, dmy = size; if (tls->rng == NULL) { tls->rng = BLI_rng_new_srandom(psys->seed + data->mval[0] + data->mval[1] + - tls_v->thread_id); + BLI_task_parallel_thread_id(tls_v)); } /* rejection sampling to get points in circle */ while (dmx * dmx + dmy * dmy > size2) { @@ -4176,12 +4173,19 @@ static void brush_add_count_iter(void *__restrict iter_data_v, } } -static void brush_add_count_iter_finalize(void *__restrict userdata_v, - void *__restrict userdata_chunk_v) +static void brush_add_count_iter_reduce(const void *__restrict UNUSED(userdata), + void *__restrict join_v, + void *__restrict chunk_v) +{ + BrushAddCountIterTLSData *join = (BrushAddCountIterTLSData *)join_v; + BrushAddCountIterTLSData *tls = (BrushAddCountIterTLSData *)chunk_v; + join->num_added += tls->num_added; +} + +static void brush_add_count_iter_free(const void *__restrict UNUSED(userdata_v), + void *__restrict chunk_v) { - BrushAddCountIterData *iter_data = (BrushAddCountIterData *)userdata_v; - BrushAddCountIterTLSData *tls = (BrushAddCountIterTLSData *)userdata_chunk_v; - iter_data->num_added += tls->num_added; + BrushAddCountIterTLSData *tls = (BrushAddCountIterTLSData *)chunk_v; if (tls->rng != NULL) { BLI_rng_free(tls->rng); } @@ -4245,23 +4249,22 @@ static int brush_add(const bContext *C, PEData *data, short number) iter_data.number = number; iter_data.size = size; iter_data.add_pars = add_pars; - iter_data.num_added = 0; copy_m4_m4(iter_data.imat, imat); BrushAddCountIterTLSData tls = {NULL}; TaskParallelSettings settings; BLI_parallel_range_settings_defaults(&settings); - settings.scheduling_mode = TASK_SCHEDULING_DYNAMIC; settings.userdata_chunk = &tls; settings.userdata_chunk_size = sizeof(BrushAddCountIterTLSData); - settings.func_finalize = brush_add_count_iter_finalize; + settings.func_reduce = brush_add_count_iter_reduce; + settings.func_free = brush_add_count_iter_free; BLI_task_parallel_range(0, number, &iter_data, brush_add_count_iter, &settings); /* Convert add_parse to a dense array, where all new particles are in the * beginning of the array. */ - n = iter_data.num_added; + n = tls.num_added; for (int current_iter = 0, new_index = 0; current_iter < number; current_iter++) { if (add_pars[current_iter].num == DMCACHE_NOTFOUND) { continue; @@ -5124,7 +5127,8 @@ void PE_create_particle_edit( int totpoint; if (psmd != NULL) { - psmd_eval = (ParticleSystemModifierData *)modifiers_findByName(ob_eval, psmd->modifier.name); + psmd_eval = (ParticleSystemModifierData *)BKE_modifiers_findby_name(ob_eval, + psmd->modifier.name); } /* no psmd->dm happens in case particle system modifier is not enabled */ @@ -5248,8 +5252,8 @@ static bool particle_edit_toggle_poll(bContext *C) return 0; } - return (ob->particlesystem.first || modifiers_findByType(ob, eModifierType_Cloth) || - modifiers_findByType(ob, eModifierType_Softbody)); + return (ob->particlesystem.first || BKE_modifiers_findby_type(ob, eModifierType_Cloth) || + BKE_modifiers_findby_type(ob, eModifierType_Softbody)); } static void free_all_psys_edit(Object *object) @@ -5294,7 +5298,7 @@ static int particle_edit_toggle_exec(bContext *C, wmOperator *op) * with possible changes applied when object was outside of the * edit mode. */ Object *object_eval = DEG_get_evaluated_object(depsgraph, ob); - edit->psmd_eval = (ParticleSystemModifierData *)modifiers_findByName( + edit->psmd_eval = (ParticleSystemModifierData *)BKE_modifiers_findby_name( object_eval, edit->psmd->modifier.name); recalc_emitter_field(depsgraph, ob, edit->psys); } diff --git a/source/blender/editors/physics/particle_object.c b/source/blender/editors/physics/particle_object.c index f37a20bf43e..e75169a476b 100644 --- a/source/blender/editors/physics/particle_object.c +++ b/source/blender/editors/physics/particle_object.c @@ -1064,7 +1064,7 @@ static void remove_particle_systems_from_object(Object *ob_to) eModifierType_DynamicPaint, eModifierType_Fluid)) { BLI_remlink(&ob_to->modifiers, md); - modifier_free(md); + BKE_modifier_free(md); } } @@ -1138,13 +1138,13 @@ static bool copy_particle_systems_to_object(const bContext *C, psys_unique_name(ob_to, psys, psys->name); /* add a particle system modifier for each system */ - md = modifier_new(eModifierType_ParticleSystem); + md = BKE_modifier_new(eModifierType_ParticleSystem); psmd = (ParticleSystemModifierData *)md; /* push on top of the stack, no use trying to reproduce old stack order */ BLI_addtail(&ob_to->modifiers, md); BLI_snprintf(md->name, sizeof(md->name), "ParticleSystem %i", i); - modifier_unique_name(&ob_to->modifiers, (ModifierData *)psmd); + BKE_modifier_unique_name(&ob_to->modifiers, (ModifierData *)psmd); psmd->psys = psys; diff --git a/source/blender/editors/physics/physics_fluid.c b/source/blender/editors/physics/physics_fluid.c index d281320eb5a..8524870c15e 100644 --- a/source/blender/editors/physics/physics_fluid.c +++ b/source/blender/editors/physics/physics_fluid.c @@ -157,7 +157,7 @@ static bool fluid_initjob( FluidDomainSettings *mds; Object *ob = ED_object_active_context(C); - mmd = (FluidModifierData *)modifiers_findByType(ob, eModifierType_Fluid); + mmd = (FluidModifierData *)BKE_modifiers_findby_type(ob, eModifierType_Fluid); if (!mmd) { BLI_strncpy(error_msg, N_("Bake failed: no Fluid modifier found"), error_size); return false; @@ -186,13 +186,13 @@ static bool fluid_validatepaths(FluidJob *job, ReportList *reports) temp_dir[0] = '\0'; bool is_relative = false; - const char *relbase = modifier_path_relbase(job->bmain, job->ob); + const char *relbase = BKE_modifier_path_relbase(job->bmain, job->ob); /* We do not accept empty paths, they can end in random places silently, see T51176. */ if (mds->cache_directory[0] == '\0') { char cache_name[64]; BKE_fluid_cache_new_name_for_current_session(sizeof(cache_name), cache_name); - modifier_path_init(mds->cache_directory, sizeof(mds->cache_directory), cache_name); + BKE_modifier_path_init(mds->cache_directory, sizeof(mds->cache_directory), cache_name); BKE_reportf(reports, RPT_WARNING, "Fluid: Empty cache path, reset to default '%s'", @@ -210,7 +210,7 @@ static bool fluid_validatepaths(FluidJob *job, ReportList *reports) if (!dir_exists) { char cache_name[64]; BKE_fluid_cache_new_name_for_current_session(sizeof(cache_name), cache_name); - modifier_path_init(mds->cache_directory, sizeof(mds->cache_directory), cache_name); + BKE_modifier_path_init(mds->cache_directory, sizeof(mds->cache_directory), cache_name); BKE_reportf(reports, RPT_ERROR, @@ -362,7 +362,7 @@ static void fluid_bake_endjob(void *customdata) RPT_INFO, "Fluid: %s complete! (%.2f)", job->name, PIL_check_seconds_timer() - job->start); } else { - if (mds->error != NULL && mds->error[0] != '\0') { + if (mds->error[0] != '\0') { WM_reportf(RPT_ERROR, "Fluid: %s failed: %s", job->name, mds->error); } else { /* User canceled the bake */ @@ -377,7 +377,7 @@ static void fluid_bake_startjob(void *customdata, short *stop, short *do_update, FluidDomainSettings *mds = job->mmd->domain; char temp_dir[FILE_MAX]; - const char *relbase = modifier_path_relbase_from_global(job->ob); + const char *relbase = BKE_modifier_path_relbase_from_global(job->ob); job->stop = stop; job->do_update = do_update; @@ -474,7 +474,7 @@ static void fluid_free_endjob(void *customdata) RPT_INFO, "Fluid: %s complete! (%.2f)", job->name, PIL_check_seconds_timer() - job->start); } else { - if (mds->error != NULL && mds->error[0] != '\0') { + if (mds->error[0] != '\0') { WM_reportf(RPT_ERROR, "Fluid: %s failed: %s", job->name, mds->error); } else { /* User canceled the free job */ @@ -623,7 +623,7 @@ static int fluid_free_exec(struct bContext *C, struct wmOperator *op) /* * Get modifier data */ - mmd = (FluidModifierData *)modifiers_findByType(ob, eModifierType_Fluid); + mmd = (FluidModifierData *)BKE_modifiers_findby_type(ob, eModifierType_Fluid); if (!mmd) { BKE_report(op->reports, RPT_ERROR, "Bake free failed: no Fluid modifier found"); return OPERATOR_CANCELLED; @@ -685,7 +685,7 @@ static int fluid_pause_exec(struct bContext *C, struct wmOperator *op) /* * Get modifier data */ - mmd = (FluidModifierData *)modifiers_findByType(ob, eModifierType_Fluid); + mmd = (FluidModifierData *)BKE_modifiers_findby_type(ob, eModifierType_Fluid); if (!mmd) { BKE_report(op->reports, RPT_ERROR, "Bake free failed: no Fluid modifier found"); return OPERATOR_CANCELLED; diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c index 17049fdb28b..46827940b57 100644 --- a/source/blender/editors/render/render_internal.c +++ b/source/blender/editors/render/render_internal.c @@ -349,7 +349,6 @@ static int screen_render_exec(bContext *C, wmOperator *op) RE_SetReports(re, op->reports); - BLI_threaded_malloc_begin(); if (is_animation) { RE_RenderAnim(re, mainp, @@ -363,7 +362,6 @@ static int screen_render_exec(bContext *C, wmOperator *op) else { RE_RenderFrame(re, mainp, scene, single_layer, camera_override, scene->r.cfra, is_write_still); } - BLI_threaded_malloc_end(); RE_SetReports(re, NULL); @@ -391,16 +389,14 @@ static void make_renderinfo_string(const RenderStats *rs, char *str) { char info_time_str[32]; // used to be extern to header_info.c - uintptr_t mem_in_use, mmap_in_use, peak_memory; - float megs_used_memory, mmap_used_memory, megs_peak_memory; + uintptr_t mem_in_use, peak_memory; + float megs_used_memory, megs_peak_memory; char *spos = str; mem_in_use = MEM_get_memory_in_use(); - mmap_in_use = MEM_get_mapped_memory_in_use(); peak_memory = MEM_get_peak_memory(); - megs_used_memory = (mem_in_use - mmap_in_use) / (1024.0 * 1024.0); - mmap_used_memory = (mmap_in_use) / (1024.0 * 1024.0); + megs_used_memory = (mem_in_use) / (1024.0 * 1024.0); megs_peak_memory = (peak_memory) / (1024.0 * 1024.0); /* local view */ @@ -462,11 +458,7 @@ static void make_renderinfo_string(const RenderStats *rs, } if (rs->mem_peak == 0.0f) { - spos += sprintf(spos, - TIP_("| Mem:%.2fM (%.2fM, Peak %.2fM) "), - megs_used_memory, - mmap_used_memory, - megs_peak_memory); + spos += sprintf(spos, TIP_("| Mem:%.2fM (Peak %.2fM) "), megs_used_memory, megs_peak_memory); } else { spos += sprintf(spos, TIP_("| Mem:%.2fM, Peak: %.2fM "), rs->mem_used, rs->mem_peak); diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.c index 87ba5ca630f..2861e851282 100644 --- a/source/blender/editors/render/render_opengl.c +++ b/source/blender/editors/render/render_opengl.c @@ -144,7 +144,6 @@ typedef struct OGLRender { wmTimer *timer; /* use to check if running modal or not (invoke'd or exec'd)*/ void **movie_ctx_arr; - TaskScheduler *task_scheduler; TaskPool *task_pool; bool pool_ok; bool is_animation; @@ -630,6 +629,7 @@ static int gather_frames_to_render_for_id(LibraryIDLinkCallbackData *cb_data) case ID_HA: /* Hair */ case ID_PT: /* PointCloud */ case ID_VO: /* Volume */ + case ID_SIM: /* Simulation */ break; /* Blacklist: */ @@ -855,22 +855,16 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op) gather_frames_to_render(C, oglrender); } - TaskScheduler *task_scheduler = BLI_task_scheduler_get(); if (BKE_imtype_is_movie(scene->r.im_format.imtype)) { - task_scheduler = BLI_task_scheduler_create(1); - oglrender->task_scheduler = task_scheduler; - oglrender->task_pool = BLI_task_pool_create_background( - task_scheduler, oglrender, TASK_PRIORITY_LOW); + oglrender->task_pool = BLI_task_pool_create_background_serial(oglrender, TASK_PRIORITY_LOW); } else { - oglrender->task_scheduler = NULL; - oglrender->task_pool = BLI_task_pool_create(task_scheduler, oglrender, TASK_PRIORITY_LOW); + oglrender->task_pool = BLI_task_pool_create(oglrender, TASK_PRIORITY_LOW); } oglrender->pool_ok = true; BLI_spin_init(&oglrender->reports_lock); } else { - oglrender->task_scheduler = NULL; oglrender->task_pool = NULL; } oglrender->num_scheduled_frames = 0; @@ -909,10 +903,6 @@ static void screen_opengl_render_end(bContext *C, OGLRender *oglrender) } BLI_task_pool_work_and_wait(oglrender->task_pool); BLI_task_pool_free(oglrender->task_pool); - /* Depending on various things we might or might not use global scheduler. */ - if (oglrender->task_scheduler != NULL) { - BLI_task_scheduler_free(oglrender->task_scheduler); - } BLI_spin_end(&oglrender->reports_lock); } BLI_mutex_end(&oglrender->task_mutex); @@ -1032,9 +1022,9 @@ typedef struct WriteTaskData { Scene tmp_scene; } WriteTaskData; -static void write_result_func(TaskPool *__restrict pool, void *task_data_v, int UNUSED(thread_id)) +static void write_result_func(TaskPool *__restrict pool, void *task_data_v) { - OGLRender *oglrender = (OGLRender *)BLI_task_pool_userdata(pool); + OGLRender *oglrender = (OGLRender *)BLI_task_pool_user_data(pool); WriteTaskData *task_data = (WriteTaskData *)task_data_v; Scene *scene = &task_data->tmp_scene; RenderResult *rr = task_data->rr; diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c index 96aad89827f..48b54ddcea3 100644 --- a/source/blender/editors/screen/area.c +++ b/source/blender/editors/screen/area.c @@ -2519,6 +2519,7 @@ void ED_region_panels_layout_ex(const bContext *C, int margin_x = 0; const bool region_layout_based = region->flag & RGN_FLAG_DYNAMIC_SIZE; const bool is_context_new = (contextnr != -1) ? UI_view2d_tab_set(v2d, contextnr) : false; + bool update_tot_size = true; /* before setting the view */ if (vertical) { @@ -2536,7 +2537,6 @@ void ED_region_panels_layout_ex(const bContext *C, v2d->scroll |= (V2D_SCROLL_BOTTOM); v2d->scroll &= ~(V2D_SCROLL_RIGHT); } - const int scroll = v2d->scroll; /* collect categories */ if (use_category_tabs) { @@ -2588,6 +2588,11 @@ void ED_region_panels_layout_ex(const bContext *C, } } + if (panel && UI_panel_is_dragging(panel)) { + /* Prevent View2d.tot rectangle size changes while dragging panels. */ + update_tot_size = false; + } + ed_panel_draw(C, area, region, ®ion->panels, pt, panel, w, em, vertical); } @@ -2643,17 +2648,9 @@ void ED_region_panels_layout_ex(const bContext *C, y = -y; } - /* this also changes the 'cur' */ - UI_view2d_totRect_set(v2d, x, y); - - if (scroll != v2d->scroll) { - /* Note: this code scales fine, but because of rounding differences, positions of elements - * flip +1 or -1 pixel compared to redoing the entire layout again. - * Leaving in commented code for future tests */ -#if 0 - UI_panels_scale(region, BLI_rctf_size_x(&v2d->cur)); - break; -#endif + if (update_tot_size) { + /* this also changes the 'cur' */ + UI_view2d_totRect_set(v2d, x, y); } if (use_category_tabs) { diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index 90813c9351c..f2bfcb7a395 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -3873,7 +3873,6 @@ static int region_quadview_exec(bContext *C, wmOperator *op) rv3d->viewlock_quad = RV3D_VIEWLOCK_INIT; rv3d->viewlock = 0; - rv3d->rflag &= ~RV3D_CLIPPING; /* FIXME: This fixes missing update to workbench TAA. (see T76216) * However, it would be nice if the tagging should be done in a more conventional way. */ @@ -4396,7 +4395,7 @@ static int screen_animation_step(bContext *C, wmOperator *UNUSED(op), const wmEv wmWindow *window; ScrArea *area; int sync; - float time; + double time; /* sync, don't sync, or follow scene setting */ if (sad->flag & ANIMPLAY_FLAG_SYNC) { @@ -4419,7 +4418,7 @@ static int screen_animation_step(bContext *C, wmOperator *UNUSED(op), const wmEv } else if ((scene->audio.flag & AUDIO_SYNC) && (sad->flag & ANIMPLAY_FLAG_REVERSE) == false && isfinite(time = BKE_sound_sync_scene(scene_eval))) { - double newfra = (double)time * FPS; + double newfra = time * FPS; /* give some space here to avoid jumps */ if (newfra + 0.5 > scene->r.cfra && newfra - 0.5 < scene->r.cfra) { @@ -4867,8 +4866,11 @@ static void SCREEN_OT_back_to_previous(struct wmOperatorType *ot) /** \name Show User Preferences Operator * \{ */ -static int userpref_show_invoke(bContext *C, wmOperator *op, const wmEvent *event) +static int userpref_show_exec(bContext *C, wmOperator *op) { + wmWindow *win_cur = CTX_wm_window(C); + /* Use eventstate, not event from _invoke, so this can be called through exec(). */ + const wmEvent *event = win_cur->eventstate; int sizex = (500 + UI_NAVIGATION_REGION_WIDTH) * UI_DPI_FAC; int sizey = 520 * UI_DPI_FAC; @@ -4905,7 +4907,7 @@ static void SCREEN_OT_userpref_show(struct wmOperatorType *ot) ot->idname = "SCREEN_OT_userpref_show"; /* api callbacks */ - ot->invoke = userpref_show_invoke; + ot->exec = userpref_show_exec; ot->poll = ED_operator_screenactive; } @@ -4915,8 +4917,11 @@ static void SCREEN_OT_userpref_show(struct wmOperatorType *ot) /** \name Show Drivers Editor Operator * \{ */ -static int drivers_editor_show_invoke(bContext *C, wmOperator *op, const wmEvent *event) +static int drivers_editor_show_exec(bContext *C, wmOperator *op) { + wmWindow *win_cur = CTX_wm_window(C); + /* Use eventstate, not event from _invoke, so this can be called through exec(). */ + const wmEvent *event = win_cur->eventstate; PointerRNA ptr = {NULL}; PropertyRNA *prop = NULL; int index = -1; @@ -4980,7 +4985,7 @@ static void SCREEN_OT_drivers_editor_show(struct wmOperatorType *ot) ot->idname = "SCREEN_OT_drivers_editor_show"; /* api callbacks */ - ot->invoke = drivers_editor_show_invoke; + ot->exec = drivers_editor_show_exec; ot->poll = ED_operator_screenactive; } @@ -4990,8 +4995,11 @@ static void SCREEN_OT_drivers_editor_show(struct wmOperatorType *ot) /** \name Show Info Log Operator * \{ */ -static int info_log_show_invoke(bContext *C, wmOperator *op, const wmEvent *event) +static int info_log_show_exec(bContext *C, wmOperator *op) { + wmWindow *win_cur = CTX_wm_window(C); + /* Use eventstate, not event from _invoke, so this can be called through exec(). */ + const wmEvent *event = win_cur->eventstate; int sizex = 900 * UI_DPI_FAC; int sizey = 580 * UI_DPI_FAC; int shift_y = 480; @@ -5021,7 +5029,7 @@ static void SCREEN_OT_info_log_show(struct wmOperatorType *ot) ot->idname = "SCREEN_OT_info_log_show"; /* api callbacks */ - ot->invoke = info_log_show_invoke; + ot->exec = info_log_show_exec; ot->poll = ED_operator_screenactive; } diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c index 536453ad085..191a064a95c 100644 --- a/source/blender/editors/sculpt_paint/paint_cursor.c +++ b/source/blender/editors/sculpt_paint/paint_cursor.c @@ -10,7 +10,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, + * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * The Original Code is Copyright (C) 2009 by Nicholas Bishop @@ -171,6 +171,8 @@ static void load_tex_task_cb_ex(void *__restrict userdata, bool convert_to_linear = false; struct ColorSpace *colorspace = NULL; + const int thread_id = BLI_task_parallel_thread_id(tls); + if (mtex->tex && mtex->tex->type == TEX_IMAGE && mtex->tex->ima) { ImBuf *tex_ibuf = BKE_image_pool_acquire_ibuf(mtex->tex->ima, &mtex->tex->iuser, pool); /* For consistency, sampling always returns color in linear space. */ @@ -214,8 +216,7 @@ static void load_tex_task_cb_ex(void *__restrict userdata, if (col) { float rgba[4]; - paint_get_tex_pixel_col( - mtex, x, y, rgba, pool, tls->thread_id, convert_to_linear, colorspace); + paint_get_tex_pixel_col(mtex, x, y, rgba, pool, thread_id, convert_to_linear, colorspace); buffer[index * 4] = rgba[0] * 255; buffer[index * 4 + 1] = rgba[1] * 255; @@ -223,7 +224,7 @@ static void load_tex_task_cb_ex(void *__restrict userdata, buffer[index * 4 + 3] = rgba[3] * 255; } else { - float avg = paint_get_tex_pixel(mtex, x, y, pool, tls->thread_id); + float avg = paint_get_tex_pixel(mtex, x, y, pool, thread_id); avg += br->texture_sample_bias; diff --git a/source/blender/editors/sculpt_paint/paint_hide.c b/source/blender/editors/sculpt_paint/paint_hide.c index 69ca86efa9d..e9dcc4a356a 100644 --- a/source/blender/editors/sculpt_paint/paint_hide.c +++ b/source/blender/editors/sculpt_paint/paint_hide.c @@ -10,7 +10,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, + * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * The Original Code is Copyright (C) 2010 by Nicholas Bishop diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c index af84cb2d15b..5e3204b6d5a 100644 --- a/source/blender/editors/sculpt_paint/paint_image_proj.c +++ b/source/blender/editors/sculpt_paint/paint_image_proj.c @@ -5168,9 +5168,7 @@ static void copy_original_alpha_channel(ProjPixel *pixel, bool is_floatbuf) } /* Run this for single and multi-threaded painting. */ -static void do_projectpaint_thread(TaskPool *__restrict UNUSED(pool), - void *ph_v, - int UNUSED(threadid)) +static void do_projectpaint_thread(TaskPool *__restrict UNUSED(pool), void *ph_v) { /* First unpack args from the struct */ ProjPaintState *ps = ((ProjectHandle *)ph_v)->ps; @@ -5605,7 +5603,6 @@ static bool project_paint_op(void *state, const float lastpos[2], const float po bool touch_any = false; ProjectHandle handles[BLENDER_MAX_THREADS]; - TaskScheduler *scheduler = NULL; TaskPool *task_pool = NULL; int a, i; @@ -5616,8 +5613,7 @@ static bool project_paint_op(void *state, const float lastpos[2], const float po } if (ps->thread_tot > 1) { - scheduler = BLI_task_scheduler_get(); - task_pool = BLI_task_pool_create_suspended(scheduler, NULL, TASK_PRIORITY_HIGH); + task_pool = BLI_task_pool_create_suspended(NULL, TASK_PRIORITY_HIGH); } image_pool = BKE_image_pool_new(); @@ -5661,7 +5657,7 @@ static bool project_paint_op(void *state, const float lastpos[2], const float po BLI_task_pool_free(task_pool); } else { - do_projectpaint_thread(NULL, &handles[0], 0); + do_projectpaint_thread(NULL, &handles[0]); } BKE_image_pool_free(image_pool); diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c index fb8cc3a639b..c32e496f4f5 100644 --- a/source/blender/editors/sculpt_paint/paint_mask.c +++ b/source/blender/editors/sculpt_paint/paint_mask.c @@ -10,7 +10,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, + * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * The Original Code is Copyright (C) 2012 by Nicholas Bishop @@ -168,9 +168,9 @@ static int mask_flood_fill_exec(bContext *C, wmOperator *op) .value = value, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BKE_pbvh_parallel_range(0, totnode, &data, mask_flood_fill_task_cb, &settings); + BLI_task_parallel_range(0, totnode, &data, mask_flood_fill_task_cb, &settings); if (multires) { multires_mark_as_modified(depsgraph, ob, MULTIRES_COORDS_MODIFIED); @@ -343,9 +343,9 @@ bool ED_sculpt_mask_box_select(struct bContext *C, ViewContext *vc, const rcti * .clip_planes_final = clip_planes_final, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BKE_pbvh_parallel_range(0, totnode, &data, mask_box_select_task_cb, &settings); + BLI_task_parallel_range(0, totnode, &data, mask_box_select_task_cb, &settings); if (nodes) { MEM_freeN(nodes); @@ -456,10 +456,10 @@ static void mask_gesture_lasso_task_cb(void *__restrict userdata, static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op) { - int mcords_tot; - const int(*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot); + int mcoords_len; + const int(*mcoords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcoords_len); - if (mcords) { + if (mcoords) { Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); float clip_planes[4][4], clip_planes_final[4][4]; BoundBox bb; @@ -485,7 +485,7 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op) ob = vc.obact; ED_view3d_ob_project_mat_get(vc.rv3d, ob, data.projviewobjmat); - BLI_lasso_boundbox(&data.rect, mcords, mcords_tot); + BLI_lasso_boundbox(&data.rect, mcoords, mcoords_len); data.width = data.rect.xmax - data.rect.xmin; data.px = BLI_BITMAP_NEW(data.width * (data.rect.ymax - data.rect.ymin), __func__); @@ -493,8 +493,8 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op) data.rect.ymin, data.rect.xmax, data.rect.ymax, - mcords, - mcords_tot, + mcoords, + mcoords_len, mask_lasso_px_cb, &data); @@ -532,9 +532,9 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op) data.task_data.mode = mode; data.task_data.value = value; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BKE_pbvh_parallel_range(0, totnode, &data, mask_gesture_lasso_task_cb, &settings); + BLI_task_parallel_range(0, totnode, &data, mask_gesture_lasso_task_cb, &settings); if (nodes) { MEM_freeN(nodes); @@ -551,7 +551,7 @@ static int paint_mask_gesture_lasso_exec(bContext *C, wmOperator *op) SCULPT_undo_push_end(); ED_region_tag_redraw(vc.region); - MEM_freeN((void *)mcords); + MEM_freeN((void *)mcoords); MEM_freeN(data.px); WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c index 7887aaaf658..458c24e5194 100644 --- a/source/blender/editors/sculpt_paint/paint_stroke.c +++ b/source/blender/editors/sculpt_paint/paint_stroke.c @@ -10,7 +10,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, + * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * The Original Code is Copyright (C) 2009 by Nicholas Bishop diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c index 60b4a2f8e0c..c84a3b9cbfc 100644 --- a/source/blender/editors/sculpt_paint/paint_utils.c +++ b/source/blender/editors/sculpt_paint/paint_utils.c @@ -166,10 +166,11 @@ float paint_calc_object_space_radius(ViewContext *vc, const float center[3], flo float paint_get_tex_pixel(const MTex *mtex, float u, float v, struct ImagePool *pool, int thread) { - float intensity, rgba[4]; + float intensity; + float rgba_dummy[4]; float co[3] = {u, v, 0.0f}; - externtex(mtex, co, &intensity, rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false, false); + RE_texture_evaluate(mtex, co, thread, pool, false, false, &intensity, rgba_dummy); return intensity; } @@ -184,11 +185,10 @@ void paint_get_tex_pixel_col(const MTex *mtex, struct ColorSpace *colorspace) { float co[3] = {u, v, 0.0f}; - int hasrgb; float intensity; - hasrgb = externtex( - mtex, co, &intensity, rgba, rgba + 1, rgba + 2, rgba + 3, thread, pool, false, false); + const bool hasrgb = RE_texture_evaluate(mtex, co, thread, pool, false, false, &intensity, rgba); + if (!hasrgb) { rgba[0] = intensity; rgba[1] = intensity; diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c index 296b2bae510..a18a0145faa 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex.c +++ b/source/blender/editors/sculpt_paint/paint_vertex.c @@ -1398,7 +1398,7 @@ static int wpaint_mode_toggle_exec(bContext *C, wmOperator *op) */ { VirtualModifierData virtualModifierData; - ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData); + ModifierData *md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData); if (md != NULL) { /* Can be NULL. */ View3D *v3d = CTX_wm_view3d(C); @@ -2179,9 +2179,9 @@ static void calculate_average_weight(SculptThreadedTaskData *data, struct WPaintAverageAccum *accum = MEM_mallocN(sizeof(*accum) * totnode, __func__); data->custom_data = accum; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (data->sd->flags & SCULPT_USE_OPENMP), totnode); - BKE_pbvh_parallel_range(0, totnode, data, do_wpaint_brush_calc_average_weight_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, data, do_wpaint_brush_calc_average_weight_cb_ex, &settings); uint accum_len = 0; double accum_weight = 0.0; @@ -2227,22 +2227,22 @@ static void wpaint_paint_leaves(bContext *C, data.strength = BKE_brush_weight_get(scene, brush); /* NOTE: current mirroring code cannot be run in parallel */ - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, !(me->editflag & ME_EDIT_MIRROR_X), totnode); switch ((eBrushWeightPaintTool)brush->weightpaint_tool) { case WPAINT_TOOL_AVERAGE: calculate_average_weight(&data, nodes, totnode); - BKE_pbvh_parallel_range(0, totnode, &data, do_wpaint_brush_draw_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_wpaint_brush_draw_task_cb_ex, &settings); break; case WPAINT_TOOL_SMEAR: - BKE_pbvh_parallel_range(0, totnode, &data, do_wpaint_brush_smear_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_wpaint_brush_smear_task_cb_ex, &settings); break; case WPAINT_TOOL_BLUR: - BKE_pbvh_parallel_range(0, totnode, &data, do_wpaint_brush_blur_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_wpaint_brush_blur_task_cb_ex, &settings); break; case WPAINT_TOOL_DRAW: - BKE_pbvh_parallel_range(0, totnode, &data, do_wpaint_brush_draw_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_wpaint_brush_draw_task_cb_ex, &settings); break; } } @@ -3248,9 +3248,9 @@ static void calculate_average_color(SculptThreadedTaskData *data, struct VPaintAverageAccum *accum = MEM_mallocN(sizeof(*accum) * totnode, __func__); data->custom_data = accum; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, true, totnode); - BKE_pbvh_parallel_range(0, totnode, data, do_vpaint_brush_calc_average_color_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, data, do_vpaint_brush_calc_average_color_cb_ex, &settings); uint accum_len = 0; uint accum_value[3] = {0}; @@ -3294,21 +3294,21 @@ static void vpaint_paint_leaves(bContext *C, .lcol = (uint *)me->mloopcol, .me = me, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, true, totnode); switch ((eBrushVertexPaintTool)brush->vertexpaint_tool) { case VPAINT_TOOL_AVERAGE: calculate_average_color(&data, nodes, totnode); - BKE_pbvh_parallel_range(0, totnode, &data, do_vpaint_brush_draw_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_vpaint_brush_draw_task_cb_ex, &settings); break; case VPAINT_TOOL_BLUR: - BKE_pbvh_parallel_range(0, totnode, &data, do_vpaint_brush_blur_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_vpaint_brush_blur_task_cb_ex, &settings); break; case VPAINT_TOOL_SMEAR: - BKE_pbvh_parallel_range(0, totnode, &data, do_vpaint_brush_smear_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_vpaint_brush_smear_task_cb_ex, &settings); break; case VPAINT_TOOL_DRAW: - BKE_pbvh_parallel_range(0, totnode, &data, do_vpaint_brush_draw_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_vpaint_brush_draw_task_cb_ex, &settings); break; } } diff --git a/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c b/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c index 103f312975a..08ffd8e620e 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c +++ b/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c @@ -108,7 +108,7 @@ static bool weight_from_bones_poll(bContext *C) { Object *ob = CTX_data_active_object(C); - return (ob && (ob->mode & OB_MODE_WEIGHT_PAINT) && modifiers_isDeformedByArmature(ob)); + return (ob && (ob->mode & OB_MODE_WEIGHT_PAINT) && BKE_modifiers_is_deformed_by_armature(ob)); } static int weight_from_bones_exec(bContext *C, wmOperator *op) @@ -116,7 +116,7 @@ static int weight_from_bones_exec(bContext *C, wmOperator *op) Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); Scene *scene = CTX_data_scene(C); Object *ob = CTX_data_active_object(C); - Object *armob = modifiers_isDeformedByArmature(ob); + Object *armob = BKE_modifiers_is_deformed_by_armature(ob); Mesh *me = ob->data; int type = RNA_enum_get(op->ptr, "type"); diff --git a/source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c b/source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c index 5a3067ef193..a483f63bc06 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c +++ b/source/blender/editors/sculpt_paint/paint_vertex_weight_utils.c @@ -82,7 +82,7 @@ bool ED_wpaint_ensure_data(bContext *C, /* this happens on a Bone select, when no vgroup existed yet */ if (ob->actdef <= 0) { Object *modob; - if ((modob = modifiers_isDeformedByArmature(ob))) { + if ((modob = BKE_modifiers_is_deformed_by_armature(ob))) { Bone *actbone = ((bArmature *)modob->data)->act_bone; if (actbone) { bPoseChannel *pchan = BKE_pose_channel_find_name(modob->pose, actbone->name); diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index d2dda1be1e7..855e7503e3b 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -10,7 +10,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, + * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * The Original Code is Copyright (C) 2006 by Nicholas Bishop @@ -806,12 +806,12 @@ int SCULPT_nearest_vertex_get( nvtd.nearest_vertex_index = -1; nvtd.nearest_vertex_distance_squared = FLT_MAX; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); settings.func_reduce = nearest_vertex_get_reduce; settings.userdata_chunk = &nvtd; settings.userdata_chunk_size = sizeof(NearestVertexTLSData); - BKE_pbvh_parallel_range(0, totnode, &task_data, do_nearest_vertex_get_task_cb, &settings); + BLI_task_parallel_range(0, totnode, &task_data, do_nearest_vertex_get_task_cb, &settings); MEM_SAFE_FREE(nodes); @@ -952,11 +952,11 @@ static bool sculpt_has_active_modifiers(Scene *scene, Object *ob) ModifierData *md; VirtualModifierData virtualModifierData; - md = modifiers_getVirtualModifierList(ob, &virtualModifierData); + md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData); /* Exception for shape keys because we can edit those. */ for (; md; md = md->next) { - if (modifier_isEnabled(scene, md, eModifierMode_Realtime)) { + if (BKE_modifier_is_enabled(scene, md, eModifierMode_Realtime)) { return true; } } @@ -1283,9 +1283,9 @@ static void paint_mesh_restore_co(Sculpt *sd, Object *ob) .nodes = nodes, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP) && !ss->bm, totnode); - BKE_pbvh_parallel_range(0, totnode, &data, paint_mesh_restore_co_task_cb, &settings); + BLI_task_parallel_range(0, totnode, &data, paint_mesh_restore_co_task_cb, &settings); MEM_SAFE_FREE(nodes); } @@ -1909,12 +1909,12 @@ static void calc_area_center( AreaNormalCenterTLSData anctd = {{{0}}}; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); settings.func_reduce = calc_area_normal_and_center_reduce; settings.userdata_chunk = &anctd; settings.userdata_chunk_size = sizeof(AreaNormalCenterTLSData); - BKE_pbvh_parallel_range(0, totnode, &data, calc_area_normal_and_center_task_cb, &settings); + BLI_task_parallel_range(0, totnode, &data, calc_area_normal_and_center_task_cb, &settings); /* For flatten center. */ for (n = 0; n < ARRAY_SIZE(anctd.area_cos); n++) { @@ -1968,12 +1968,12 @@ bool SCULPT_pbvh_calc_area_normal(const Brush *brush, AreaNormalCenterTLSData anctd = {{{0}}}; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, use_threading, totnode); settings.func_reduce = calc_area_normal_and_center_reduce; settings.userdata_chunk = &anctd; settings.userdata_chunk_size = sizeof(AreaNormalCenterTLSData); - BKE_pbvh_parallel_range(0, totnode, &data, calc_area_normal_and_center_task_cb, &settings); + BLI_task_parallel_range(0, totnode, &data, calc_area_normal_and_center_task_cb, &settings); /* For area normal. */ for (int i = 0; i < ARRAY_SIZE(anctd.area_nos); i++) { @@ -2009,12 +2009,12 @@ static void calc_area_normal_and_center( AreaNormalCenterTLSData anctd = {{{0}}}; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); settings.func_reduce = calc_area_normal_and_center_reduce; settings.userdata_chunk = &anctd; settings.userdata_chunk_size = sizeof(AreaNormalCenterTLSData); - BKE_pbvh_parallel_range(0, totnode, &data, calc_area_normal_and_center_task_cb, &settings); + BLI_task_parallel_range(0, totnode, &data, calc_area_normal_and_center_task_cb, &settings); /* For flatten center. */ for (n = 0; n < ARRAY_SIZE(anctd.area_cos); n++) { @@ -2100,7 +2100,7 @@ static float brush_strength(const Sculpt *sd, return alpha * pressure * overlap * feather * 2.0f; case SCULPT_TOOL_CLAY_STRIPS: /* Clay Strips needs less strength to compensate the curve. */ - final_pressure = pressure * pressure * pressure; + final_pressure = powf(pressure, 1.5f); return alpha * flip * final_pressure * overlap * feather * 0.3f; case SCULPT_TOOL_CLAY_THUMB: final_pressure = pressure * pressure; @@ -2618,22 +2618,17 @@ static void do_topology_rake_bmesh_task_cb_ex(void *__restrict userdata, SculptBrushTest test; SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); PBVHVertexIter vd; BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { if (sculpt_brush_test_sq_fn(&test, vd.co)) { - const float fade = bstrength * - SCULPT_brush_strength_factor(ss, - brush, - vd.co, - sqrtf(test.dist), - vd.no, - vd.fno, - *vd.mask, - vd.index, - tls->thread_id) * - ss->cache->pressure; + const float fade = + bstrength * + SCULPT_brush_strength_factor( + ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, *vd.mask, vd.index, thread_id) * + ss->cache->pressure; float avg[3], val[3]; @@ -2675,10 +2670,10 @@ static void bmesh_topology_rake( .nodes = nodes, .strength = factor, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BKE_pbvh_parallel_range(0, totnode, &data, do_topology_rake_bmesh_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_topology_rake_bmesh_task_cb_ex, &settings); } } @@ -2696,12 +2691,13 @@ static void do_mask_brush_draw_task_cb_ex(void *__restrict userdata, SculptBrushTest test; SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { if (sculpt_brush_test_sq_fn(&test, vd.co)) { const float fade = SCULPT_brush_strength_factor( - ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, 0.0f, vd.index, tls->thread_id); + ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, 0.0f, vd.index, thread_id); if (bstrength > 0.0f) { (*vd.mask) += fade * bstrength * (1.0f - *vd.mask); @@ -2731,9 +2727,9 @@ static void do_mask_brush_draw(Sculpt *sd, Object *ob, PBVHNode **nodes, int tot .nodes = nodes, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BKE_pbvh_parallel_range(0, totnode, &data, do_mask_brush_draw_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_mask_brush_draw_task_cb_ex, &settings); } static void do_mask_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) @@ -2768,6 +2764,7 @@ static void do_draw_brush_task_cb_ex(void *__restrict userdata, SculptBrushTest test; SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { @@ -2781,7 +2778,7 @@ static void do_draw_brush_task_cb_ex(void *__restrict userdata, vd.fno, vd.mask ? *vd.mask : 0.0f, vd.index, - tls->thread_id); + thread_id); mul_v3_v3fl(proxy[vd.i], offset, fade); @@ -2818,9 +2815,9 @@ static void do_draw_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) .offset = offset, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BKE_pbvh_parallel_range(0, totnode, &data, do_draw_brush_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_draw_brush_task_cb_ex, &settings); } static void do_draw_sharp_brush_task_cb_ex(void *__restrict userdata, @@ -2843,6 +2840,7 @@ static void do_draw_sharp_brush_task_cb_ex(void *__restrict userdata, SculptBrushTest test; SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { @@ -2857,7 +2855,7 @@ static void do_draw_sharp_brush_task_cb_ex(void *__restrict userdata, NULL, vd.mask ? *vd.mask : 0.0f, vd.index, - tls->thread_id); + thread_id); mul_v3_v3fl(proxy[vd.i], offset, fade); @@ -2894,9 +2892,9 @@ static void do_draw_sharp_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int to .offset = offset, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BKE_pbvh_parallel_range(0, totnode, &data, do_draw_sharp_brush_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_draw_sharp_brush_task_cb_ex, &settings); } /* -------------------------------------------------------------------- */ @@ -2923,6 +2921,7 @@ static void do_topology_slide_task_cb_ex(void *__restrict userdata, SculptBrushTest test; SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { @@ -2936,7 +2935,7 @@ static void do_topology_slide_task_cb_ex(void *__restrict userdata, NULL, vd.mask ? *vd.mask : 0.0f, vd.index, - tls->thread_id); + thread_id); float current_disp[3]; float current_disp_norm[3]; float final_disp[3]; @@ -3037,6 +3036,7 @@ static void do_topology_relax_task_cb_ex(void *__restrict userdata, SculptBrushTest test; SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { @@ -3050,7 +3050,7 @@ static void do_topology_relax_task_cb_ex(void *__restrict userdata, NULL, vd.mask ? *vd.mask : 0.0f, vd.index, - tls->thread_id); + thread_id); SCULPT_relax_vertex(ss, &vd, fade * bstrength, false, vd.co); if (vd.mvert) { @@ -3079,15 +3079,15 @@ static void do_slide_relax_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int t .nodes = nodes, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); if (ss->cache->alt_smooth) { for (int i = 0; i < 4; i++) { - BKE_pbvh_parallel_range(0, totnode, &data, do_topology_relax_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_topology_relax_task_cb_ex, &settings); } } else { - BKE_pbvh_parallel_range(0, totnode, &data, do_topology_slide_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_topology_slide_task_cb_ex, &settings); } } @@ -3200,6 +3200,7 @@ static void do_crease_brush_task_cb_ex(void *__restrict userdata, SculptBrushTest test; SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { @@ -3213,7 +3214,7 @@ static void do_crease_brush_task_cb_ex(void *__restrict userdata, vd.fno, vd.mask ? *vd.mask : 0.0f, vd.index, - tls->thread_id); + thread_id); float val1[3]; float val2[3]; @@ -3288,9 +3289,9 @@ static void do_crease_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod .flippedbstrength = flippedbstrength, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BKE_pbvh_parallel_range(0, totnode, &data, do_crease_brush_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_crease_brush_task_cb_ex, &settings); } static void do_pinch_brush_task_cb_ex(void *__restrict userdata, @@ -3311,6 +3312,7 @@ static void do_pinch_brush_task_cb_ex(void *__restrict userdata, SculptBrushTest test; SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); float x_object_space[3]; float z_object_space[3]; @@ -3328,7 +3330,7 @@ static void do_pinch_brush_task_cb_ex(void *__restrict userdata, vd.fno, vd.mask ? *vd.mask : 0.0f, vd.index, - tls->thread_id); + thread_id); float disp_center[3]; float x_disp[3]; float z_disp[3]; @@ -3401,9 +3403,9 @@ static void do_pinch_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode .stroke_xz = stroke_xz, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BKE_pbvh_parallel_range(0, totnode, &data, do_pinch_brush_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_pinch_brush_task_cb_ex, &settings); } static void do_grab_brush_task_cb_ex(void *__restrict userdata, @@ -3427,6 +3429,7 @@ static void do_grab_brush_task_cb_ex(void *__restrict userdata, SculptBrushTest test; SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { @@ -3441,7 +3444,7 @@ static void do_grab_brush_task_cb_ex(void *__restrict userdata, NULL, vd.mask ? *vd.mask : 0.0f, vd.index, - tls->thread_id); + thread_id); mul_v3_v3fl(proxy[vd.i], grab_delta, fade); @@ -3473,9 +3476,9 @@ static void do_grab_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) .grab_delta = grab_delta, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BKE_pbvh_parallel_range(0, totnode, &data, do_grab_brush_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_grab_brush_task_cb_ex, &settings); } static void do_elastic_deform_brush_task_cb_ex(void *__restrict userdata, @@ -3582,9 +3585,9 @@ static void do_elastic_deform_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, in .grab_delta = grab_delta, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BKE_pbvh_parallel_range(0, totnode, &data, do_elastic_deform_brush_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_elastic_deform_brush_task_cb_ex, &settings); } ePaintSymmetryAreas SCULPT_get_vertex_symm_area(const float co[3]) @@ -3744,6 +3747,7 @@ static void do_nudge_brush_task_cb_ex(void *__restrict userdata, SculptBrushTest test; SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { @@ -3756,7 +3760,7 @@ static void do_nudge_brush_task_cb_ex(void *__restrict userdata, vd.fno, vd.mask ? *vd.mask : 0.0f, vd.index, - tls->thread_id); + thread_id); mul_v3_v3fl(proxy[vd.i], cono, fade); @@ -3788,9 +3792,9 @@ static void do_nudge_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode .cono = cono, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BKE_pbvh_parallel_range(0, totnode, &data, do_nudge_brush_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_nudge_brush_task_cb_ex, &settings); } static void do_snake_hook_brush_task_cb_ex(void *__restrict userdata, @@ -3817,6 +3821,7 @@ static void do_snake_hook_brush_task_cb_ex(void *__restrict userdata, SculptBrushTest test; SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { @@ -3829,7 +3834,7 @@ static void do_snake_hook_brush_task_cb_ex(void *__restrict userdata, vd.fno, vd.mask ? *vd.mask : 0.0f, vd.index, - tls->thread_id); + thread_id); mul_v3_v3fl(proxy[vd.i], grab_delta, fade); @@ -3909,9 +3914,9 @@ static void do_snake_hook_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int to .grab_delta = grab_delta, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BKE_pbvh_parallel_range(0, totnode, &data, do_snake_hook_brush_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_snake_hook_brush_task_cb_ex, &settings); } static void do_thumb_brush_task_cb_ex(void *__restrict userdata, @@ -3935,6 +3940,7 @@ static void do_thumb_brush_task_cb_ex(void *__restrict userdata, SculptBrushTest test; SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { @@ -3949,7 +3955,7 @@ static void do_thumb_brush_task_cb_ex(void *__restrict userdata, NULL, vd.mask ? *vd.mask : 0.0f, vd.index, - tls->thread_id); + thread_id); mul_v3_v3fl(proxy[vd.i], cono, fade); @@ -3981,9 +3987,9 @@ static void do_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode .cono = cono, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BKE_pbvh_parallel_range(0, totnode, &data, do_thumb_brush_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_thumb_brush_task_cb_ex, &settings); } static void do_rotate_brush_task_cb_ex(void *__restrict userdata, @@ -4007,6 +4013,7 @@ static void do_rotate_brush_task_cb_ex(void *__restrict userdata, SculptBrushTest test; SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { @@ -4022,7 +4029,7 @@ static void do_rotate_brush_task_cb_ex(void *__restrict userdata, NULL, vd.mask ? *vd.mask : 0.0f, vd.index, - tls->thread_id); + thread_id); sub_v3_v3v3(vec, orig_data.co, ss->cache->location); axis_angle_normalized_to_mat3(rot, ss->cache->sculpt_normal_symm, angle * fade); @@ -4054,9 +4061,9 @@ static void do_rotate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod .angle = angle, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BKE_pbvh_parallel_range(0, totnode, &data, do_rotate_brush_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_rotate_brush_task_cb_ex, &settings); } static void do_layer_brush_task_cb_ex(void *__restrict userdata, @@ -4078,6 +4085,7 @@ static void do_layer_brush_task_cb_ex(void *__restrict userdata, SculptBrushTest test; SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { @@ -4092,7 +4100,7 @@ static void do_layer_brush_task_cb_ex(void *__restrict userdata, vd.fno, vd.mask ? *vd.mask : 0.0f, vd.index, - tls->thread_id); + thread_id); const int vi = vd.index; float *disp_factor; @@ -4169,9 +4177,9 @@ static void do_layer_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode .nodes = nodes, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BKE_pbvh_parallel_range(0, totnode, &data, do_layer_brush_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_layer_brush_task_cb_ex, &settings); } static void do_inflate_brush_task_cb_ex(void *__restrict userdata, @@ -4191,6 +4199,7 @@ static void do_inflate_brush_task_cb_ex(void *__restrict userdata, SculptBrushTest test; SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { @@ -4203,7 +4212,7 @@ static void do_inflate_brush_task_cb_ex(void *__restrict userdata, vd.fno, vd.mask ? *vd.mask : 0.0f, vd.index, - tls->thread_id); + thread_id); float val[3]; if (vd.fno) { @@ -4235,9 +4244,9 @@ static void do_inflate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno .nodes = nodes, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BKE_pbvh_parallel_range(0, totnode, &data, do_inflate_brush_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_inflate_brush_task_cb_ex, &settings); } int SCULPT_plane_trim(const StrokeCache *cache, const Brush *brush, const float val[3]) @@ -4293,6 +4302,7 @@ static void do_flatten_brush_task_cb_ex(void *__restrict userdata, SculptBrushTest test; SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); plane_from_point_normal_v3(test.plane_tool, area_co, area_no); @@ -4315,7 +4325,7 @@ static void do_flatten_brush_task_cb_ex(void *__restrict userdata, vd.fno, vd.mask ? *vd.mask : 0.0f, vd.index, - tls->thread_id); + thread_id); mul_v3_v3fl(proxy[vd.i], val, fade); @@ -4359,9 +4369,9 @@ static void do_flatten_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totno .area_co = area_co, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BKE_pbvh_parallel_range(0, totnode, &data, do_flatten_brush_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_flatten_brush_task_cb_ex, &settings); } /* -------------------------------------------------------------------- */ @@ -4447,6 +4457,7 @@ static void do_clay_brush_task_cb_ex(void *__restrict userdata, SculptBrushTest test; SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); plane_from_point_normal_v3(test.plane_tool, area_co, area_no); @@ -4467,7 +4478,7 @@ static void do_clay_brush_task_cb_ex(void *__restrict userdata, vd.fno, vd.mask ? *vd.mask : 0.0f, vd.index, - tls->thread_id); + thread_id); mul_v3_v3fl(proxy[vd.i], val, fade); @@ -4509,13 +4520,13 @@ static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) ClaySampleData csd = {{0}}; - PBVHParallelSettings sample_settings; + TaskParallelSettings sample_settings; BKE_pbvh_parallel_range_settings(&sample_settings, (sd->flags & SCULPT_USE_OPENMP), totnode); sample_settings.func_reduce = calc_clay_surface_reduce; sample_settings.userdata_chunk = &csd; sample_settings.userdata_chunk_size = sizeof(ClaySampleData); - BKE_pbvh_parallel_range(0, totnode, &sample_data, calc_clay_surface_task_cb, &sample_settings); + BLI_task_parallel_range(0, totnode, &sample_data, calc_clay_surface_task_cb, &sample_settings); float d_offset = (csd.plane_dist[0] + csd.plane_dist[1]); d_offset = min_ff(radius, d_offset); @@ -4540,9 +4551,9 @@ static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) .area_co = area_co, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BKE_pbvh_parallel_range(0, totnode, &data, do_clay_brush_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_clay_brush_task_cb_ex, &settings); } static void do_clay_strips_brush_task_cb_ex(void *__restrict userdata, @@ -4566,6 +4577,7 @@ static void do_clay_strips_brush_task_cb_ex(void *__restrict userdata, SCULPT_brush_test_init(ss, &test); plane_from_point_normal_v3(test.plane_tool, area_co, area_no_sp); + const int thread_id = BLI_task_parallel_thread_id(tls); BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { @@ -4589,7 +4601,7 @@ static void do_clay_strips_brush_task_cb_ex(void *__restrict userdata, vd.fno, vd.mask ? *vd.mask : 0.0f, vd.index, - tls->thread_id); + thread_id); mul_v3_v3fl(proxy[vd.i], val, fade); @@ -4611,7 +4623,7 @@ static void do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int t const bool flip = (ss->cache->bstrength < 0.0f); const float radius = flip ? -ss->cache->radius : ss->cache->radius; const float offset = SCULPT_brush_plane_offset_get(sd, ss); - const float displace = radius * (0.25f + offset); + const float displace = radius * (0.18f + offset); /* The sculpt-plane normal (whatever its set to). */ float area_no_sp[3]; @@ -4673,9 +4685,9 @@ static void do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int t .mat = mat, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BKE_pbvh_parallel_range(0, totnode, &data, do_clay_strips_brush_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_clay_strips_brush_task_cb_ex, &settings); } static void do_fill_brush_task_cb_ex(void *__restrict userdata, @@ -4697,6 +4709,7 @@ static void do_fill_brush_task_cb_ex(void *__restrict userdata, SculptBrushTest test; SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); plane_from_point_normal_v3(test.plane_tool, area_co, area_no); @@ -4720,7 +4733,7 @@ static void do_fill_brush_task_cb_ex(void *__restrict userdata, vd.fno, vd.mask ? *vd.mask : 0.0f, vd.index, - tls->thread_id); + thread_id); mul_v3_v3fl(proxy[vd.i], val, fade); @@ -4766,9 +4779,9 @@ static void do_fill_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) .area_co = area_co, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BKE_pbvh_parallel_range(0, totnode, &data, do_fill_brush_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_fill_brush_task_cb_ex, &settings); } static void do_scrape_brush_task_cb_ex(void *__restrict userdata, @@ -4790,6 +4803,7 @@ static void do_scrape_brush_task_cb_ex(void *__restrict userdata, SculptBrushTest test; SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); plane_from_point_normal_v3(test.plane_tool, area_co, area_no); BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) @@ -4812,7 +4826,7 @@ static void do_scrape_brush_task_cb_ex(void *__restrict userdata, vd.fno, vd.mask ? *vd.mask : 0.0f, vd.index, - tls->thread_id); + thread_id); mul_v3_v3fl(proxy[vd.i], val, fade); @@ -4858,9 +4872,9 @@ static void do_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnod .area_co = area_co, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BKE_pbvh_parallel_range(0, totnode, &data, do_scrape_brush_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_scrape_brush_task_cb_ex, &settings); } /* -------------------------------------------------------------------- */ @@ -4888,6 +4902,7 @@ static void do_clay_thumb_brush_task_cb_ex(void *__restrict userdata, SculptBrushTest test; SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); float plane_tilt[4]; float normal_tilt[3]; @@ -4928,7 +4943,7 @@ static void do_clay_thumb_brush_task_cb_ex(void *__restrict userdata, vd.fno, vd.mask ? *vd.mask : 0.0f, vd.index, - tls->thread_id); + thread_id); mul_v3_v3fl(proxy[vd.i], val, fade); @@ -5030,9 +5045,9 @@ static void do_clay_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int to .clay_strength = clay_strength, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BKE_pbvh_parallel_range(0, totnode, &data, do_clay_thumb_brush_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_clay_thumb_brush_task_cb_ex, &settings); } /** \} */ @@ -5054,6 +5069,7 @@ static void do_gravity_task_cb_ex(void *__restrict userdata, SculptBrushTest test; SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { @@ -5066,7 +5082,7 @@ static void do_gravity_task_cb_ex(void *__restrict userdata, vd.fno, vd.mask ? *vd.mask : 0.0f, vd.index, - tls->thread_id); + thread_id); mul_v3_v3fl(proxy[vd.i], offset, fade); @@ -5101,9 +5117,9 @@ static void do_gravity(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, fl .offset = offset, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BKE_pbvh_parallel_range(0, totnode, &data, do_gravity_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_gravity_task_cb_ex, &settings); } void SCULPT_vertcos_to_key(Object *ob, KeyBlock *kb, const float (*vertCos)[3]) @@ -5284,7 +5300,7 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe /* Draw Face Sets in draw mode makes a single undo push, in alt-smooth mode deforms the * vertices and uses regular coords undo. */ - /* It also assings the paint_face_set here as it needs to be done regardless of the stroke type + /* It also assigns the paint_face_set here as it needs to be done regardless of the stroke type * and the number of nodes under the brush influence. */ if (brush->sculpt_tool == SCULPT_TOOL_DRAW_FACE_SETS && ss->cache->first_time && ss->cache->mirror_symmetry_pass == 0 && !ss->cache->alt_smooth) { @@ -5310,9 +5326,9 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe .nodes = nodes, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BKE_pbvh_parallel_range(0, totnode, &task_data, do_brush_action_task_cb, &settings); + BLI_task_parallel_range(0, totnode, &task_data, do_brush_action_task_cb, &settings); if (sculpt_brush_needs_normal(ss, brush)) { update_sculpt_normal(sd, ob, nodes, totnode); @@ -5566,9 +5582,9 @@ static void sculpt_combine_proxies(Sculpt *sd, Object *ob) .nodes = nodes, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BKE_pbvh_parallel_range(0, totnode, &data, sculpt_combine_proxies_task_cb, &settings); + BLI_task_parallel_range(0, totnode, &data, sculpt_combine_proxies_task_cb, &settings); } MEM_SAFE_FREE(nodes); @@ -5654,9 +5670,9 @@ void SCULPT_flush_stroke_deform(Sculpt *sd, Object *ob, bool is_proxy_used) .vertCos = vertCos, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BKE_pbvh_parallel_range(0, totnode, &data, SCULPT_flush_stroke_deform_task_cb, &settings); + BLI_task_parallel_range(0, totnode, &data, SCULPT_flush_stroke_deform_task_cb, &settings); if (vertCos) { SCULPT_vertcos_to_key(ob, ss->shapekey_active, vertCos); @@ -6182,7 +6198,7 @@ static float sculpt_brush_dynamic_size_get(Brush *brush, StrokeCache *cache, flo case SCULPT_TOOL_CLAY: return max_ff(initial_size * 0.20f, initial_size * pow3f(cache->pressure)); case SCULPT_TOOL_CLAY_STRIPS: - return max_ff(initial_size * 0.30f, initial_size * pow2f(cache->pressure)); + return max_ff(initial_size * 0.30f, initial_size * powf(cache->pressure, 1.5f)); case SCULPT_TOOL_CLAY_THUMB: { float clay_stabilized_pressure = sculpt_clay_thumb_get_stabilized_pressure(cache); return initial_size * clay_stabilized_pressure; @@ -7533,7 +7549,7 @@ static int ed_object_sculptmode_flush_recalc_flag(Scene *scene, { int flush_recalc = 0; /* Multires in sculpt mode could have different from object mode subdivision level. */ - flush_recalc |= mmd && BKE_multires_sculpt_level_get(mmd) != mmd->lvl; + flush_recalc |= mmd && mmd->sculptlvl != mmd->lvl; /* If object has got active modifiers, it's dm could be different in sculpt mode. */ flush_recalc |= sculpt_has_active_modifiers(scene, ob); return flush_recalc; diff --git a/source/blender/editors/sculpt_paint/sculpt_automasking.c b/source/blender/editors/sculpt_paint/sculpt_automasking.c index 3ccf59ba3bb..f0f6478d3a6 100644 --- a/source/blender/editors/sculpt_paint/sculpt_automasking.c +++ b/source/blender/editors/sculpt_paint/sculpt_automasking.c @@ -10,7 +10,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, + * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * The Original Code is Copyright (C) 2020 Blender Foundation. diff --git a/source/blender/editors/sculpt_paint/sculpt_cloth.c b/source/blender/editors/sculpt_paint/sculpt_cloth.c index b1cc6d02bbb..62a7f1925ab 100644 --- a/source/blender/editors/sculpt_paint/sculpt_cloth.c +++ b/source/blender/editors/sculpt_paint/sculpt_cloth.c @@ -10,7 +10,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, + * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * The Original Code is Copyright (C) 2020 Blender Foundation. @@ -221,6 +221,7 @@ static void do_cloth_brush_apply_forces_task_cb_ex(void *__restrict userdata, SculptBrushTest test; SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); /* For Pich Perpendicular Deform Type. */ float x_object_space[3]; @@ -269,7 +270,7 @@ static void do_cloth_brush_apply_forces_task_cb_ex(void *__restrict userdata, vd.fno, vd.mask ? *vd.mask : 0.0f, vd.index, - tls->thread_id); + thread_id); float brush_disp[3]; float normal[3]; @@ -412,7 +413,7 @@ static void cloth_brush_build_nodes_constraints(Sculpt *sd, * storing the constraints per node. */ /* Currently all constrains are added to the same global array which can't be accessed from * different threads. */ - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, false, totnode); SculptThreadedTaskData build_constraints_data = { @@ -421,7 +422,7 @@ static void cloth_brush_build_nodes_constraints(Sculpt *sd, .brush = brush, .nodes = nodes, }; - BKE_pbvh_parallel_range( + BLI_task_parallel_range( 0, totnode, &build_constraints_data, do_cloth_brush_build_constraints_task_cb_ex, &settings); } @@ -490,9 +491,9 @@ static void cloth_brush_do_simulation_step(Sculpt *sd, Object *ob, PBVHNode **no .cloth_time_step = CLOTH_SIMULATION_TIME_STEP, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BKE_pbvh_parallel_range( + BLI_task_parallel_range( 0, totnode, &solve_simulation_data, do_cloth_brush_solve_simulation_task_cb_ex, &settings); } @@ -565,9 +566,9 @@ static void cloth_brush_apply_brush_foces(Sculpt *sd, Object *ob, PBVHNode **nod } } - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BKE_pbvh_parallel_range( + BLI_task_parallel_range( 0, totnode, &apply_forces_data, do_cloth_brush_apply_forces_task_cb_ex, &settings); } diff --git a/source/blender/editors/sculpt_paint/sculpt_detail.c b/source/blender/editors/sculpt_paint/sculpt_detail.c index a99aa3d1bcf..b7d1cd8c005 100644 --- a/source/blender/editors/sculpt_paint/sculpt_detail.c +++ b/source/blender/editors/sculpt_paint/sculpt_detail.c @@ -10,7 +10,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, + * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * The Original Code is Copyright (C) 2020 Blender Foundation. diff --git a/source/blender/editors/sculpt_paint/sculpt_dyntopo.c b/source/blender/editors/sculpt_paint/sculpt_dyntopo.c index 0ab3b8cd14e..eefd8529dbf 100644 --- a/source/blender/editors/sculpt_paint/sculpt_dyntopo.c +++ b/source/blender/editors/sculpt_paint/sculpt_dyntopo.c @@ -10,7 +10,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, + * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * The Original Code is Copyright (C) 2020 Blender Foundation. @@ -384,12 +384,12 @@ enum eDynTopoWarnFlag SCULPT_dynamic_topology_check(Scene *scene, Object *ob) { VirtualModifierData virtualModifierData; - ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData); + ModifierData *md = BKE_modifiers_get_virtual_modifierlist(ob, &virtualModifierData); /* Exception for shape keys because we can edit those. */ for (; md; md = md->next) { - const ModifierTypeInfo *mti = modifierType_getInfo(md->type); - if (!modifier_isEnabled(scene, md, eModifierMode_Realtime)) { + const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); + if (!BKE_modifier_is_enabled(scene, md, eModifierMode_Realtime)) { continue; } diff --git a/source/blender/editors/sculpt_paint/sculpt_face_set.c b/source/blender/editors/sculpt_paint/sculpt_face_set.c index 43ff1ad3ef5..f96f08e3244 100644 --- a/source/blender/editors/sculpt_paint/sculpt_face_set.c +++ b/source/blender/editors/sculpt_paint/sculpt_face_set.c @@ -10,7 +10,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, + * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * The Original Code is Copyright (C) 2020 Blender Foundation. @@ -87,6 +87,7 @@ static void do_draw_face_sets_brush_task_cb_ex(void *__restrict userdata, SculptBrushTest test; SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { @@ -107,7 +108,7 @@ static void do_draw_face_sets_brush_task_cb_ex(void *__restrict userdata, vd.fno, vd.mask ? *vd.mask : 0.0f, vd.index, - tls->thread_id); + thread_id); if (fade > 0.05f && ss->face_sets[vert_map->indices[j]] > 0) { ss->face_sets[vert_map->indices[j]] = abs(ss->cache->paint_face_set); @@ -127,7 +128,7 @@ static void do_draw_face_sets_brush_task_cb_ex(void *__restrict userdata, vd.fno, vd.mask ? *vd.mask : 0.0f, vd.index, - tls->thread_id); + thread_id); if (fade > 0.05f) { SCULPT_vertex_face_set_set(ss, vd.index, ss->cache->paint_face_set); @@ -160,6 +161,8 @@ static void do_relax_face_sets_brush_task_cb_ex(void *__restrict userdata, bstrength *= 2.0f; } + const int thread_id = BLI_task_parallel_thread_id(tls); + BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { if (sculpt_brush_test_sq_fn(&test, vd.co)) { @@ -172,7 +175,7 @@ static void do_relax_face_sets_brush_task_cb_ex(void *__restrict userdata, vd.fno, vd.mask ? *vd.mask : 0.0f, vd.index, - tls->thread_id); + thread_id); SCULPT_relax_vertex(ss, &vd, fade * bstrength, relax_face_sets, vd.co); if (vd.mvert) { @@ -199,15 +202,15 @@ void SCULPT_do_draw_face_sets_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, in .nodes = nodes, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); if (ss->cache->alt_smooth) { for (int i = 0; i < 4; i++) { - BKE_pbvh_parallel_range(0, totnode, &data, do_relax_face_sets_brush_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_relax_face_sets_brush_task_cb_ex, &settings); } } else { - BKE_pbvh_parallel_range(0, totnode, &data, do_draw_face_sets_brush_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_draw_face_sets_brush_task_cb_ex, &settings); } } diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_mask.c b/source/blender/editors/sculpt_paint/sculpt_filter_mask.c index 38bbd083994..d2a683461a7 100644 --- a/source/blender/editors/sculpt_paint/sculpt_filter_mask.c +++ b/source/blender/editors/sculpt_paint/sculpt_filter_mask.c @@ -10,7 +10,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, + * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * The Original Code is Copyright (C) 2020 Blender Foundation. @@ -246,9 +246,9 @@ static int sculpt_mask_filter_exec(bContext *C, wmOperator *op) .prev_mask = prev_mask, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BKE_pbvh_parallel_range(0, totnode, &data, mask_filter_task_cb, &settings); + BLI_task_parallel_range(0, totnode, &data, mask_filter_task_cb, &settings); if (ELEM(filter_type, MASK_FILTER_GROW, MASK_FILTER_SHRINK)) { MEM_freeN(prev_mask); @@ -275,9 +275,9 @@ void SCULPT_mask_filter_smooth_apply( }; for (int i = 0; i < smooth_iterations; i++) { - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BKE_pbvh_parallel_range(0, totnode, &data, mask_filter_task_cb, &settings); + BLI_task_parallel_range(0, totnode, &data, mask_filter_task_cb, &settings); } } @@ -458,17 +458,17 @@ static int sculpt_dirty_mask_exec(bContext *C, wmOperator *op) .max = -FLT_MAX, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); settings.func_reduce = dirty_mask_compute_range_reduce; settings.userdata_chunk = ⦥ settings.userdata_chunk_size = sizeof(DirtyMaskRangeData); - BKE_pbvh_parallel_range(0, totnode, &data, dirty_mask_compute_range_task_cb, &settings); + BLI_task_parallel_range(0, totnode, &data, dirty_mask_compute_range_task_cb, &settings); data.dirty_mask_min = range.min; data.dirty_mask_max = range.max; - BKE_pbvh_parallel_range(0, totnode, &data, dirty_mask_apply_task_cb, &settings); + BLI_task_parallel_range(0, totnode, &data, dirty_mask_apply_task_cb, &settings); MEM_SAFE_FREE(nodes); diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c index 94b6e0eb864..7c438e9245b 100644 --- a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c +++ b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c @@ -10,7 +10,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, + * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * The Original Code is Copyright (C) 2020 Blender Foundation. @@ -112,10 +112,10 @@ void SCULPT_filter_cache_init(Object *ob, Sculpt *sd) .nodes = ss->filter_cache->nodes, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings( &settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode); - BKE_pbvh_parallel_range( + BLI_task_parallel_range( 0, ss->filter_cache->totnode, &data, filter_cache_init_task_cb, &settings); } @@ -496,13 +496,13 @@ static int sculpt_mesh_filter_modal(bContext *C, wmOperator *op, const wmEvent * .filter_strength = filter_strength, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings( &settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode); - BKE_pbvh_parallel_range(0, ss->filter_cache->totnode, &data, mesh_filter_task_cb, &settings); + BLI_task_parallel_range(0, ss->filter_cache->totnode, &data, mesh_filter_task_cb, &settings); if (filter_type == MESH_FILTER_SURFACE_SMOOTH) { - BKE_pbvh_parallel_range(0, + BLI_task_parallel_range(0, ss->filter_cache->totnode, &data, mesh_filter_surface_smooth_displace_task_cb, diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h index bc7a78f491c..9b13f6e6c24 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.h +++ b/source/blender/editors/sculpt_paint/sculpt_intern.h @@ -10,7 +10,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, + * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * The Original Code is Copyright (C) 2006 by Nicholas Bishop diff --git a/source/blender/editors/sculpt_paint/sculpt_mask_expand.c b/source/blender/editors/sculpt_paint/sculpt_mask_expand.c index 34ca92acef9..cbb198e14a3 100644 --- a/source/blender/editors/sculpt_paint/sculpt_mask_expand.c +++ b/source/blender/editors/sculpt_paint/sculpt_mask_expand.c @@ -10,7 +10,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, + * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * The Original Code is Copyright (C) 2020 Blender Foundation. @@ -288,10 +288,10 @@ static int sculpt_mask_expand_modal(bContext *C, wmOperator *op, const wmEvent * .mask_expand_keep_prev_mask = RNA_boolean_get(op->ptr, "keep_previous_mask"), .mask_expand_create_face_set = RNA_boolean_get(op->ptr, "create_face_set"), }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings( &settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode); - BKE_pbvh_parallel_range(0, ss->filter_cache->totnode, &data, sculpt_expand_task_cb, &settings); + BLI_task_parallel_range(0, ss->filter_cache->totnode, &data, sculpt_expand_task_cb, &settings); ss->filter_cache->mask_update_current_it = mask_expand_update_it; } @@ -458,10 +458,10 @@ static int sculpt_mask_expand_invoke(bContext *C, wmOperator *op, const wmEvent .mask_expand_keep_prev_mask = RNA_boolean_get(op->ptr, "keep_previous_mask"), .mask_expand_create_face_set = RNA_boolean_get(op->ptr, "create_face_set"), }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings( &settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode); - BKE_pbvh_parallel_range(0, ss->filter_cache->totnode, &data, sculpt_expand_task_cb, &settings); + BLI_task_parallel_range(0, ss->filter_cache->totnode, &data, sculpt_expand_task_cb, &settings); const char *status_str = TIP_( "Move the mouse to expand the mask from the active vertex. LMB: confirm mask, ESC/RMB: " diff --git a/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c b/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c index c74a2ba503a..f3327706102 100644 --- a/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c +++ b/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c @@ -10,7 +10,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, + * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * The Original Code is Copyright (C) 2020 Blender Foundation. @@ -79,6 +79,7 @@ static void calc_multiplane_scrape_surface_task_cb(void *__restrict userdata, SculptBrushTest test; SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( ss, &test, brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); /* Apply the brush normal radius to the test before sampling. */ float test_radius = sqrtf(test.radius_squared); @@ -107,7 +108,7 @@ static void calc_multiplane_scrape_surface_task_cb(void *__restrict userdata, vd.fno, vd.mask ? *vd.mask : 0.0f, vd.index, - tls->thread_id); + thread_id); /* Sample the normal and area of the +X and -X axis individually. */ if (local_co[0] > 0.0f) { @@ -163,6 +164,7 @@ static void do_multiplane_scrape_brush_task_cb_ex(void *__restrict userdata, SculptBrushTest test; SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { @@ -208,7 +210,7 @@ static void do_multiplane_scrape_brush_task_cb_ex(void *__restrict userdata, vd.fno, vd.mask ? *vd.mask : 0.0f, vd.index, - tls->thread_id); + thread_id); mul_v3_v3fl(proxy[vd.i], val, fade); @@ -301,13 +303,13 @@ void SCULPT_do_multiplane_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, MultiplaneScrapeSampleData mssd = {{{0}}}; - PBVHParallelSettings sample_settings; + TaskParallelSettings sample_settings; BKE_pbvh_parallel_range_settings(&sample_settings, (sd->flags & SCULPT_USE_OPENMP), totnode); sample_settings.func_reduce = calc_multiplane_scrape_surface_reduce; sample_settings.userdata_chunk = &mssd; sample_settings.userdata_chunk_size = sizeof(MultiplaneScrapeSampleData); - BKE_pbvh_parallel_range( + BLI_task_parallel_range( 0, totnode, &sample_data, calc_multiplane_scrape_surface_task_cb, &sample_settings); float sampled_plane_normals[2][3]; @@ -392,9 +394,9 @@ void SCULPT_do_multiplane_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, normalize_v3(plane_no); plane_from_point_normal_v3(data.multiplane_scrape_planes[0], area_co, plane_no); - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BKE_pbvh_parallel_range(0, totnode, &data, do_multiplane_scrape_brush_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_multiplane_scrape_brush_task_cb_ex, &settings); } void SCULPT_multiplane_scrape_preview_draw(const uint gpuattr, diff --git a/source/blender/editors/sculpt_paint/sculpt_pose.c b/source/blender/editors/sculpt_paint/sculpt_pose.c index fde4a9d1d23..c7511dfc80f 100644 --- a/source/blender/editors/sculpt_paint/sculpt_pose.c +++ b/source/blender/editors/sculpt_paint/sculpt_pose.c @@ -10,7 +10,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, + * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * The Original Code is Copyright (C) 2020 Blender Foundation. @@ -263,7 +263,7 @@ static void sculpt_pose_grow_pose_factor(Sculpt *sd, }; data.pose_initial_co = pose_target; - PBVHParallelSettings settings; + TaskParallelSettings settings; PoseGrowFactorTLSData gftd; gftd.pos_count = 0; zero_v3(gftd.pos_avg); @@ -279,7 +279,7 @@ static void sculpt_pose_grow_pose_factor(Sculpt *sd, zero_v3(gftd.pos_avg); gftd.pos_count = 0; memcpy(data.prev_mask, pose_factor, SCULPT_vertex_count_get(ss) * sizeof(float)); - BKE_pbvh_parallel_range(0, totnode, &data, pose_brush_grow_factor_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, pose_brush_grow_factor_task_cb_ex, &settings); if (gftd.pos_count != 0) { mul_v3_fl(gftd.pos_avg, 1.0f / (float)gftd.pos_count); @@ -793,9 +793,9 @@ void SCULPT_pose_brush_init(Sculpt *sd, Object *ob, SculptSession *ss, Brush *br for (int ik = 0; ik < ss->cache->pose_ik_chain->tot_segments; ik++) { data.pose_factor = ss->cache->pose_ik_chain->segments[ik].weights; for (int i = 0; i < br->pose_smooth_iterations; i++) { - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BKE_pbvh_parallel_range(0, totnode, &data, pose_brush_init_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, pose_brush_init_task_cb_ex, &settings); } } @@ -885,9 +885,9 @@ void SCULPT_do_pose_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) .grab_delta = grab_delta, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BKE_pbvh_parallel_range(0, totnode, &data, do_pose_brush_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_pose_brush_task_cb_ex, &settings); } void SCULPT_pose_ik_chain_free(SculptPoseIKChain *ik_chain) diff --git a/source/blender/editors/sculpt_paint/sculpt_smooth.c b/source/blender/editors/sculpt_paint/sculpt_smooth.c index 3a09d52d418..17451cb40ae 100644 --- a/source/blender/editors/sculpt_paint/sculpt_smooth.c +++ b/source/blender/editors/sculpt_paint/sculpt_smooth.c @@ -10,7 +10,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, + * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * The Original Code is Copyright (C) 2020 Blender Foundation. @@ -245,6 +245,8 @@ static void do_smooth_brush_mesh_task_cb_ex(void *__restrict userdata, SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); + BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { if (sculpt_brush_test_sq_fn(&test, vd.co)) { @@ -257,7 +259,7 @@ static void do_smooth_brush_mesh_task_cb_ex(void *__restrict userdata, vd.fno, smooth_mask ? 0.0f : (vd.mask ? *vd.mask : 0.0f), vd.index, - tls->thread_id); + thread_id); if (smooth_mask) { float val = SCULPT_neighbor_mask_average(ss, vd.vert_indices[vd.i]) - *vd.mask; val *= fade * bstrength; @@ -301,6 +303,7 @@ static void do_smooth_brush_bmesh_task_cb_ex(void *__restrict userdata, SculptBrushTest test; SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { @@ -313,7 +316,7 @@ static void do_smooth_brush_bmesh_task_cb_ex(void *__restrict userdata, vd.fno, smooth_mask ? 0.0f : *vd.mask, vd.index, - tls->thread_id); + thread_id); if (smooth_mask) { float val = SCULPT_neighbor_mask_average(ss, vd.index) - *vd.mask; val *= fade * bstrength; @@ -358,6 +361,8 @@ static void do_smooth_brush_multires_task_cb_ex(void *__restrict userdata, SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); + BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { if (sculpt_brush_test_sq_fn(&test, vd.co)) { @@ -370,7 +375,7 @@ static void do_smooth_brush_multires_task_cb_ex(void *__restrict userdata, vd.fno, smooth_mask ? 0.0f : (vd.mask ? *vd.mask : 0.0f), vd.index, - tls->thread_id); + thread_id); if (smooth_mask) { float val = SCULPT_neighbor_mask_average(ss, vd.index) - *vd.mask; val *= fade * bstrength; @@ -427,18 +432,18 @@ void SCULPT_smooth(Sculpt *sd, .strength = strength, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); switch (type) { case PBVH_GRIDS: - BKE_pbvh_parallel_range(0, totnode, &data, do_smooth_brush_multires_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_smooth_brush_multires_task_cb_ex, &settings); break; case PBVH_FACES: - BKE_pbvh_parallel_range(0, totnode, &data, do_smooth_brush_mesh_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_smooth_brush_mesh_task_cb_ex, &settings); break; case PBVH_BMESH: - BKE_pbvh_parallel_range(0, totnode, &data, do_smooth_brush_bmesh_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_smooth_brush_bmesh_task_cb_ex, &settings); break; } } @@ -512,6 +517,7 @@ static void SCULPT_do_surface_smooth_brush_laplacian_task_cb_ex( SculptBrushTest test; SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]); @@ -522,7 +528,7 @@ static void SCULPT_do_surface_smooth_brush_laplacian_task_cb_ex( const float fade = bstrength * SCULPT_brush_strength_factor( - ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, 0.0f, vd.index, tls->thread_id); + ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, 0.0f, vd.index, thread_id); float disp[3]; SCULPT_surface_smooth_laplacian_step(ss, @@ -555,6 +561,7 @@ static void SCULPT_do_surface_smooth_brush_displace_task_cb_ex( SculptBrushTest test; SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); BKE_pbvh_vertex_iter_begin(ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { @@ -562,7 +569,7 @@ static void SCULPT_do_surface_smooth_brush_displace_task_cb_ex( const float fade = bstrength * SCULPT_brush_strength_factor( - ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, 0.0f, vd.index, tls->thread_id); + ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, 0.0f, vd.index, thread_id); SCULPT_surface_smooth_displace_step( ss, vd.co, ss->cache->surface_smooth_laplacian_disp, vd.index, beta, fade); } @@ -590,12 +597,12 @@ void SCULPT_do_surface_smooth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, in .nodes = nodes, }; - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); for (int i = 0; i < brush->surface_smooth_iterations; i++) { - BKE_pbvh_parallel_range( + BLI_task_parallel_range( 0, totnode, &data, SCULPT_do_surface_smooth_brush_laplacian_task_cb_ex, &settings); - BKE_pbvh_parallel_range( + BLI_task_parallel_range( 0, totnode, &data, SCULPT_do_surface_smooth_brush_displace_task_cb_ex, &settings); } } diff --git a/source/blender/editors/sculpt_paint/sculpt_transform.c b/source/blender/editors/sculpt_paint/sculpt_transform.c index c7cbb6672a4..2eb1191b950 100644 --- a/source/blender/editors/sculpt_paint/sculpt_transform.c +++ b/source/blender/editors/sculpt_paint/sculpt_transform.c @@ -10,7 +10,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, + * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * The Original Code is Copyright (C) 2020 Blender Foundation. @@ -177,10 +177,10 @@ void ED_sculpt_update_modal_transform(struct bContext *C) mul_m4_m4m4(data.transform_mats[i], pivot_mat, data.transform_mats[i]); } - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings( &settings, (sd->flags & SCULPT_USE_OPENMP), ss->filter_cache->totnode); - BKE_pbvh_parallel_range( + BLI_task_parallel_range( 0, ss->filter_cache->totnode, &data, sculpt_transform_task_cb, &settings); if (ss->deform_modifiers_active || ss->shapekey_active) { diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c index 3d774350110..4a449e529d5 100644 --- a/source/blender/editors/sculpt_paint/sculpt_undo.c +++ b/source/blender/editors/sculpt_paint/sculpt_undo.c @@ -10,7 +10,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, + * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * The Original Code is Copyright (C) 2006 by Nicholas Bishop @@ -415,9 +415,9 @@ static void sculpt_undo_bmesh_restore_generic(bContext *C, BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode); - PBVHParallelSettings settings; + TaskParallelSettings settings; BKE_pbvh_parallel_range_settings(&settings, (sd->flags & SCULPT_USE_OPENMP), totnode); - BKE_pbvh_parallel_range( + BLI_task_parallel_range( 0, totnode, nodes, sculpt_undo_bmesh_restore_generic_task_cb, &settings); if (nodes) { @@ -914,7 +914,7 @@ static void sculpt_undo_alloc_and_store_hidden(PBVH *pbvh, SculptUndoNode *unode BKE_pbvh_node_get_grids(pbvh, node, &grid_indices, &totgrid, NULL, NULL, NULL); - unode->grid_hidden = MEM_mapallocN(sizeof(*unode->grid_hidden) * totgrid, "unode->grid_hidden"); + unode->grid_hidden = MEM_callocN(sizeof(*unode->grid_hidden) * totgrid, "unode->grid_hidden"); for (i = 0; i < totgrid; i++) { if (grid_hidden[grid_indices[i]]) { @@ -975,13 +975,11 @@ static SculptUndoNode *sculpt_undo_alloc_node(Object *ob, PBVHNode *node, Sculpt maxgrid = 0; } - /* We will use this while sculpting, is mapalloc slow to access then? */ - /* General TODO, fix count_alloc. */ switch (type) { case SCULPT_UNDO_COORDS: - unode->co = MEM_mapallocN(sizeof(float[3]) * allvert, "SculptUndoNode.co"); - unode->no = MEM_mapallocN(sizeof(short[3]) * allvert, "SculptUndoNode.no"); + unode->co = MEM_callocN(sizeof(float[3]) * allvert, "SculptUndoNode.co"); + unode->no = MEM_callocN(sizeof(short[3]) * allvert, "SculptUndoNode.no"); usculpt->undo_size = (sizeof(float[3]) + sizeof(short[3]) + sizeof(int)) * allvert; break; @@ -995,7 +993,7 @@ static SculptUndoNode *sculpt_undo_alloc_node(Object *ob, PBVHNode *node, Sculpt break; case SCULPT_UNDO_MASK: - unode->mask = MEM_mapallocN(sizeof(float) * allvert, "SculptUndoNode.mask"); + unode->mask = MEM_callocN(sizeof(float) * allvert, "SculptUndoNode.mask"); usculpt->undo_size += (sizeof(float) * sizeof(int)) * allvert; @@ -1014,12 +1012,12 @@ static SculptUndoNode *sculpt_undo_alloc_node(Object *ob, PBVHNode *node, Sculpt unode->maxgrid = maxgrid; unode->totgrid = totgrid; unode->gridsize = gridsize; - unode->grids = MEM_mapallocN(sizeof(int) * totgrid, "SculptUndoNode.grids"); + unode->grids = MEM_callocN(sizeof(int) * totgrid, "SculptUndoNode.grids"); } else { /* Regular mesh. */ unode->maxvert = ss->totvert; - unode->index = MEM_mapallocN(sizeof(int) * allvert, "SculptUndoNode.index"); + unode->index = MEM_callocN(sizeof(int) * allvert, "SculptUndoNode.index"); } if (ss->deform_modifiers_active) { diff --git a/source/blender/editors/sculpt_paint/sculpt_uv.c b/source/blender/editors/sculpt_paint/sculpt_uv.c index a81de36fbc4..d6b259c9ac0 100644 --- a/source/blender/editors/sculpt_paint/sculpt_uv.c +++ b/source/blender/editors/sculpt_paint/sculpt_uv.c @@ -10,7 +10,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, + * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * The Original Code is Copyright (C) Blender Foundation, 2002-2009 diff --git a/source/blender/editors/space_action/action_data.c b/source/blender/editors/space_action/action_data.c index a356962946e..b5a0c4a9e22 100644 --- a/source/blender/editors/space_action/action_data.c +++ b/source/blender/editors/space_action/action_data.c @@ -164,13 +164,13 @@ static void actedit_change_action(bContext *C, bAction *act) * 1) There must be an dopesheet/action editor, and it must be in a mode which uses actions... * OR * The NLA Editor is active (i.e. Animation Data panel -> new action) - * 2) The associated AnimData block must not be in tweakmode + * 2) The associated AnimData block must not be in tweak-mode. */ static bool action_new_poll(bContext *C) { Scene *scene = CTX_data_scene(C); - /* Check tweakmode is off (as you don't want to be tampering with the action in that case) */ + /* Check tweak-mode is off (as you don't want to be tampering with the action in that case) */ /* NOTE: unlike for pushdown, * this operator needs to be run when creating an action from nothing... */ if (ED_operator_action_active(C)) { @@ -300,7 +300,7 @@ void ACTION_OT_new(wmOperatorType *ot) /* Criteria: * 1) There must be an dopesheet/action editor, and it must be in a mode which uses actions * 2) There must be an action active - * 3) The associated AnimData block must not be in tweakmode + * 3) The associated AnimData block must not be in tweak-mode */ static bool action_pushdown_poll(bContext *C) { @@ -308,7 +308,7 @@ static bool action_pushdown_poll(bContext *C) SpaceAction *saction = (SpaceAction *)CTX_wm_space_data(C); AnimData *adt = ED_actedit_animdata_from_context(C); - /* Check for AnimData, Actions, and that tweakmode is off */ + /* Check for AnimData, Actions, and that tweak-mode is off. */ if (adt && saction->action) { /* NOTE: We check this for the AnimData block in question and not the global flag, * as the global flag may be left dirty by some of the browsing ops here. @@ -330,9 +330,8 @@ static int action_pushdown_exec(bContext *C, wmOperator *op) /* Do the deed... */ if (adt) { - /* Perform the pushdown operation - * - This will deal with all the AnimData-side usercounts - */ + /* Perform the push-down operation + * - This will deal with all the AnimData-side user-counts. */ if (action_has_motion(adt->action) == 0) { /* action may not be suitable... */ BKE_report(op->reports, RPT_WARNING, "Action must have at least one keyframe or F-Modifier"); @@ -389,7 +388,7 @@ static int action_stash_exec(bContext *C, wmOperator *op) if (BKE_nla_action_stash(adt)) { /* The stash operation will remove the user already, * so the flushing step later shouldn't double up - * the usercount fixes. Hence, we must unset this ref + * the user-count fixes. Hence, we must unset this ref * first before setting the new action. */ saction->action = NULL; @@ -435,14 +434,14 @@ void ACTION_OT_stash(wmOperatorType *ot) /* Criteria: * 1) There must be an dopesheet/action editor, and it must be in a mode which uses actions - * 2) The associated AnimData block must not be in tweakmode + * 2) The associated AnimData block must not be in tweak-mode */ static bool action_stash_create_poll(bContext *C) { if (ED_operator_action_active(C)) { AnimData *adt = ED_actedit_animdata_from_context(C); - /* Check tweakmode is off (as you don't want to be tampering with the action in that case) */ + /* Check tweak-mode is off (as you don't want to be tampering with the action in that case) */ /* NOTE: unlike for pushdown, * this operator needs to be run when creating an action from nothing... */ if (adt) { @@ -498,7 +497,7 @@ static int action_stash_create_exec(bContext *C, wmOperator *op) /* The stash operation will remove the user already, * so the flushing step later shouldn't double up - * the usercount fixes. Hence, we must unset this ref + * the user-count fixes. Hence, we must unset this ref * first before setting the new action. */ saction->action = NULL; @@ -728,8 +727,8 @@ static NlaStrip *action_layer_get_nlastrip(ListBase *strips, float ctime) static void action_layer_switch_strip( AnimData *adt, NlaTrack *old_track, NlaStrip *old_strip, NlaTrack *nlt, NlaStrip *strip) { - /* Exit tweakmode on old strip - * NOTE: We need to manually clear this stuff ourselves, as tweakmode exit doesn't do it + /* Exit tweak-mode on old strip + * NOTE: We need to manually clear this stuff ourselves, as tweak-mode exit doesn't do it */ BKE_nla_tweakmode_exit(adt); @@ -761,11 +760,11 @@ static void action_layer_switch_strip( adt->flag |= ADT_NLA_SOLO_TRACK; nlt->flag |= NLATRACK_SOLO; - // TODO: Needs restpose flushing (when we get reference track) + // TODO: Needs rest-pose flushing (when we get reference track) } } - /* Enter tweakmode again - hopefully we're now "it" */ + /* Enter tweak-mode again - hopefully we're now "it" */ BKE_nla_tweakmode_enter(adt); BLI_assert(adt->actstrip == strip); } @@ -778,7 +777,7 @@ static bool action_layer_next_poll(bContext *C) if (ED_operator_action_active(C)) { AnimData *adt = ED_actedit_animdata_from_context(C); if (adt) { - /* only allow if we're in tweakmode, and there's something above us... */ + /* only allow if we're in tweak-mode, and there's something above us... */ if (adt->flag & ADT_NLA_EDIT_ON) { /* We need to check if there are any tracks above the active one * since the track the action comes from is not stored in AnimData @@ -840,7 +839,7 @@ static int action_layer_next_exec(bContext *C, wmOperator *op) } else { /* No more actions (strips) - Go back to editing the original active action - * NOTE: This will mean exiting tweakmode... + * NOTE: This will mean exiting tweak-mode... */ BKE_nla_tweakmode_exit(adt); @@ -855,13 +854,12 @@ static int action_layer_next_exec(bContext *C, wmOperator *op) /* turn on NLA muting (to keep same effect) */ adt->flag |= ADT_NLA_EVAL_OFF; - // TODO: Needs restpose flushing (when we get reference track) + // TODO: Needs rest-pose flushing (when we get reference track) } } /* Update the action that this editor now uses - * NOTE: The calls above have already handled the usercount/animdata side of things - */ + * NOTE: The calls above have already handled the user-count/anim-data side of things. */ actedit_change_action(C, adt->action); return OPERATOR_FINISHED; } @@ -960,8 +958,7 @@ static int action_layer_prev_exec(bContext *C, wmOperator *op) } /* Update the action that this editor now uses - * NOTE: The calls above have already handled the usercount/animdata side of things - */ + * NOTE: The calls above have already handled the user-count/animdata side of things. */ actedit_change_action(C, adt->action); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/space_action/action_edit.c b/source/blender/editors/space_action/action_edit.c index 927e51a3e04..e90122f2585 100644 --- a/source/blender/editors/space_action/action_edit.c +++ b/source/blender/editors/space_action/action_edit.c @@ -313,8 +313,8 @@ void ACTION_OT_previewrange_set(wmOperatorType *ot) /** * Find the extents of the active channel * - * \param[out] min Bottom y-extent of channel - * \param[out] max Top y-extent of channel + * \param[out] min: Bottom y-extent of channel + * \param[out] max: Top y-extent of channel * \return Success of finding a selected channel */ static bool actkeys_channels_get_selected_extents(bAnimContext *ac, float *min, float *max) @@ -448,7 +448,7 @@ static int actkeys_viewsel_exec(bContext *C, wmOperator *UNUSED(op)) void ACTION_OT_view_all(wmOperatorType *ot) { /* identifiers */ - ot->name = "View All"; + ot->name = "Frame All"; ot->idname = "ACTION_OT_view_all"; ot->description = "Reset viewable area to show full keyframe range"; diff --git a/source/blender/editors/space_action/action_select.c b/source/blender/editors/space_action/action_select.c index 26c29d6cbe7..bbb68f632fb 100644 --- a/source/blender/editors/space_action/action_select.c +++ b/source/blender/editors/space_action/action_select.c @@ -793,8 +793,8 @@ static int actkeys_lassoselect_exec(bContext *C, wmOperator *op) } data_lasso.rectf_view = &rect_fl; - data_lasso.mcords = WM_gesture_lasso_path_to_array(C, op, &data_lasso.mcords_tot); - if (data_lasso.mcords == NULL) { + data_lasso.mcoords = WM_gesture_lasso_path_to_array(C, op, &data_lasso.mcoords_len); + if (data_lasso.mcoords == NULL) { return OPERATOR_CANCELLED; } @@ -805,13 +805,13 @@ static int actkeys_lassoselect_exec(bContext *C, wmOperator *op) } /* get settings from operator */ - BLI_lasso_boundbox(&rect, data_lasso.mcords, data_lasso.mcords_tot); + BLI_lasso_boundbox(&rect, data_lasso.mcoords, data_lasso.mcoords_len); BLI_rctf_rcti_copy(&rect_fl, &rect); /* apply box_select action */ region_select_action_keys(&ac, &rect_fl, BEZT_OK_CHANNEL_LASSO, selectmode, &data_lasso); - MEM_freeN((void *)data_lasso.mcords); + MEM_freeN((void *)data_lasso.mcoords); /* send notifier that keyframe selection has changed */ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); diff --git a/source/blender/editors/space_buttons/buttons_context.c b/source/blender/editors/space_buttons/buttons_context.c index 587ba5b0b79..7e6088bc3cc 100644 --- a/source/blender/editors/space_buttons/buttons_context.c +++ b/source/blender/editors/space_buttons/buttons_context.c @@ -1041,7 +1041,7 @@ int buttons_context(const bContext *C, const char *member, bContextDataResult *r if (ptr && ptr->data) { Object *ob = ptr->data; - ModifierData *md = modifiers_findByType(ob, eModifierType_Cloth); + ModifierData *md = BKE_modifiers_findby_type(ob, eModifierType_Cloth); CTX_data_pointer_set(result, &ob->id, &RNA_ClothModifier, md); return 1; } @@ -1051,7 +1051,7 @@ int buttons_context(const bContext *C, const char *member, bContextDataResult *r if (ptr && ptr->data) { Object *ob = ptr->data; - ModifierData *md = modifiers_findByType(ob, eModifierType_Softbody); + ModifierData *md = BKE_modifiers_findby_type(ob, eModifierType_Softbody); CTX_data_pointer_set(result, &ob->id, &RNA_SoftBodyModifier, md); return 1; } @@ -1062,7 +1062,7 @@ int buttons_context(const bContext *C, const char *member, bContextDataResult *r if (ptr && ptr->data) { Object *ob = ptr->data; - ModifierData *md = modifiers_findByType(ob, eModifierType_Fluid); + ModifierData *md = BKE_modifiers_findby_type(ob, eModifierType_Fluid); CTX_data_pointer_set(result, &ob->id, &RNA_FluidModifier, md); return 1; } @@ -1072,7 +1072,7 @@ int buttons_context(const bContext *C, const char *member, bContextDataResult *r if (ptr && ptr->data) { Object *ob = ptr->data; - ModifierData *md = modifiers_findByType(ob, eModifierType_Collision); + ModifierData *md = BKE_modifiers_findby_type(ob, eModifierType_Collision); CTX_data_pointer_set(result, &ob->id, &RNA_CollisionModifier, md); return 1; } @@ -1086,7 +1086,7 @@ int buttons_context(const bContext *C, const char *member, bContextDataResult *r if (ptr && ptr->data) { Object *ob = ptr->data; - ModifierData *md = modifiers_findByType(ob, eModifierType_DynamicPaint); + ModifierData *md = BKE_modifiers_findby_type(ob, eModifierType_DynamicPaint); CTX_data_pointer_set(result, &ob->id, &RNA_DynamicPaintModifier, md); return 1; } diff --git a/source/blender/editors/space_buttons/buttons_texture.c b/source/blender/editors/space_buttons/buttons_texture.c index 00818ac77b5..6b7f86a9143 100644 --- a/source/blender/editors/space_buttons/buttons_texture.c +++ b/source/blender/editors/space_buttons/buttons_texture.c @@ -236,10 +236,10 @@ static void buttons_texture_users_from_context(ListBase *users, int a; /* modifiers */ - modifiers_foreachTexLink(ob, buttons_texture_modifier_foreach, users); + BKE_modifiers_foreach_tex_link(ob, buttons_texture_modifier_foreach, users); /* grease pencil modifiers */ - BKE_gpencil_modifiers_foreachTexLink(ob, buttons_texture_modifier_gpencil_foreach, users); + BKE_gpencil_modifiers_foreach_tex_link(ob, buttons_texture_modifier_gpencil_foreach, users); /* particle systems */ if (psys && !limited_mode) { diff --git a/source/blender/editors/space_clip/clip_dopesheet_ops.c b/source/blender/editors/space_clip/clip_dopesheet_ops.c index cd95a00c62a..c3323491085 100644 --- a/source/blender/editors/space_clip/clip_dopesheet_ops.c +++ b/source/blender/editors/space_clip/clip_dopesheet_ops.c @@ -204,7 +204,7 @@ static int dopesheet_view_all_exec(bContext *C, wmOperator *UNUSED(op)) void CLIP_OT_dopesheet_view_all(wmOperatorType *ot) { /* identifiers */ - ot->name = "View All"; + ot->name = "Frame All"; ot->description = "Reset viewable area to show full keyframe range"; ot->idname = "CLIP_OT_dopesheet_view_all"; diff --git a/source/blender/editors/space_clip/clip_draw.c b/source/blender/editors/space_clip/clip_draw.c index a1652ca0e88..fe7ae7096a0 100644 --- a/source/blender/editors/space_clip/clip_draw.c +++ b/source/blender/editors/space_clip/clip_draw.c @@ -1651,7 +1651,7 @@ static void draw_tracking_tracks(SpaceClip *sc, pos[0] = (pos[0] / (pos[3] * 2.0f) + 0.5f) * width; pos[1] = (pos[1] / (pos[3] * 2.0f) + 0.5f) * height * aspy; - BKE_tracking_distort_v2(tracking, pos, npos); + BKE_tracking_distort_v2(tracking, width, height, pos, npos); if (npos[0] >= 0.0f && npos[1] >= 0.0f && npos[0] <= width && npos[1] <= height * aspy) { vec[0] = (marker->pos[0] + track->offset[0]) * width; @@ -1730,8 +1730,7 @@ static void draw_distortion(SpaceClip *sc, { float x, y; const int n = 10; - int i, j, a; - float pos[2], tpos[2], grid[11][11][2]; + float tpos[2], grid[11][11][2]; MovieTracking *tracking = &clip->tracking; bGPdata *gpd = NULL; float aspy = 1.0f / tracking->camera.pixel_aspect; @@ -1764,7 +1763,7 @@ static void draw_distortion(SpaceClip *sc, float val[4][2], idx[4][2]; float min[2], max[2]; - for (a = 0; a < 4; a++) { + for (int a = 0; a < 4; a++) { if (a < 2) { val[a][a % 2] = FLT_MAX; } @@ -1773,13 +1772,13 @@ static void draw_distortion(SpaceClip *sc, } } - zero_v2(pos); - for (i = 0; i <= n; i++) { - for (j = 0; j <= n; j++) { + for (int i = 0; i <= n; i++) { + for (int j = 0; j <= n; j++) { if (i == 0 || j == 0 || i == n || j == n) { - BKE_tracking_distort_v2(tracking, pos, tpos); + const float pos[2] = {dx * j, dy * i}; + BKE_tracking_distort_v2(tracking, width, height, pos, tpos); - for (a = 0; a < 4; a++) { + for (int a = 0; a < 4; a++) { int ok; if (a < 2) { @@ -1796,59 +1795,49 @@ static void draw_distortion(SpaceClip *sc, } } } - - pos[0] += dx; } - - pos[0] = 0.0f; - pos[1] += dy; } INIT_MINMAX2(min, max); - for (a = 0; a < 4; a++) { - pos[0] = idx[a][0] * dx; - pos[1] = idx[a][1] * dy; + for (int a = 0; a < 4; a++) { + const float pos[2] = {idx[a][0] * dx, idx[a][1] * dy}; - BKE_tracking_undistort_v2(tracking, pos, tpos); + BKE_tracking_undistort_v2(tracking, width, height, pos, tpos); minmax_v2v2_v2(min, max, tpos); } - copy_v2_v2(pos, min); dx = (max[0] - min[0]) / n; dy = (max[1] - min[1]) / n; - for (i = 0; i <= n; i++) { - for (j = 0; j <= n; j++) { - BKE_tracking_distort_v2(tracking, pos, grid[i][j]); + for (int i = 0; i <= n; i++) { + for (int j = 0; j <= n; j++) { + const float pos[2] = {min[0] + dx * j, min[1] + dy * i}; + + BKE_tracking_distort_v2(tracking, width, height, pos, grid[i][j]); grid[i][j][0] /= width; grid[i][j][1] /= height * aspy; - - pos[0] += dx; } - - pos[0] = min[0]; - pos[1] += dy; } immUniformColor3f(1.0f, 0.0f, 0.0f); - for (i = 0; i <= n; i++) { + for (int i = 0; i <= n; i++) { immBegin(GPU_PRIM_LINE_STRIP, n + 1); - for (j = 0; j <= n; j++) { + for (int j = 0; j <= n; j++) { immVertex2fv(position, grid[i][j]); } immEnd(); } - for (j = 0; j <= n; j++) { + for (int j = 0; j <= n; j++) { immBegin(GPU_PRIM_LINE_STRIP, n + 1); - for (i = 0; i <= n; i++) { + for (int i = 0; i <= n; i++) { immVertex2fv(position, grid[i][j]); } @@ -1882,8 +1871,8 @@ static void draw_distortion(SpaceClip *sc, while (stroke) { if (stroke->flag & GP_STROKE_2DSPACE) { if (stroke->totpoints > 1) { - for (i = 0; i < stroke->totpoints - 1; i++) { - float npos[2], dpos[2], len; + for (int i = 0; i < stroke->totpoints - 1; i++) { + float pos[2], npos[2], dpos[2], len; int steps; pos[0] = (stroke->points[i].x + offsx) * width; @@ -1897,8 +1886,8 @@ static void draw_distortion(SpaceClip *sc, /* we want to distort only long straight lines */ if (stroke->totpoints == 2) { - BKE_tracking_undistort_v2(tracking, pos, pos); - BKE_tracking_undistort_v2(tracking, npos, npos); + BKE_tracking_undistort_v2(tracking, width, height, pos, pos); + BKE_tracking_undistort_v2(tracking, width, height, npos, npos); } sub_v2_v2v2(dpos, npos, pos); @@ -1906,8 +1895,8 @@ static void draw_distortion(SpaceClip *sc, immBegin(GPU_PRIM_LINE_STRIP, steps + 1); - for (j = 0; j <= steps; j++) { - BKE_tracking_distort_v2(tracking, pos, tpos); + for (int j = 0; j <= steps; j++) { + BKE_tracking_distort_v2(tracking, width, height, pos, tpos); immVertex2f(position, tpos[0] / width, tpos[1] / (height * aspy)); add_v2_v2(pos, dpos); diff --git a/source/blender/editors/space_clip/clip_editor.c b/source/blender/editors/space_clip/clip_editor.c index cce01947ab7..5be4b2d5df0 100644 --- a/source/blender/editors/space_clip/clip_editor.c +++ b/source/blender/editors/space_clip/clip_editor.c @@ -546,7 +546,7 @@ void ED_clip_point_undistorted_pos(SpaceClip *sc, const float co[2], float r_co[ r_co[0] *= width; r_co[1] *= height * aspy; - BKE_tracking_undistort_v2(&clip->tracking, r_co, r_co); + BKE_tracking_undistort_v2(&clip->tracking, width, height, r_co, r_co); r_co[0] /= width; r_co[1] /= height * aspy; @@ -580,7 +580,7 @@ void ED_clip_point_stable_pos( float aspy = 1.0f / tracking->camera.pixel_aspect; float tmp[2] = {*xr * width, *yr * height * aspy}; - BKE_tracking_distort_v2(tracking, tmp, tmp); + BKE_tracking_distort_v2(tracking, width, height, tmp, tmp); *xr = tmp[0] / width; *yr = tmp[1] / (height * aspy); @@ -885,9 +885,9 @@ static uchar *prefetch_thread_next_frame(PrefetchQueue *queue, return mem; } -static void prefetch_task_func(TaskPool *__restrict pool, void *task_data, int UNUSED(threadid)) +static void prefetch_task_func(TaskPool *__restrict pool, void *task_data) { - PrefetchQueue *queue = (PrefetchQueue *)BLI_task_pool_userdata(pool); + PrefetchQueue *queue = (PrefetchQueue *)BLI_task_pool_user_data(pool); MovieClip *clip = (MovieClip *)task_data; uchar *mem; size_t size; @@ -942,9 +942,8 @@ static void start_prefetch_threads(MovieClip *clip, float *progress) { PrefetchQueue queue; - TaskScheduler *task_scheduler = BLI_task_scheduler_get(); TaskPool *task_pool; - int i, tot_thread = BLI_task_scheduler_num_threads(task_scheduler); + int i, tot_thread = BLI_task_scheduler_num_threads(); /* initialize queue */ BLI_spin_init(&queue.spin); @@ -961,7 +960,7 @@ static void start_prefetch_threads(MovieClip *clip, queue.do_update = do_update; queue.progress = progress; - task_pool = BLI_task_pool_create(task_scheduler, &queue, TASK_PRIORITY_LOW); + task_pool = BLI_task_pool_create(&queue, TASK_PRIORITY_LOW); for (i = 0; i < tot_thread; i++) { BLI_task_pool_push(task_pool, prefetch_task_func, clip, false, NULL); } diff --git a/source/blender/editors/space_clip/clip_graph_draw.c b/source/blender/editors/space_clip/clip_graph_draw.c index dc212741e6b..277930495bd 100644 --- a/source/blender/editors/space_clip/clip_graph_draw.c +++ b/source/blender/editors/space_clip/clip_graph_draw.c @@ -220,31 +220,46 @@ static void draw_frame_curves(SpaceClip *sc, uint pos) MovieClip *clip = ED_space_clip_get_clip(sc); MovieTracking *tracking = &clip->tracking; MovieTrackingReconstruction *reconstruction = BKE_tracking_get_active_reconstruction(tracking); - int i, lines = 0, prevfra = 0; + + int previous_frame; + float previous_error; + bool have_previous_point = false; + + /* Indicates whether immBegin() was called. */ + bool is_lines_segment_open = false; immUniformColor3f(0.0f, 0.0f, 1.0f); - for (i = 0; i < reconstruction->camnr; i++) { + for (int i = 0; i < reconstruction->camnr; i++) { MovieReconstructedCamera *camera = &reconstruction->cameras[i]; - int framenr; - if (lines && camera->framenr != prevfra + 1) { - immEnd(); - lines = 0; - } + const int current_frame = BKE_movieclip_remap_clip_to_scene_frame(clip, camera->framenr); + const float current_error = camera->error; - if (!lines) { - immBeginAtMost(GPU_PRIM_LINE_STRIP, reconstruction->camnr); - lines = 1; + if (have_previous_point && current_frame != previous_frame + 1) { + if (is_lines_segment_open) { + immEnd(); + is_lines_segment_open = false; + } + have_previous_point = false; } - framenr = BKE_movieclip_remap_clip_to_scene_frame(clip, camera->framenr); - immVertex2f(pos, framenr, camera->error); + if (have_previous_point) { + if (!is_lines_segment_open) { + immBeginAtMost(GPU_PRIM_LINE_STRIP, reconstruction->camnr); + is_lines_segment_open = true; + + immVertex2f(pos, previous_frame, previous_error); + } + immVertex2f(pos, current_frame, current_error); + } - prevfra = camera->framenr; + previous_frame = current_frame; + previous_error = current_error; + have_previous_point = true; } - if (lines) { + if (is_lines_segment_open) { immEnd(); } } diff --git a/source/blender/editors/space_clip/clip_graph_ops.c b/source/blender/editors/space_clip/clip_graph_ops.c index e974480a233..589831b1c45 100644 --- a/source/blender/editors/space_clip/clip_graph_ops.c +++ b/source/blender/editors/space_clip/clip_graph_ops.c @@ -671,7 +671,7 @@ static int view_all_exec(bContext *C, wmOperator *UNUSED(op)) void CLIP_OT_graph_view_all(wmOperatorType *ot) { /* identifiers */ - ot->name = "View All"; + ot->name = "Frame All"; ot->description = "View all curves in editor"; ot->idname = "CLIP_OT_graph_view_all"; diff --git a/source/blender/editors/space_clip/clip_ops.c b/source/blender/editors/space_clip/clip_ops.c index 3204374b747..984aa0a63ad 100644 --- a/source/blender/editors/space_clip/clip_ops.c +++ b/source/blender/editors/space_clip/clip_ops.c @@ -784,7 +784,7 @@ void CLIP_OT_view_zoom_in(wmOperatorType *ot) PropertyRNA *prop; /* identifiers */ - ot->name = "View Zoom In"; + ot->name = "Zoom In"; ot->idname = "CLIP_OT_view_zoom_in"; ot->description = "Zoom in the view"; @@ -841,7 +841,7 @@ void CLIP_OT_view_zoom_out(wmOperatorType *ot) PropertyRNA *prop; /* identifiers */ - ot->name = "View Zoom Out"; + ot->name = "Zoom Out"; ot->idname = "CLIP_OT_view_zoom_out"; ot->description = "Zoom out the view"; @@ -975,7 +975,7 @@ void CLIP_OT_view_all(wmOperatorType *ot) PropertyRNA *prop; /* identifiers */ - ot->name = "View All"; + ot->name = "Frame All"; ot->idname = "CLIP_OT_view_all"; ot->description = "View whole image with markers"; @@ -1367,10 +1367,10 @@ static uchar *proxy_thread_next_frame(ProxyQueue *queue, return mem; } -static void proxy_task_func(TaskPool *__restrict pool, void *task_data, int UNUSED(threadid)) +static void proxy_task_func(TaskPool *__restrict pool, void *task_data) { ProxyThread *data = (ProxyThread *)task_data; - ProxyQueue *queue = (ProxyQueue *)BLI_task_pool_userdata(pool); + ProxyQueue *queue = (ProxyQueue *)BLI_task_pool_user_data(pool); uchar *mem; size_t size; int cfra; @@ -1413,11 +1413,10 @@ static void do_sequence_proxy(void *pjv, ProxyJob *pj = pjv; MovieClip *clip = pj->clip; Scene *scene = pj->scene; - TaskScheduler *task_scheduler = BLI_task_scheduler_get(); TaskPool *task_pool; int sfra = SFRA, efra = EFRA; ProxyThread *handles; - int i, tot_thread = BLI_task_scheduler_num_threads(task_scheduler); + int i, tot_thread = BLI_task_scheduler_num_threads(); int width, height; ProxyQueue queue; @@ -1434,7 +1433,7 @@ static void do_sequence_proxy(void *pjv, queue.do_update = do_update; queue.progress = progress; - task_pool = BLI_task_pool_create(task_scheduler, &queue, TASK_PRIORITY_LOW); + task_pool = BLI_task_pool_create(&queue, TASK_PRIORITY_LOW); handles = MEM_callocN(sizeof(ProxyThread) * tot_thread, "proxy threaded handles"); for (i = 0; i < tot_thread; i++) { ProxyThread *handle = &handles[i]; diff --git a/source/blender/editors/space_clip/clip_utils.c b/source/blender/editors/space_clip/clip_utils.c index 4a0df454a78..03f791ad70d 100644 --- a/source/blender/editors/space_clip/clip_utils.c +++ b/source/blender/editors/space_clip/clip_utils.c @@ -166,7 +166,8 @@ static float calculate_reprojection_error_at_marker(MovieClip *clip, reprojected_position[1] = (reprojected_position[1] / (reprojected_position[3] * 2.0f) + 0.5f) * clip_height * aspy; - BKE_tracking_distort_v2(tracking, reprojected_position, reprojected_position); + BKE_tracking_distort_v2( + tracking, clip_width, clip_height, reprojected_position, reprojected_position); marker_position[0] = (marker->pos[0] + track->offset[0]) * clip_width; marker_position[1] = (marker->pos[1] + track->offset[1]) * clip_height * aspy; diff --git a/source/blender/editors/space_clip/tracking_select.c b/source/blender/editors/space_clip/tracking_select.c index c2a4ebdfc63..81cc858c69f 100644 --- a/source/blender/editors/space_clip/tracking_select.c +++ b/source/blender/editors/space_clip/tracking_select.c @@ -598,8 +598,8 @@ void CLIP_OT_select_box(wmOperatorType *ot) /********************** lasso select operator *********************/ static int do_lasso_select_marker(bContext *C, - const int mcords[][2], - const short moves, + const int mcoords[][2], + const int mcoords_len, bool select) { SpaceClip *sc = CTX_wm_space_clip(C); @@ -616,7 +616,7 @@ static int do_lasso_select_marker(bContext *C, int framenr = ED_space_clip_get_clip_frame_number(sc); /* get rectangle from operator */ - BLI_lasso_boundbox(&rect, mcords, moves); + BLI_lasso_boundbox(&rect, mcoords, mcoords_len); /* do actual selection */ track = tracksbase->first; @@ -631,7 +631,8 @@ static int do_lasso_select_marker(bContext *C, ED_clip_point_stable_pos__reverse(sc, region, marker->pos, screen_co); if (BLI_rcti_isect_pt(&rect, screen_co[0], screen_co[1]) && - BLI_lasso_is_point_inside(mcords, moves, screen_co[0], screen_co[1], V2D_IS_CLIPPED)) { + BLI_lasso_is_point_inside( + mcoords, mcoords_len, screen_co[0], screen_co[1], V2D_IS_CLIPPED)) { if (select) { BKE_tracking_track_flag_set(track, TRACK_AREA_ALL, SELECT); } @@ -659,7 +660,8 @@ static int do_lasso_select_marker(bContext *C, ED_clip_point_stable_pos__reverse(sc, region, plane_marker->corners[i], screen_co); if (BLI_rcti_isect_pt(&rect, screen_co[0], screen_co[1]) && - BLI_lasso_is_point_inside(mcords, moves, screen_co[0], screen_co[1], V2D_IS_CLIPPED)) { + BLI_lasso_is_point_inside( + mcoords, mcoords_len, screen_co[0], screen_co[1], V2D_IS_CLIPPED)) { if (select) { plane_track->flag |= SELECT; } @@ -685,10 +687,10 @@ static int do_lasso_select_marker(bContext *C, static int clip_lasso_select_exec(bContext *C, wmOperator *op) { - int mcords_tot; - const int(*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot); + int mcoords_len; + const int(*mcoords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcoords_len); - if (mcords) { + if (mcoords) { const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode"); const bool select = (sel_op != SEL_OP_SUB); if (SEL_OP_USE_PRE_DESELECT(sel_op)) { @@ -696,9 +698,9 @@ static int clip_lasso_select_exec(bContext *C, wmOperator *op) ED_clip_select_all(sc, SEL_DESELECT, NULL); } - do_lasso_select_marker(C, mcords, mcords_tot, select); + do_lasso_select_marker(C, mcoords, mcoords_len, select); - MEM_freeN((void *)mcords); + MEM_freeN((void *)mcoords); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c index ac8fa413f07..7f6d0658ec8 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -1264,11 +1264,9 @@ static void filelist_intern_free(FileListIntern *filelist_intern) MEM_SAFE_FREE(filelist_intern->filtered); } -static void filelist_cache_preview_runf(TaskPool *__restrict pool, - void *taskdata, - int UNUSED(threadid)) +static void filelist_cache_preview_runf(TaskPool *__restrict pool, void *taskdata) { - FileListEntryCache *cache = BLI_task_pool_userdata(pool); + FileListEntryCache *cache = BLI_task_pool_user_data(pool); FileListEntryPreviewTaskData *preview_taskdata = taskdata; FileListEntryPreview *preview = preview_taskdata->preview; @@ -1306,9 +1304,7 @@ static void filelist_cache_preview_runf(TaskPool *__restrict pool, // printf("%s: End (%d)...\n", __func__, threadid); } -static void filelist_cache_preview_freef(TaskPool *__restrict UNUSED(pool), - void *taskdata, - int UNUSED(threadid)) +static void filelist_cache_preview_freef(TaskPool *__restrict UNUSED(pool), void *taskdata) { FileListEntryPreviewTaskData *preview_taskdata = taskdata; FileListEntryPreview *preview = preview_taskdata->preview; @@ -1327,9 +1323,7 @@ static void filelist_cache_preview_freef(TaskPool *__restrict UNUSED(pool), static void filelist_cache_preview_ensure_running(FileListEntryCache *cache) { if (!cache->previews_pool) { - TaskScheduler *scheduler = BLI_task_scheduler_get(); - - cache->previews_pool = BLI_task_pool_create_background(scheduler, cache, TASK_PRIORITY_LOW); + cache->previews_pool = BLI_task_pool_create_background(cache, TASK_PRIORITY_LOW); cache->previews_done = BLI_thread_queue_init(); IMB_thumb_locks_acquire(); diff --git a/source/blender/editors/space_graph/graph_buttons.c b/source/blender/editors/space_graph/graph_buttons.c index d1feab6f24b..185bf029f1a 100644 --- a/source/blender/editors/space_graph/graph_buttons.c +++ b/source/blender/editors/space_graph/graph_buttons.c @@ -42,6 +42,7 @@ #include "BKE_context.h" #include "BKE_curve.h" #include "BKE_fcurve.h" +#include "BKE_fcurve_driver.h" #include "BKE_global.h" #include "BKE_main.h" #include "BKE_screen.h" @@ -422,8 +423,7 @@ static void graph_panel_key_properties(const bContext *C, Panel *panel) col = uiLayoutColumn(layout, true); /* keyframe itself */ { - - uiItemL_respect_property_split(col, IFACE_("Key Value"), ICON_NONE); + uiItemL_respect_property_split(col, IFACE_("Key Frame"), ICON_NONE); but = uiDefButR(block, UI_BTYPE_NUM, B_REDR, @@ -434,16 +434,14 @@ static void graph_panel_key_properties(const bContext *C, Panel *panel) UI_UNIT_Y, &bezt_ptr, "co", - 1, + 0, 0, 0, -1, -1, NULL); - UI_but_func_set(but, graphedit_activekey_update_cb, fcu, bezt); - UI_but_unit_type_set(but, unit); - uiItemL_respect_property_split(col, IFACE_("Frame"), ICON_NONE); + uiItemL_respect_property_split(col, IFACE_("Value"), ICON_NONE); but = uiDefButR(block, UI_BTYPE_NUM, B_REDR, @@ -454,21 +452,42 @@ static void graph_panel_key_properties(const bContext *C, Panel *panel) UI_UNIT_Y, &bezt_ptr, "co", - 0, + 1, 0, 0, -1, -1, NULL); UI_but_func_set(but, graphedit_activekey_update_cb, fcu, bezt); + UI_but_unit_type_set(but, unit); + + UI_but_func_set(but, graphedit_activekey_update_cb, fcu, bezt); } /* previous handle - only if previous was Bezier interpolation */ if ((prevbezt) && (prevbezt->ipo == BEZT_IPO_BEZ)) { col = uiLayoutColumn(layout, true); + uiItemL_respect_property_split(col, IFACE_("Left Handle Type"), ICON_NONE); + but = uiDefButR(block, + UI_BTYPE_MENU, + B_REDR, + NULL, + 0, + 0, + but_max_width, + UI_UNIT_Y, + &bezt_ptr, + "handle_left_type", + 0, + 0, + 0, + -1, + -1, + "Type of left handle"); + UI_but_func_set(but, graphedit_activekey_handles_cb, fcu, bezt); - uiItemL_respect_property_split(col, IFACE_("Left Handle X"), ICON_NONE); + uiItemL_respect_property_split(col, IFACE_("Frame"), ICON_NONE); but = uiDefButR(block, UI_BTYPE_NUM, B_REDR, @@ -487,7 +506,7 @@ static void graph_panel_key_properties(const bContext *C, Panel *panel) NULL); UI_but_func_set(but, graphedit_activekey_left_handle_coord_cb, fcu, bezt); - uiItemL_respect_property_split(col, IFACE_("Y"), ICON_NONE); + uiItemL_respect_property_split(col, IFACE_("Value"), ICON_NONE); but = uiDefButR(block, UI_BTYPE_NUM, B_REDR, @@ -506,8 +525,14 @@ static void graph_panel_key_properties(const bContext *C, Panel *panel) NULL); UI_but_func_set(but, graphedit_activekey_left_handle_coord_cb, fcu, bezt); UI_but_unit_type_set(but, unit); + } + + /* next handle - only if current is Bezier interpolation */ + if (bezt->ipo == BEZT_IPO_BEZ) { + /* NOTE: special update callbacks are needed on the coords here due to T39911 */ - uiItemL_respect_property_split(col, IFACE_("Type"), ICON_NONE); + col = uiLayoutColumn(layout, true); + uiItemL_respect_property_split(col, IFACE_("Right Handle Type"), ICON_NONE); but = uiDefButR(block, UI_BTYPE_MENU, B_REDR, @@ -517,22 +542,16 @@ static void graph_panel_key_properties(const bContext *C, Panel *panel) but_max_width, UI_UNIT_Y, &bezt_ptr, - "handle_left_type", + "handle_right_type", 0, 0, 0, -1, -1, - "Type of left handle"); + "Type of right handle"); UI_but_func_set(but, graphedit_activekey_handles_cb, fcu, bezt); - } - /* next handle - only if current is Bezier interpolation */ - if (bezt->ipo == BEZT_IPO_BEZ) { - /* NOTE: special update callbacks are needed on the coords here due to T39911 */ - - col = uiLayoutColumn(layout, true); - uiItemL_respect_property_split(col, IFACE_("Right Handle X"), ICON_NONE); + uiItemL_respect_property_split(col, IFACE_("Frame"), ICON_NONE); but = uiDefButR(block, UI_BTYPE_NUM, B_REDR, @@ -551,7 +570,7 @@ static void graph_panel_key_properties(const bContext *C, Panel *panel) NULL); UI_but_func_set(but, graphedit_activekey_right_handle_coord_cb, fcu, bezt); - uiItemL_respect_property_split(col, IFACE_("Y"), ICON_NONE); + uiItemL_respect_property_split(col, IFACE_("Value"), ICON_NONE); but = uiDefButR(block, UI_BTYPE_NUM, B_REDR, @@ -570,25 +589,6 @@ static void graph_panel_key_properties(const bContext *C, Panel *panel) NULL); UI_but_func_set(but, graphedit_activekey_right_handle_coord_cb, fcu, bezt); UI_but_unit_type_set(but, unit); - - uiItemL_respect_property_split(col, IFACE_("Type"), ICON_NONE); - but = uiDefButR(block, - UI_BTYPE_MENU, - B_REDR, - NULL, - 0, - 0, - but_max_width, - UI_UNIT_Y, - &bezt_ptr, - "handle_right_type", - 0, - 0, - 0, - -1, - -1, - "Type of right handle"); - UI_but_func_set(but, graphedit_activekey_handles_cb, fcu, bezt); } } else { diff --git a/source/blender/editors/space_graph/graph_draw.c b/source/blender/editors/space_graph/graph_draw.c index eac87caf777..68fef5e921f 100644 --- a/source/blender/editors/space_graph/graph_draw.c +++ b/source/blender/editors/space_graph/graph_draw.c @@ -343,6 +343,10 @@ static void draw_fcurve_handles(SpaceGraph *sipo, FCurve *fcu) uint color = GPU_vertformat_attr_add( format, "color", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); immBindBuiltinProgram(GPU_SHADER_2D_FLAT_COLOR); + if ((sipo->flag & SIPO_BEAUTYDRAW_OFF) == 0) { + GPU_line_smooth(true); + } + GPU_blend(true); immBeginAtMost(GPU_PRIM_LINES, 4 * 2 * fcu->totvert); @@ -419,6 +423,10 @@ static void draw_fcurve_handles(SpaceGraph *sipo, FCurve *fcu) immEnd(); immUnbindProgram(); + GPU_blend(false); + if ((sipo->flag & SIPO_BEAUTYDRAW_OFF) == 0) { + GPU_line_smooth(false); + } } /* Samples ---------------- */ @@ -1181,9 +1189,7 @@ void graph_draw_curves(bAnimContext *ac, SpaceGraph *sipo, ARegion *region, shor if (do_handles) { /* only draw handles/vertices on keyframes */ - GPU_blend(true); draw_fcurve_handles(sipo, fcu); - GPU_blend(false); } draw_fcurve_vertices(region, fcu, do_handles, (sipo->flag & SIPO_SELVHANDLESONLY)); diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c index 08053dba4d9..8ffd2844f1a 100644 --- a/source/blender/editors/space_graph/graph_edit.c +++ b/source/blender/editors/space_graph/graph_edit.c @@ -328,7 +328,7 @@ static int graphkeys_view_selected_exec(bContext *C, wmOperator *op) void GRAPH_OT_view_all(wmOperatorType *ot) { /* identifiers */ - ot->name = "View All"; + ot->name = "Frame All"; ot->idname = "GRAPH_OT_view_all"; ot->description = "Reset viewable area to show full keyframe range"; diff --git a/source/blender/editors/space_graph/graph_select.c b/source/blender/editors/space_graph/graph_select.c index a2e9ba86dec..ae435b5624a 100644 --- a/source/blender/editors/space_graph/graph_select.c +++ b/source/blender/editors/space_graph/graph_select.c @@ -760,8 +760,8 @@ static int graphkeys_lassoselect_exec(bContext *C, wmOperator *op) } data_lasso.rectf_view = &rect_fl; - data_lasso.mcords = WM_gesture_lasso_path_to_array(C, op, &data_lasso.mcords_tot); - if (data_lasso.mcords == NULL) { + data_lasso.mcoords = WM_gesture_lasso_path_to_array(C, op, &data_lasso.mcoords_len); + if (data_lasso.mcoords == NULL) { return OPERATOR_CANCELLED; } @@ -782,13 +782,13 @@ static int graphkeys_lassoselect_exec(bContext *C, wmOperator *op) } /* get settings from operator */ - BLI_lasso_boundbox(&rect, data_lasso.mcords, data_lasso.mcords_tot); + BLI_lasso_boundbox(&rect, data_lasso.mcoords, data_lasso.mcoords_len); BLI_rctf_rcti_copy(&rect_fl, &rect); /* apply box_select action */ box_select_graphkeys(&ac, &rect_fl, BEZT_OK_REGION_LASSO, selectmode, incl_handles, &data_lasso); - MEM_freeN((void *)data_lasso.mcords); + MEM_freeN((void *)data_lasso.mcoords); /* send notifier that keyframe selection has changed */ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); diff --git a/source/blender/editors/space_image/image_edit.c b/source/blender/editors/space_image/image_edit.c index 7f911113b7c..c9f2ec38354 100644 --- a/source/blender/editors/space_image/image_edit.c +++ b/source/blender/editors/space_image/image_edit.c @@ -264,7 +264,10 @@ void ED_space_image_get_aspect(SpaceImage *sima, float *r_aspx, float *r_aspy) } } -void ED_space_image_get_zoom(SpaceImage *sima, ARegion *region, float *r_zoomx, float *r_zoomy) +void ED_space_image_get_zoom(SpaceImage *sima, + const ARegion *region, + float *r_zoomx, + float *r_zoomy) { int width, height; @@ -314,7 +317,7 @@ void ED_image_get_uv_aspect(Image *ima, ImageUser *iuser, float *r_aspx, float * } /* takes event->mval */ -void ED_image_mouse_pos(SpaceImage *sima, ARegion *region, const int mval[2], float co[2]) +void ED_image_mouse_pos(SpaceImage *sima, const ARegion *region, const int mval[2], float co[2]) { int sx, sy, width, height; float zoomx, zoomy; @@ -341,7 +344,7 @@ void ED_image_view_center_to_point(SpaceImage *sima, float x, float y) } void ED_image_point_pos( - SpaceImage *sima, ARegion *region, float x, float y, float *r_x, float *r_y) + SpaceImage *sima, const ARegion *region, float x, float y, float *r_x, float *r_y) { int sx, sy, width, height; float zoomx, zoomy; @@ -356,7 +359,7 @@ void ED_image_point_pos( } void ED_image_point_pos__reverse(SpaceImage *sima, - ARegion *region, + const ARegion *region, const float co[2], float r_co[2]) { diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index 7889e56ecfe..8cb85ce9800 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -826,7 +826,7 @@ void IMAGE_OT_view_all(wmOperatorType *ot) PropertyRNA *prop; /* identifiers */ - ot->name = "View All"; + ot->name = "Frame All"; ot->idname = "IMAGE_OT_view_all"; ot->description = "View the entire image"; @@ -983,7 +983,7 @@ void IMAGE_OT_view_zoom_in(wmOperatorType *ot) PropertyRNA *prop; /* identifiers */ - ot->name = "View Zoom In"; + ot->name = "Zoom In"; ot->idname = "IMAGE_OT_view_zoom_in"; ot->description = "Zoom in the image (centered around 2D cursor)"; @@ -1042,7 +1042,7 @@ void IMAGE_OT_view_zoom_out(wmOperatorType *ot) PropertyRNA *prop; /* identifiers */ - ot->name = "View Zoom Out"; + ot->name = "Zoom Out"; ot->idname = "IMAGE_OT_view_zoom_out"; ot->description = "Zoom out the image (centered around 2D cursor)"; diff --git a/source/blender/editors/space_image/image_undo.c b/source/blender/editors/space_image/image_undo.c index eb1c46240cb..5668b88826e 100644 --- a/source/blender/editors/space_image/image_undo.c +++ b/source/blender/editors/space_image/image_undo.c @@ -225,9 +225,9 @@ void *ED_image_paint_tile_push(ListBase *paint_tiles, "PaintTile.mask"); } - ptile->rect.pt = MEM_mapallocN((ibuf->rect_float ? sizeof(float[4]) : sizeof(char[4])) * - square_i(ED_IMAGE_UNDO_TILE_SIZE), - "PaintTile.rect"); + ptile->rect.pt = MEM_callocN((ibuf->rect_float ? sizeof(float[4]) : sizeof(char[4])) * + square_i(ED_IMAGE_UNDO_TILE_SIZE), + "PaintTile.rect"); ptile->use_float = has_float; ptile->valid = true; diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c index 1e1d4373fea..d7d85112497 100644 --- a/source/blender/editors/space_image/space_image.c +++ b/source/blender/editors/space_image/space_image.c @@ -127,6 +127,7 @@ static SpaceLink *image_new(const ScrArea *UNUSED(area), const Scene *UNUSED(sce simage->zoom = 1.0f; simage->lock = true; simage->flag = SI_SHOW_GPENCIL | SI_USE_ALPHA | SI_COORDFLOATS; + simage->uv_opacity = 1.0f; BKE_imageuser_default(&simage->iuser); simage->iuser.flag = IMA_SHOW_STEREO | IMA_ANIM_ALWAYS; diff --git a/source/blender/editors/space_info/info_stats.c b/source/blender/editors/space_info/info_stats.c index a91a11b2465..dbd3b65857a 100644 --- a/source/blender/editors/space_info/info_stats.c +++ b/source/blender/editors/space_info/info_stats.c @@ -33,6 +33,8 @@ #include "DNA_scene_types.h" #include "DNA_windowmanager_types.h" +#include "BLF_api.h" + #include "BLI_listbase.h" #include "BLI_math.h" #include "BLI_string.h" @@ -59,9 +61,10 @@ #include "ED_armature.h" #include "ED_info.h" +#include "UI_resources.h" + #include "GPU_extensions.h" -#define MAX_INFO_LEN 512 #define MAX_INFO_NUM_LEN 16 typedef struct SceneStats { @@ -73,8 +76,6 @@ typedef struct SceneStats { uint64_t totlamp, totlampsel; uint64_t tottri; uint64_t totgplayer, totgpframe, totgpstroke, totgppoint; - - char infostr[MAX_INFO_LEN]; } SceneStats; typedef struct SceneStatsFmt { @@ -368,10 +369,16 @@ static void stats_update(Depsgraph *depsgraph, ViewLayer *view_layer) if (obedit) { /* Edit Mode */ - FOREACH_OBJECT_IN_MODE_BEGIN (view_layer, ((View3D *)NULL), ob->type, ob->mode, ob_iter) { - stats_object_edit(ob_iter, &stats); + FOREACH_OBJECT_BEGIN (view_layer, ob_iter) { + if (ob_iter->base_flag & BASE_VISIBLE_VIEWLAYER) { + if (ob_iter->mode == OB_MODE_EDIT) { + stats_object_edit(ob_iter, &stats); + stats.totobjsel++; + } + stats.totobj++; + } } - FOREACH_OBJECT_IN_MODE_END; + FOREACH_OBJECT_END; } else if (ob && (ob->mode & OB_MODE_POSE)) { /* Pose Mode */ @@ -398,26 +405,92 @@ static void stats_update(Depsgraph *depsgraph, ViewLayer *view_layer) *(view_layer->stats) = stats; } -static void stats_string(ViewLayer *view_layer) +static const char *footer_string(ViewLayer *view_layer) { #define MAX_INFO_MEM_LEN 64 - SceneStats *stats = view_layer->stats; - SceneStatsFmt stats_fmt; - LayerCollection *layer_collection = view_layer->active_collection; - Object *ob = OBACT(view_layer); - Object *obedit = OBEDIT_FROM_OBACT(ob); - eObjectMode object_mode = ob ? ob->mode : OB_MODE_OBJECT; - uintptr_t mem_in_use, mmap_in_use; char memstr[MAX_INFO_MEM_LEN]; char gpumemstr[MAX_INFO_MEM_LEN] = ""; char formatted_mem[15]; - char *s; size_t ofs = 0; - mem_in_use = MEM_get_memory_in_use(); - mmap_in_use = MEM_get_mapped_memory_in_use(); + uintptr_t mem_in_use = MEM_get_memory_in_use(); + + /* get memory statistics */ + BLI_str_format_byte_unit(formatted_mem, mem_in_use, false); + ofs = BLI_snprintf(memstr, MAX_INFO_MEM_LEN, TIP_("Mem: %s"), formatted_mem); + + if (GPU_mem_stats_supported()) { + int gpu_free_mem, gpu_tot_memory; + + GPU_mem_stats_get(&gpu_tot_memory, &gpu_free_mem); + + BLI_str_format_byte_unit(formatted_mem, gpu_free_mem, false); + ofs = BLI_snprintf(gpumemstr, MAX_INFO_MEM_LEN, TIP_(" | Free GPU Mem: %s"), formatted_mem); + + if (gpu_tot_memory) { + BLI_str_format_byte_unit(formatted_mem, gpu_tot_memory, false); + BLI_snprintf(gpumemstr + ofs, MAX_INFO_MEM_LEN - ofs, TIP_("/%s"), formatted_mem); + } + } + + BLI_snprintf(view_layer->footer_str, + sizeof(view_layer->footer_str), + "%s%s | %s", + memstr, + gpumemstr, + versionstr); + + return view_layer->footer_str; + +#undef MAX_INFO_MEM_LEN +} + +void ED_info_stats_clear(ViewLayer *view_layer) +{ + if (view_layer->stats) { + MEM_freeN(view_layer->stats); + view_layer->stats = NULL; + } +} + +const char *ED_info_footer_string(ViewLayer *view_layer) +{ + return footer_string(view_layer); +} + +static void stats_row(int col1, + const char *key, + int col2, + const char *value1, + const char *value2, + int *y, + int height) +{ + *y -= height; + BLF_draw_default(col1, *y, 0.0f, key, 128); + char values[128]; + BLI_snprintf(values, sizeof(values), (value2) ? "%s / %s" : "%s", value1, value2); + BLF_draw_default(col2, *y, 0.0f, values, sizeof(values)); +} + +void ED_info_draw_stats( + Main *bmain, Scene *scene, ViewLayer *view_layer, int x, int *y, int height) +{ + /* Create stats if they don't already exist. */ + if (!view_layer->stats) { + /* Do not not access dependency graph if interface is marked as locked. */ + wmWindowManager *wm = bmain->wm.first; + if (wm->is_interface_locked) { + return; + } + Depsgraph *depsgraph = BKE_scene_get_depsgraph(bmain, scene, view_layer, true); + stats_update(depsgraph, view_layer); + } + + SceneStats *stats = view_layer->stats; + SceneStatsFmt stats_fmt; - /* Generate formatted numbers */ + /* Generate formatted numbers. */ #define SCENE_STATS_FMT_INT(_id) BLI_str_format_uint64_grouped(stats_fmt._id, stats->_id) SCENE_STATS_FMT_INT(totvert); @@ -447,151 +520,94 @@ static void stats_string(ViewLayer *view_layer) #undef SCENE_STATS_FMT_INT - /* get memory statistics */ - BLI_str_format_byte_unit(formatted_mem, mem_in_use - mmap_in_use, false); - ofs = BLI_snprintf(memstr, MAX_INFO_MEM_LEN, TIP_(" | Mem: %s"), formatted_mem); - - if (mmap_in_use) { - BLI_str_format_byte_unit(formatted_mem, mmap_in_use, false); - BLI_snprintf(memstr + ofs, MAX_INFO_MEM_LEN - ofs, TIP_(" (%s)"), formatted_mem); + Object *ob = OBACT(view_layer); + Object *obedit = OBEDIT_FROM_OBACT(ob); + eObjectMode object_mode = ob ? ob->mode : OB_MODE_OBJECT; + const int font_id = BLF_default(); + + UI_FontThemeColor(font_id, TH_TEXT_HI); + BLF_enable(font_id, BLF_SHADOW); + BLF_shadow(font_id, 5, (const float[4]){0.0f, 0.0f, 0.0f, 1.0f}); + BLF_shadow_offset(font_id, 1, -1); + + /* Translated labels for each stat row. */ + enum { + OBJ, + VERTS, + EDGES, + FACES, + TRIS, + BONES, + LAYERS, + FRAMES, + STROKES, + POINTS, + MAX_LABELS_COUNT + }; + char labels[MAX_LABELS_COUNT][64]; + + STRNCPY(labels[OBJ], IFACE_("Objects")); + STRNCPY(labels[VERTS], IFACE_("Vertices")); + STRNCPY(labels[EDGES], IFACE_("Edges")); + STRNCPY(labels[FACES], IFACE_("Faces")); + STRNCPY(labels[TRIS], IFACE_("Triangles")); + STRNCPY(labels[BONES], IFACE_("Bones")); + STRNCPY(labels[LAYERS], IFACE_("Layers")); + STRNCPY(labels[FRAMES], IFACE_("Frames")); + STRNCPY(labels[STROKES], IFACE_("Strokes")); + STRNCPY(labels[POINTS], IFACE_("Points")); + + int longest_label = 0; + int i; + for (i = 0; i < MAX_LABELS_COUNT; ++i) { + longest_label = max_ii(longest_label, BLF_width(font_id, labels[i], sizeof(labels[i]))); } - if (GPU_mem_stats_supported()) { - int gpu_free_mem, gpu_tot_memory; - - GPU_mem_stats_get(&gpu_tot_memory, &gpu_free_mem); - - BLI_str_format_byte_unit(formatted_mem, gpu_free_mem, false); - ofs = BLI_snprintf(gpumemstr, MAX_INFO_MEM_LEN, TIP_(" | Free GPU Mem: %s"), formatted_mem); + int col1 = x; + int col2 = x + longest_label + (0.5f * U.widget_unit); - if (gpu_tot_memory) { - BLI_str_format_byte_unit(formatted_mem, gpu_tot_memory, false); - BLI_snprintf(gpumemstr + ofs, MAX_INFO_MEM_LEN - ofs, TIP_("/%s"), formatted_mem); - } - } - - s = stats->infostr; - ofs = 0; + /* Add some extra margin above this section. */ + *y -= (0.6f * height); if (object_mode == OB_MODE_OBJECT) { - ofs += BLI_snprintf(s + ofs, - MAX_INFO_LEN - ofs, - "%s | ", - BKE_collection_ui_name_get(layer_collection->collection)); - } - - if (ob) { - ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, "%s | ", ob->id.name + 2); + stats_row(col1, labels[OBJ], col2, stats_fmt.totobjsel, stats_fmt.totobj, y, height); } if (obedit) { - if (BKE_keyblock_from_object(obedit)) { - ofs += BLI_strncpy_rlen(s + ofs, TIP_("(Key) "), MAX_INFO_LEN - ofs); - } - if (obedit->type == OB_MESH) { - ofs += BLI_snprintf(s + ofs, - MAX_INFO_LEN - ofs, - TIP_("Verts:%s/%s | Edges:%s/%s | Faces:%s/%s | Tris:%s"), - stats_fmt.totvertsel, - stats_fmt.totvert, - stats_fmt.totedgesel, - stats_fmt.totedge, - stats_fmt.totfacesel, - stats_fmt.totface, - stats_fmt.tottri); + stats_row(col1, labels[OBJ], col2, stats_fmt.totobjsel, stats_fmt.totobj, y, height); + stats_row(col1, labels[VERTS], col2, stats_fmt.totvertsel, stats_fmt.totvert, y, height); + stats_row(col1, labels[EDGES], col2, stats_fmt.totedgesel, stats_fmt.totedge, y, height); + stats_row(col1, labels[FACES], col2, stats_fmt.totfacesel, stats_fmt.totface, y, height); + stats_row(col1, labels[TRIS], col2, stats_fmt.tottri, NULL, y, height); } else if (obedit->type == OB_ARMATURE) { - ofs += BLI_snprintf(s + ofs, - MAX_INFO_LEN - ofs, - TIP_("Verts:%s/%s | Bones:%s/%s"), - stats_fmt.totvertsel, - stats_fmt.totvert, - stats_fmt.totbonesel, - stats_fmt.totbone); + stats_row(col1, labels[VERTS], col2, stats_fmt.totvertsel, stats_fmt.totvert, y, height); + stats_row(col1, labels[BONES], col2, stats_fmt.totbonesel, stats_fmt.totbone, y, height); } else { - ofs += BLI_snprintf(s + ofs, - MAX_INFO_LEN - ofs, - TIP_("Verts:%s/%s"), - stats_fmt.totvertsel, - stats_fmt.totvert); + stats_row(col1, labels[VERTS], col2, stats_fmt.totvertsel, stats_fmt.totvert, y, height); } - - ofs += BLI_strncpy_rlen(s + ofs, memstr, MAX_INFO_LEN - ofs); - ofs += BLI_strncpy_rlen(s + ofs, gpumemstr, MAX_INFO_LEN - ofs); } else if (ob && (object_mode & OB_MODE_POSE)) { - ofs += BLI_snprintf(s + ofs, - MAX_INFO_LEN - ofs, - TIP_("Bones:%s/%s %s%s"), - stats_fmt.totbonesel, - stats_fmt.totbone, - memstr, - gpumemstr); + stats_row(col1, labels[BONES], col2, stats_fmt.totbonesel, stats_fmt.totbone, y, height); } else if ((ob) && (ob->type == OB_GPENCIL)) { - ofs += BLI_snprintf(s + ofs, - MAX_INFO_LEN - ofs, - TIP_("Layers:%s | Frames:%s | Strokes:%s | Points:%s | Objects:%s/%s"), - stats_fmt.totgplayer, - stats_fmt.totgpframe, - stats_fmt.totgpstroke, - stats_fmt.totgppoint, - stats_fmt.totobjsel, - stats_fmt.totobj); - - ofs += BLI_strncpy_rlen(s + ofs, memstr, MAX_INFO_LEN - ofs); - ofs += BLI_strncpy_rlen(s + ofs, gpumemstr, MAX_INFO_LEN - ofs); + stats_row(col1, labels[LAYERS], col2, stats_fmt.totgplayer, NULL, y, height); + stats_row(col1, labels[FRAMES], col2, stats_fmt.totgpframe, NULL, y, height); + stats_row(col1, labels[STROKES], col2, stats_fmt.totgpstroke, NULL, y, height); + stats_row(col1, labels[POINTS], col2, stats_fmt.totgppoint, NULL, y, height); } else if (stats_is_object_dynamic_topology_sculpt(ob, object_mode)) { - ofs += BLI_snprintf(s + ofs, - MAX_INFO_LEN - ofs, - TIP_("Verts:%s | Tris:%s%s"), - stats_fmt.totvert, - stats_fmt.tottri, - gpumemstr); + stats_row(col1, labels[VERTS], col2, stats_fmt.totvert, NULL, y, height); + stats_row(col1, labels[TRIS], col2, stats_fmt.tottri, NULL, y, height); } else { - ofs += BLI_snprintf(s + ofs, - MAX_INFO_LEN - ofs, - TIP_("Verts:%s | Faces:%s | Tris:%s | Objects:%s/%s%s%s"), - stats_fmt.totvert, - stats_fmt.totface, - stats_fmt.tottri, - stats_fmt.totobjsel, - stats_fmt.totobj, - memstr, - gpumemstr); + stats_row(col1, labels[VERTS], col2, stats_fmt.totvert, NULL, y, height); + stats_row(col1, labels[EDGES], col2, stats_fmt.totedge, NULL, y, height); + stats_row(col1, labels[FACES], col2, stats_fmt.totface, NULL, y, height); + stats_row(col1, labels[TRIS], col2, stats_fmt.tottri, NULL, y, height); } - ofs += BLI_snprintf(s + ofs, MAX_INFO_LEN - ofs, " | %s", versionstr); -#undef MAX_INFO_MEM_LEN -} - -#undef MAX_INFO_LEN - -void ED_info_stats_clear(ViewLayer *view_layer) -{ - if (view_layer->stats) { - MEM_freeN(view_layer->stats); - view_layer->stats = NULL; - } -} - -const char *ED_info_stats_string(Main *bmain, Scene *scene, ViewLayer *view_layer) -{ - /* Looping through dependency graph when interface is locked is not safe. - * The interface is marked as locked when jobs wants to modify the - * dependency graph. */ - wmWindowManager *wm = bmain->wm.first; - if (wm->is_interface_locked) { - return ""; - } - Depsgraph *depsgraph = BKE_scene_get_depsgraph(bmain, scene, view_layer, true); - if (!view_layer->stats) { - stats_update(depsgraph, view_layer); - } - stats_string(view_layer); - return view_layer->stats->infostr; + BLF_disable(font_id, BLF_SHADOW); } diff --git a/source/blender/editors/space_nla/nla_buttons.c b/source/blender/editors/space_nla/nla_buttons.c index 218e2be0362..307b6d9bc21 100644 --- a/source/blender/editors/space_nla/nla_buttons.c +++ b/source/blender/editors/space_nla/nla_buttons.c @@ -143,7 +143,8 @@ bool nla_panel_context(const bContext *C, case ANIMTYPE_PALETTE: case ANIMTYPE_DSHAIR: case ANIMTYPE_DSPOINTCLOUD: - case ANIMTYPE_DSVOLUME: { + case ANIMTYPE_DSVOLUME: + case ANIMTYPE_DSSIMULATION: { /* for these channels, we only do AnimData */ if (ale->adt && adt_ptr) { ID *id; @@ -354,7 +355,7 @@ static void nla_panel_properties(const bContext *C, Panel *panel) { PointerRNA strip_ptr; uiLayout *layout = panel->layout; - uiLayout *column; + uiLayout *column, *row; uiBlock *block; short showEvalProps = 1; @@ -401,20 +402,19 @@ static void nla_panel_properties(const bContext *C, Panel *panel) uiItemR(column, &strip_ptr, "blend_in", 0, IFACE_("Blend In"), ICON_NONE); uiItemR(column, &strip_ptr, "blend_out", 0, IFACE_("Out"), ICON_NONE); - column = uiLayoutColumn(layout, true); - uiLayoutSetActive(column, RNA_boolean_get(&strip_ptr, "use_animated_influence") == false); - uiItemR(column, &strip_ptr, "use_auto_blend", 0, NULL, ICON_NONE); // XXX as toggle? - - uiItemS(layout); + row = uiLayoutRow(column, true); + uiLayoutSetActive(row, RNA_boolean_get(&strip_ptr, "use_animated_influence") == false); + uiItemR(row, &strip_ptr, "use_auto_blend", 0, NULL, ICON_NONE); // XXX as toggle? /* settings */ - column = uiLayoutColumn(layout, true); - uiLayoutSetActive(column, + column = uiLayoutColumnWithHeading(layout, true, "Playback"); + row = uiLayoutRow(column, true); + uiLayoutSetActive(row, !(RNA_boolean_get(&strip_ptr, "use_animated_influence") || RNA_boolean_get(&strip_ptr, "use_animated_time"))); - uiItemR(column, &strip_ptr, "use_reverse", 0, NULL, ICON_NONE); + uiItemR(row, &strip_ptr, "use_reverse", 0, NULL, ICON_NONE); - uiItemR(layout, &strip_ptr, "use_animated_time_cyclic", 0, NULL, ICON_NONE); + uiItemR(column, &strip_ptr, "use_animated_time_cyclic", 0, NULL, ICON_NONE); } } @@ -442,15 +442,12 @@ static void nla_panel_actclip(const bContext *C, Panel *panel) uiItemR(row, &strip_ptr, "action", 0, NULL, ICON_ACTION); /* action extents */ - // XXX custom names were used here (to avoid the prefixes)... probably not necessary in future? column = uiLayoutColumn(layout, true); uiItemR(column, &strip_ptr, "action_frame_start", 0, IFACE_("Frame Start"), ICON_NONE); uiItemR(column, &strip_ptr, "action_frame_end", 0, IFACE_("End"), ICON_NONE); - /* XXX: this layout may actually be too abstract and confusing, - * and may be better using standard column layout. */ - row = uiLayoutRow(layout, false); - uiItemR(row, &strip_ptr, "use_sync_length", 0, IFACE_("Sync Length"), ICON_NONE); + row = uiLayoutRowWithHeading(layout, false, "Sync Length"); + uiItemR(row, &strip_ptr, "use_sync_length", 0, "", ICON_NONE); uiItemO(row, IFACE_("Now"), ICON_FILE_REFRESH, "NLA_OT_action_sync_length"); /* action usage */ diff --git a/source/blender/editors/space_nla/nla_channels.c b/source/blender/editors/space_nla/nla_channels.c index 5adcec8a5d7..d399ea47d7e 100644 --- a/source/blender/editors/space_nla/nla_channels.c +++ b/source/blender/editors/space_nla/nla_channels.c @@ -193,7 +193,8 @@ static int mouse_nla_channels( case ANIMTYPE_PALETTE: case ANIMTYPE_DSHAIR: case ANIMTYPE_DSPOINTCLOUD: - case ANIMTYPE_DSVOLUME: { + case ANIMTYPE_DSVOLUME: + case ANIMTYPE_DSSIMULATION: { /* sanity checking... */ if (ale->adt) { /* select/deselect */ diff --git a/source/blender/editors/space_nla/nla_edit.c b/source/blender/editors/space_nla/nla_edit.c index 5b949911158..f68896e21d6 100644 --- a/source/blender/editors/space_nla/nla_edit.c +++ b/source/blender/editors/space_nla/nla_edit.c @@ -410,8 +410,8 @@ void NLA_OT_previewrange_set(wmOperatorType *ot) /** * Find the extents of the active channel * - * \param[out] min Bottom y-extent of channel - * \param[out] max Top y-extent of channel + * \param[out] min: Bottom y-extent of channel. + * \param[out] max: Top y-extent of channel. * \return Success of finding a selected channel */ static bool nla_channels_get_selected_extents(bAnimContext *ac, float *min, float *max) @@ -526,7 +526,7 @@ static int nlaedit_viewsel_exec(bContext *C, wmOperator *UNUSED(op)) void NLA_OT_view_all(wmOperatorType *ot) { /* identifiers */ - ot->name = "View All"; + ot->name = "Frame All"; ot->idname = "NLA_OT_view_all"; ot->description = "Reset viewable area to show full strips range"; diff --git a/source/blender/editors/space_node/CMakeLists.txt b/source/blender/editors/space_node/CMakeLists.txt index f8c30f9a688..4e21cdc9d16 100644 --- a/source/blender/editors/space_node/CMakeLists.txt +++ b/source/blender/editors/space_node/CMakeLists.txt @@ -75,6 +75,10 @@ if(WITH_OPENIMAGEDENOISE) add_definitions(-DWITH_OPENIMAGEDENOISE) endif() +if (WITH_NEW_SIMULATION_TYPE) + add_definitions(-DWITH_NEW_SIMULATION_TYPE) +endif() + add_definitions(${GL_DEFINITIONS}) blender_add_lib(bf_editor_space_node "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index e5ca2efb26f..44003a5b9bc 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -69,9 +69,13 @@ #include "NOD_composite.h" #include "NOD_shader.h" +#include "NOD_simulation.h" #include "NOD_texture.h" #include "node_intern.h" /* own include */ +/* Default flags for uiItemR(). Name is kept short since this is used a lot in this file. */ +#define DEFAULT_FLAGS UI_ITEM_R_SPLIT_EMPTY_NAME + /* ****************** SOCKET BUTTON DRAW FUNCTIONS ***************** */ static void node_socket_button_label(bContext *UNUSED(C), @@ -93,7 +97,7 @@ static void node_buts_value(uiLayout *layout, bContext *UNUSED(C), PointerRNA *p PointerRNA sockptr; RNA_pointer_create(ptr->owner_id, &RNA_NodeSocket, output, &sockptr); - uiItemR(layout, &sockptr, "default_value", 0, "", ICON_NONE); + uiItemR(layout, &sockptr, "default_value", DEFAULT_FLAGS, "", ICON_NONE); } static void node_buts_rgb(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) @@ -107,7 +111,7 @@ static void node_buts_rgb(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr col = uiLayoutColumn(layout, false); uiTemplateColorPicker(col, &sockptr, "default_value", 1, 0, 0, 0); - uiItemR(col, &sockptr, "default_value", UI_ITEM_R_SLIDER, "", ICON_NONE); + uiItemR(col, &sockptr, "default_value", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE); } static void node_buts_mix_rgb(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) @@ -118,12 +122,12 @@ static void node_buts_mix_rgb(uiLayout *layout, bContext *UNUSED(C), PointerRNA col = uiLayoutColumn(layout, false); row = uiLayoutRow(col, true); - uiItemR(row, ptr, "blend_type", 0, "", ICON_NONE); + uiItemR(row, ptr, "blend_type", DEFAULT_FLAGS, "", ICON_NONE); if (ELEM(ntree->type, NTREE_COMPOSIT, NTREE_TEXTURE)) { - uiItemR(row, ptr, "use_alpha", 0, "", ICON_IMAGE_RGB_ALPHA); + uiItemR(row, ptr, "use_alpha", DEFAULT_FLAGS, "", ICON_IMAGE_RGB_ALPHA); } - uiItemR(col, ptr, "use_clamp", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "use_clamp", DEFAULT_FLAGS, NULL, ICON_NONE); } static void node_buts_time(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) @@ -145,8 +149,8 @@ static void node_buts_time(uiLayout *layout, bContext *UNUSED(C), PointerRNA *pt uiTemplateCurveMapping(layout, ptr, "curve", 's', false, false, false, false); row = uiLayoutRow(layout, true); - uiItemR(row, ptr, "frame_start", 0, IFACE_("Sta"), ICON_NONE); - uiItemR(row, ptr, "frame_end", 0, IFACE_("End"), ICON_NONE); + uiItemR(row, ptr, "frame_start", DEFAULT_FLAGS, IFACE_("Sta"), ICON_NONE); + uiItemR(row, ptr, "frame_end", DEFAULT_FLAGS, IFACE_("End"), ICON_NONE); } static void node_buts_colorramp(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) @@ -196,7 +200,7 @@ static void node_buts_normal(uiLayout *layout, bContext *UNUSED(C), PointerRNA * PointerRNA sockptr; RNA_pointer_create(ptr->owner_id, &RNA_NodeSocket, output, &sockptr); - uiItemR(layout, &sockptr, "default_value", 0, "", ICON_NONE); + uiItemR(layout, &sockptr, "default_value", DEFAULT_FLAGS, "", ICON_NONE); } #if 0 /* not used in 2.5x yet */ @@ -242,33 +246,33 @@ static void node_buts_texture(uiLayout *layout, bContext *UNUSED(C), PointerRNA short multi = (node->id && ((Tex *)node->id)->use_nodes && (node->type != CMP_NODE_TEXTURE) && (node->type != TEX_NODE_TEXTURE)); - uiItemR(layout, ptr, "texture", 0, "", ICON_NONE); + uiItemR(layout, ptr, "texture", DEFAULT_FLAGS, "", ICON_NONE); if (multi) { /* Number Drawing not optimal here, better have a list*/ - uiItemR(layout, ptr, "node_output", 0, "", ICON_NONE); + uiItemR(layout, ptr, "node_output", DEFAULT_FLAGS, "", ICON_NONE); } } static void node_shader_buts_clamp(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "clamp_type", 0, "", ICON_NONE); + uiItemR(layout, ptr, "clamp_type", DEFAULT_FLAGS, "", ICON_NONE); } static void node_shader_buts_map_range(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "interpolation_type", 0, "", ICON_NONE); + uiItemR(layout, ptr, "interpolation_type", DEFAULT_FLAGS, "", ICON_NONE); if (!ELEM(RNA_enum_get(ptr, "interpolation_type"), NODE_MAP_RANGE_SMOOTHSTEP, NODE_MAP_RANGE_SMOOTHERSTEP)) { - uiItemR(layout, ptr, "clamp", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "clamp", DEFAULT_FLAGS, NULL, ICON_NONE); } } static void node_buts_math(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "operation", 0, "", ICON_NONE); - uiItemR(layout, ptr, "use_clamp", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "operation", DEFAULT_FLAGS, "", ICON_NONE); + uiItemR(layout, ptr, "use_clamp", DEFAULT_FLAGS, NULL, ICON_NONE); } static int node_resize_area_default(bNode *node, int x, int y) @@ -534,9 +538,9 @@ static int node_resize_area_frame(bNode *node, int x, int y) static void node_buts_frame_ex(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "label_size", 0, IFACE_("Label Size"), ICON_NONE); - uiItemR(layout, ptr, "shrink", 0, IFACE_("Shrink"), ICON_NONE); - uiItemR(layout, ptr, "text", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "label_size", DEFAULT_FLAGS, IFACE_("Label Size"), ICON_NONE); + uiItemR(layout, ptr, "shrink", DEFAULT_FLAGS, IFACE_("Shrink"), ICON_NONE); + uiItemR(layout, ptr, "text", DEFAULT_FLAGS, NULL, ICON_NONE); } #define NODE_REROUTE_SIZE 8.0f @@ -697,7 +701,7 @@ static void node_buts_image_user(uiLayout *layout, col = uiLayoutColumn(layout, false); - uiItemR(col, imaptr, "source", 0, "", ICON_NONE); + uiItemR(col, imaptr, "source", DEFAULT_FLAGS, "", ICON_NONE); source = RNA_enum_get(imaptr, "source"); @@ -716,23 +720,23 @@ static void node_buts_image_user(uiLayout *layout, if (ELEM(source, IMA_SRC_SEQUENCE, IMA_SRC_MOVIE)) { col = uiLayoutColumn(layout, true); - uiItemR(col, ptr, "frame_duration", 0, NULL, ICON_NONE); - uiItemR(col, ptr, "frame_start", 0, NULL, ICON_NONE); - uiItemR(col, ptr, "frame_offset", 0, NULL, ICON_NONE); - uiItemR(col, ptr, "use_cyclic", 0, NULL, ICON_NONE); - uiItemR(col, ptr, "use_auto_refresh", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "frame_duration", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(col, ptr, "frame_start", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(col, ptr, "frame_offset", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(col, ptr, "use_cyclic", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(col, ptr, "use_auto_refresh", DEFAULT_FLAGS, NULL, ICON_NONE); } if (compositor && RNA_enum_get(imaptr, "type") == IMA_TYPE_MULTILAYER && RNA_boolean_get(ptr, "has_layers")) { col = uiLayoutColumn(layout, false); - uiItemR(col, ptr, "layer", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "layer", DEFAULT_FLAGS, NULL, ICON_NONE); } uiLayout *split = uiLayoutSplit(layout, 0.5f, true); PointerRNA colorspace_settings_ptr = RNA_pointer_get(imaptr, "colorspace_settings"); uiItemL(split, IFACE_("Color Space"), ICON_NONE); - uiItemR(split, &colorspace_settings_ptr, "name", 0, "", ICON_NONE); + uiItemR(split, &colorspace_settings_ptr, "name", DEFAULT_FLAGS, "", ICON_NONE); /* Avoid losing changes image is painted. */ if (BKE_image_is_dirty(imaptr->data)) { @@ -742,35 +746,35 @@ static void node_buts_image_user(uiLayout *layout, static void node_shader_buts_mapping(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "vector_type", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "vector_type", DEFAULT_FLAGS, NULL, ICON_NONE); } static void node_shader_buts_vector_rotate(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "rotation_type", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "invert", 0, NULL, 0); + uiItemR(layout, ptr, "rotation_type", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(layout, ptr, "invert", DEFAULT_FLAGS, NULL, 0); } static void node_shader_buts_vect_math(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "operation", 0, "", ICON_NONE); + uiItemR(layout, ptr, "operation", DEFAULT_FLAGS, "", ICON_NONE); } static void node_shader_buts_vect_transform(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "vector_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE); - uiItemR(layout, ptr, "convert_from", 0, "", ICON_NONE); - uiItemR(layout, ptr, "convert_to", 0, "", ICON_NONE); + uiItemR(layout, ptr, "vector_type", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE); + uiItemR(layout, ptr, "convert_from", DEFAULT_FLAGS, "", ICON_NONE); + uiItemR(layout, ptr, "convert_to", DEFAULT_FLAGS, "", ICON_NONE); } static void node_shader_buts_attribute(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "attribute_name", 0, IFACE_("Name"), ICON_NONE); + uiItemR(layout, ptr, "attribute_name", DEFAULT_FLAGS, IFACE_("Name"), ICON_NONE); } static void node_shader_buts_wireframe(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "use_pixel_size", 0, NULL, 0); + uiItemR(layout, ptr, "use_pixel_size", DEFAULT_FLAGS, NULL, 0); } static void node_shader_buts_tex_image(uiLayout *layout, bContext *C, PointerRNA *ptr) @@ -789,14 +793,14 @@ static void node_shader_buts_tex_image(uiLayout *layout, bContext *C, PointerRNA UI_TEMPLATE_ID_FILTER_ALL, false, NULL); - uiItemR(layout, ptr, "interpolation", 0, "", ICON_NONE); - uiItemR(layout, ptr, "projection", 0, "", ICON_NONE); + uiItemR(layout, ptr, "interpolation", DEFAULT_FLAGS, "", ICON_NONE); + uiItemR(layout, ptr, "projection", DEFAULT_FLAGS, "", ICON_NONE); if (RNA_enum_get(ptr, "projection") == SHD_PROJ_BOX) { - uiItemR(layout, ptr, "projection_blend", 0, "Blend", ICON_NONE); + uiItemR(layout, ptr, "projection_blend", DEFAULT_FLAGS, "Blend", ICON_NONE); } - uiItemR(layout, ptr, "extension", 0, "", ICON_NONE); + uiItemR(layout, ptr, "extension", DEFAULT_FLAGS, "", ICON_NONE); /* note: image user properties used directly here, unlike compositor image node, * which redefines them in the node struct RNA to get proper updates. @@ -827,8 +831,8 @@ static void node_shader_buts_tex_environment(uiLayout *layout, bContext *C, Poin false, NULL); - uiItemR(layout, ptr, "interpolation", 0, "", ICON_NONE); - uiItemR(layout, ptr, "projection", 0, "", ICON_NONE); + uiItemR(layout, ptr, "interpolation", DEFAULT_FLAGS, "", ICON_NONE); + uiItemR(layout, ptr, "projection", DEFAULT_FLAGS, "", ICON_NONE); node_buts_image_user(layout, C, &iuserptr, &imaptr, &iuserptr, false); } @@ -838,29 +842,29 @@ static void node_shader_buts_tex_environment_ex(uiLayout *layout, bContext *C, P PointerRNA iuserptr = RNA_pointer_get(ptr, "image_user"); uiTemplateImage(layout, C, ptr, "image", &iuserptr, 0, 0); - uiItemR(layout, ptr, "interpolation", 0, IFACE_("Interpolation"), ICON_NONE); - uiItemR(layout, ptr, "projection", 0, IFACE_("Projection"), ICON_NONE); + uiItemR(layout, ptr, "interpolation", DEFAULT_FLAGS, IFACE_("Interpolation"), ICON_NONE); + uiItemR(layout, ptr, "projection", DEFAULT_FLAGS, IFACE_("Projection"), ICON_NONE); } static void node_shader_buts_tex_sky(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "sky_type", 0, "", ICON_NONE); - uiItemR(layout, ptr, "sun_direction", 0, "", ICON_NONE); - uiItemR(layout, ptr, "turbidity", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "sky_type", DEFAULT_FLAGS, "", ICON_NONE); + uiItemR(layout, ptr, "sun_direction", DEFAULT_FLAGS, "", ICON_NONE); + uiItemR(layout, ptr, "turbidity", DEFAULT_FLAGS, NULL, ICON_NONE); if (RNA_enum_get(ptr, "sky_type") == SHD_SKY_NEW) { - uiItemR(layout, ptr, "ground_albedo", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "ground_albedo", DEFAULT_FLAGS, NULL, ICON_NONE); } } static void node_shader_buts_tex_gradient(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "gradient_type", 0, "", ICON_NONE); + uiItemR(layout, ptr, "gradient_type", DEFAULT_FLAGS, "", ICON_NONE); } static void node_shader_buts_tex_magic(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "turbulence_depth", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "turbulence_depth", DEFAULT_FLAGS, NULL, ICON_NONE); } static void node_shader_buts_tex_brick(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) @@ -868,48 +872,48 @@ static void node_shader_buts_tex_brick(uiLayout *layout, bContext *UNUSED(C), Po uiLayout *col; col = uiLayoutColumn(layout, true); - uiItemR(col, ptr, "offset", UI_ITEM_R_SLIDER, IFACE_("Offset"), ICON_NONE); - uiItemR(col, ptr, "offset_frequency", 0, IFACE_("Frequency"), ICON_NONE); + uiItemR(col, ptr, "offset", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, IFACE_("Offset"), ICON_NONE); + uiItemR(col, ptr, "offset_frequency", DEFAULT_FLAGS, IFACE_("Frequency"), ICON_NONE); col = uiLayoutColumn(layout, true); - uiItemR(col, ptr, "squash", 0, IFACE_("Squash"), ICON_NONE); - uiItemR(col, ptr, "squash_frequency", 0, IFACE_("Frequency"), ICON_NONE); + uiItemR(col, ptr, "squash", DEFAULT_FLAGS, IFACE_("Squash"), ICON_NONE); + uiItemR(col, ptr, "squash_frequency", DEFAULT_FLAGS, IFACE_("Frequency"), ICON_NONE); } static void node_shader_buts_tex_wave(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "wave_type", 0, "", ICON_NONE); + uiItemR(layout, ptr, "wave_type", DEFAULT_FLAGS, "", ICON_NONE); int type = RNA_enum_get(ptr, "wave_type"); if (type == SHD_WAVE_BANDS) { - uiItemR(layout, ptr, "bands_direction", 0, "", ICON_NONE); + uiItemR(layout, ptr, "bands_direction", DEFAULT_FLAGS, "", ICON_NONE); } else { /* SHD_WAVE_RINGS */ - uiItemR(layout, ptr, "rings_direction", 0, "", ICON_NONE); + uiItemR(layout, ptr, "rings_direction", DEFAULT_FLAGS, "", ICON_NONE); } - uiItemR(layout, ptr, "wave_profile", 0, "", ICON_NONE); + uiItemR(layout, ptr, "wave_profile", DEFAULT_FLAGS, "", ICON_NONE); } static void node_shader_buts_tex_musgrave(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "musgrave_dimensions", 0, "", ICON_NONE); - uiItemR(layout, ptr, "musgrave_type", 0, "", ICON_NONE); + uiItemR(layout, ptr, "musgrave_dimensions", DEFAULT_FLAGS, "", ICON_NONE); + uiItemR(layout, ptr, "musgrave_type", DEFAULT_FLAGS, "", ICON_NONE); } static void node_shader_buts_tex_voronoi(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "voronoi_dimensions", 0, "", ICON_NONE); - uiItemR(layout, ptr, "feature", 0, "", ICON_NONE); + uiItemR(layout, ptr, "voronoi_dimensions", DEFAULT_FLAGS, "", ICON_NONE); + uiItemR(layout, ptr, "feature", DEFAULT_FLAGS, "", ICON_NONE); int feature = RNA_enum_get(ptr, "feature"); if (!ELEM(feature, SHD_VORONOI_DISTANCE_TO_EDGE, SHD_VORONOI_N_SPHERE_RADIUS) && RNA_enum_get(ptr, "voronoi_dimensions") != 1) { - uiItemR(layout, ptr, "distance", 0, "", ICON_NONE); + uiItemR(layout, ptr, "distance", DEFAULT_FLAGS, "", ICON_NONE); } } static void node_shader_buts_tex_noise(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "noise_dimensions", 0, "", ICON_NONE); + uiItemR(layout, ptr, "noise_dimensions", DEFAULT_FLAGS, "", ICON_NONE); } static void node_shader_buts_tex_pointdensity(uiLayout *layout, @@ -925,7 +929,7 @@ static void node_shader_buts_tex_pointdensity(uiLayout *layout, RNA_id_pointer_create(ob ? (ID *)ob->data : NULL, &obdata_ptr); uiItemR(layout, ptr, "point_source", UI_ITEM_R_EXPAND, NULL, ICON_NONE); - uiItemR(layout, ptr, "object", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "object", DEFAULT_FLAGS, NULL, ICON_NONE); if (node->id && shader_point_density->point_source == SHD_POINTDENSITY_SOURCE_PSYS) { PointerRNA dataptr; @@ -933,15 +937,15 @@ static void node_shader_buts_tex_pointdensity(uiLayout *layout, uiItemPointerR(layout, ptr, "particle_system", &dataptr, "particle_systems", NULL, ICON_NONE); } - uiItemR(layout, ptr, "space", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "radius", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "interpolation", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "resolution", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "space", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(layout, ptr, "radius", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(layout, ptr, "interpolation", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(layout, ptr, "resolution", DEFAULT_FLAGS, NULL, ICON_NONE); if (shader_point_density->point_source == SHD_POINTDENSITY_SOURCE_PSYS) { - uiItemR(layout, ptr, "particle_color_source", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "particle_color_source", DEFAULT_FLAGS, NULL, ICON_NONE); } else { - uiItemR(layout, ptr, "vertex_color_source", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "vertex_color_source", DEFAULT_FLAGS, NULL, ICON_NONE); if (shader_point_density->ob_color_source == SHD_POINTDENSITY_COLOR_VERTWEIGHT) { if (ob_ptr.data) { uiItemPointerR( @@ -959,18 +963,18 @@ static void node_shader_buts_tex_pointdensity(uiLayout *layout, static void node_shader_buts_tex_coord(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "object", 0, NULL, 0); - uiItemR(layout, ptr, "from_instancer", 0, NULL, 0); + uiItemR(layout, ptr, "object", DEFAULT_FLAGS, NULL, 0); + uiItemR(layout, ptr, "from_instancer", DEFAULT_FLAGS, NULL, 0); } static void node_shader_buts_bump(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "invert", 0, NULL, 0); + uiItemR(layout, ptr, "invert", DEFAULT_FLAGS, NULL, 0); } static void node_shader_buts_uvmap(uiLayout *layout, bContext *C, PointerRNA *ptr) { - uiItemR(layout, ptr, "from_instancer", 0, NULL, 0); + uiItemR(layout, ptr, "from_instancer", DEFAULT_FLAGS, NULL, 0); if (!RNA_boolean_get(ptr, "from_instancer")) { PointerRNA obptr = CTX_data_pointer_get(C, "active_object"); @@ -996,12 +1000,12 @@ static void node_shader_buts_vertex_color(uiLayout *layout, bContext *C, Pointer static void node_shader_buts_uvalongstroke(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "use_tips", 0, NULL, 0); + uiItemR(layout, ptr, "use_tips", DEFAULT_FLAGS, NULL, 0); } static void node_shader_buts_normal_map(uiLayout *layout, bContext *C, PointerRNA *ptr) { - uiItemR(layout, ptr, "space", 0, "", 0); + uiItemR(layout, ptr, "space", DEFAULT_FLAGS, "", 0); if (RNA_enum_get(ptr, "space") == SHD_SPACE_TANGENT) { PointerRNA obptr = CTX_data_pointer_get(C, "active_object"); @@ -1011,14 +1015,14 @@ static void node_shader_buts_normal_map(uiLayout *layout, bContext *C, PointerRN uiItemPointerR(layout, ptr, "uv_map", &dataptr, "uv_layers", "", ICON_NONE); } else { - uiItemR(layout, ptr, "uv_map", 0, "", 0); + uiItemR(layout, ptr, "uv_map", DEFAULT_FLAGS, "", 0); } } } static void node_shader_buts_displacement(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "space", 0, "", 0); + uiItemR(layout, ptr, "space", DEFAULT_FLAGS, "", 0); } static void node_shader_buts_tangent(uiLayout *layout, bContext *C, PointerRNA *ptr) @@ -1027,7 +1031,7 @@ static void node_shader_buts_tangent(uiLayout *layout, bContext *C, PointerRNA * split = uiLayoutSplit(layout, 0.0f, false); - uiItemR(split, ptr, "direction_type", 0, "", 0); + uiItemR(split, ptr, "direction_type", DEFAULT_FLAGS, "", 0); row = uiLayoutRow(split, false); @@ -1039,50 +1043,50 @@ static void node_shader_buts_tangent(uiLayout *layout, bContext *C, PointerRNA * uiItemPointerR(row, ptr, "uv_map", &dataptr, "uv_layers", "", ICON_NONE); } else { - uiItemR(row, ptr, "uv_map", 0, "", 0); + uiItemR(row, ptr, "uv_map", DEFAULT_FLAGS, "", 0); } } else { - uiItemR(row, ptr, "axis", UI_ITEM_R_EXPAND, NULL, 0); + uiItemR(row, ptr, "axis", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, 0); } } static void node_shader_buts_glossy(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "distribution", 0, "", ICON_NONE); + uiItemR(layout, ptr, "distribution", DEFAULT_FLAGS, "", ICON_NONE); } static void node_shader_buts_principled(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "distribution", 0, "", ICON_NONE); - uiItemR(layout, ptr, "subsurface_method", 0, "", ICON_NONE); + uiItemR(layout, ptr, "distribution", DEFAULT_FLAGS, "", ICON_NONE); + uiItemR(layout, ptr, "subsurface_method", DEFAULT_FLAGS, "", ICON_NONE); } static void node_shader_buts_anisotropic(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "distribution", 0, "", ICON_NONE); + uiItemR(layout, ptr, "distribution", DEFAULT_FLAGS, "", ICON_NONE); } static void node_shader_buts_subsurface(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "falloff", 0, "", ICON_NONE); + uiItemR(layout, ptr, "falloff", DEFAULT_FLAGS, "", ICON_NONE); } static void node_shader_buts_toon(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "component", 0, "", ICON_NONE); + uiItemR(layout, ptr, "component", DEFAULT_FLAGS, "", ICON_NONE); } static void node_shader_buts_hair(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "component", 0, "", ICON_NONE); + uiItemR(layout, ptr, "component", DEFAULT_FLAGS, "", ICON_NONE); } static void node_shader_buts_principled_hair(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "parametrization", 0, "", ICON_NONE); + uiItemR(layout, ptr, "parametrization", DEFAULT_FLAGS, "", ICON_NONE); } static void node_shader_buts_ies(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) @@ -1090,15 +1094,15 @@ static void node_shader_buts_ies(uiLayout *layout, bContext *UNUSED(C), PointerR uiLayout *row; row = uiLayoutRow(layout, false); - uiItemR(row, ptr, "mode", UI_ITEM_R_EXPAND, NULL, ICON_NONE); + uiItemR(row, ptr, "mode", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE); row = uiLayoutRow(layout, true); if (RNA_enum_get(ptr, "mode") == NODE_IES_INTERNAL) { - uiItemR(row, ptr, "ies", 0, "", ICON_NONE); + uiItemR(row, ptr, "ies", DEFAULT_FLAGS, "", ICON_NONE); } else { - uiItemR(row, ptr, "filepath", 0, "", ICON_NONE); + uiItemR(row, ptr, "filepath", DEFAULT_FLAGS, "", ICON_NONE); } } @@ -1107,15 +1111,15 @@ static void node_shader_buts_script(uiLayout *layout, bContext *UNUSED(C), Point uiLayout *row; row = uiLayoutRow(layout, false); - uiItemR(row, ptr, "mode", UI_ITEM_R_EXPAND, NULL, ICON_NONE); + uiItemR(row, ptr, "mode", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE); row = uiLayoutRow(layout, true); if (RNA_enum_get(ptr, "mode") == NODE_SCRIPT_INTERNAL) { - uiItemR(row, ptr, "script", 0, "", ICON_NONE); + uiItemR(row, ptr, "script", DEFAULT_FLAGS, "", ICON_NONE); } else { - uiItemR(row, ptr, "filepath", 0, "", ICON_NONE); + uiItemR(row, ptr, "filepath", DEFAULT_FLAGS, "", ICON_NONE); } uiItemO(row, "", ICON_FILE_REFRESH, "node.shader_script_update"); @@ -1129,14 +1133,14 @@ static void node_shader_buts_script_ex(uiLayout *layout, bContext *C, PointerRNA #if 0 /* not implemented yet */ if (RNA_enum_get(ptr, "mode") == NODE_SCRIPT_EXTERNAL) { - uiItemR(layout, ptr, "use_auto_update", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "use_auto_update", DEFAULT_FLAGS, NULL, ICON_NONE); } #endif } static void node_buts_output_shader(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "target", 0, "", ICON_NONE); + uiItemR(layout, ptr, "target", DEFAULT_FLAGS, "", ICON_NONE); } static void node_buts_output_linestyle(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) @@ -1145,32 +1149,32 @@ static void node_buts_output_linestyle(uiLayout *layout, bContext *UNUSED(C), Po col = uiLayoutColumn(layout, false); row = uiLayoutRow(col, true); - uiItemR(row, ptr, "blend_type", 0, "", ICON_NONE); - uiItemR(col, ptr, "use_clamp", 0, NULL, ICON_NONE); + uiItemR(row, ptr, "blend_type", DEFAULT_FLAGS, "", ICON_NONE); + uiItemR(col, ptr, "use_clamp", DEFAULT_FLAGS, NULL, ICON_NONE); } static void node_shader_buts_bevel(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "samples", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "samples", DEFAULT_FLAGS, NULL, ICON_NONE); } static void node_shader_buts_ambient_occlusion(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "samples", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "inside", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "only_local", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "samples", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(layout, ptr, "inside", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(layout, ptr, "only_local", DEFAULT_FLAGS, NULL, ICON_NONE); } static void node_shader_buts_white_noise(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "noise_dimensions", 0, "", ICON_NONE); + uiItemR(layout, ptr, "noise_dimensions", DEFAULT_FLAGS, "", ICON_NONE); } static void node_shader_buts_output_aov(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "name", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "name", DEFAULT_FLAGS, NULL, ICON_NONE); } /* only once called */ @@ -1355,10 +1359,10 @@ static void node_buts_image_views(uiLayout *layout, if (RNA_boolean_get(ptr, "has_views")) { if (RNA_enum_get(ptr, "view") == 0) { - uiItemR(col, ptr, "view", 0, NULL, ICON_CAMERA_STEREO); + uiItemR(col, ptr, "view", DEFAULT_FLAGS, NULL, ICON_CAMERA_STEREO); } else { - uiItemR(col, ptr, "view", 0, NULL, ICON_SCENE); + uiItemR(col, ptr, "view", DEFAULT_FLAGS, NULL, ICON_SCENE); } } } @@ -1419,7 +1423,7 @@ static void node_composit_buts_viewlayers(uiLayout *layout, bContext *C, Pointer col = uiLayoutColumn(layout, false); row = uiLayoutRow(col, true); - uiItemR(row, ptr, "layer", 0, "", ICON_NONE); + uiItemR(row, ptr, "layer", DEFAULT_FLAGS, "", ICON_NONE); prop = RNA_struct_find_property(ptr, "layer"); if (!(RNA_property_enum_identifier( @@ -1446,56 +1450,56 @@ static void node_composit_buts_blur(uiLayout *layout, bContext *UNUSED(C), Point filter = RNA_enum_get(ptr, "filter_type"); reference = RNA_boolean_get(ptr, "use_variable_size"); - uiItemR(col, ptr, "filter_type", 0, "", ICON_NONE); + uiItemR(col, ptr, "filter_type", DEFAULT_FLAGS, "", ICON_NONE); if (filter != R_FILTER_FAST_GAUSS) { - uiItemR(col, ptr, "use_variable_size", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "use_variable_size", DEFAULT_FLAGS, NULL, ICON_NONE); if (!reference) { - uiItemR(col, ptr, "use_bokeh", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "use_bokeh", DEFAULT_FLAGS, NULL, ICON_NONE); } - uiItemR(col, ptr, "use_gamma_correction", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "use_gamma_correction", DEFAULT_FLAGS, NULL, ICON_NONE); } - uiItemR(col, ptr, "use_relative", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "use_relative", DEFAULT_FLAGS, NULL, ICON_NONE); if (RNA_boolean_get(ptr, "use_relative")) { uiItemL(col, IFACE_("Aspect Correction"), ICON_NONE); row = uiLayoutRow(layout, true); - uiItemR(row, ptr, "aspect_correction", UI_ITEM_R_EXPAND, NULL, ICON_NONE); + uiItemR(row, ptr, "aspect_correction", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE); col = uiLayoutColumn(layout, true); - uiItemR(col, ptr, "factor_x", 0, IFACE_("X"), ICON_NONE); - uiItemR(col, ptr, "factor_y", 0, IFACE_("Y"), ICON_NONE); + uiItemR(col, ptr, "factor_x", DEFAULT_FLAGS, IFACE_("X"), ICON_NONE); + uiItemR(col, ptr, "factor_y", DEFAULT_FLAGS, IFACE_("Y"), ICON_NONE); } else { col = uiLayoutColumn(layout, true); - uiItemR(col, ptr, "size_x", 0, IFACE_("X"), ICON_NONE); - uiItemR(col, ptr, "size_y", 0, IFACE_("Y"), ICON_NONE); + uiItemR(col, ptr, "size_x", DEFAULT_FLAGS, IFACE_("X"), ICON_NONE); + uiItemR(col, ptr, "size_y", DEFAULT_FLAGS, IFACE_("Y"), ICON_NONE); } - uiItemR(col, ptr, "use_extended_bounds", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "use_extended_bounds", DEFAULT_FLAGS, NULL, ICON_NONE); } static void node_composit_buts_dblur(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiLayout *col; - uiItemR(layout, ptr, "iterations", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "use_wrap", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "iterations", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(layout, ptr, "use_wrap", DEFAULT_FLAGS, NULL, ICON_NONE); col = uiLayoutColumn(layout, true); uiItemL(col, IFACE_("Center:"), ICON_NONE); - uiItemR(col, ptr, "center_x", 0, IFACE_("X"), ICON_NONE); - uiItemR(col, ptr, "center_y", 0, IFACE_("Y"), ICON_NONE); + uiItemR(col, ptr, "center_x", DEFAULT_FLAGS, IFACE_("X"), ICON_NONE); + uiItemR(col, ptr, "center_y", DEFAULT_FLAGS, IFACE_("Y"), ICON_NONE); uiItemS(layout); col = uiLayoutColumn(layout, true); - uiItemR(col, ptr, "distance", 0, NULL, ICON_NONE); - uiItemR(col, ptr, "angle", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "distance", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(col, ptr, "angle", DEFAULT_FLAGS, NULL, ICON_NONE); uiItemS(layout); - uiItemR(layout, ptr, "spin", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "zoom", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "spin", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(layout, ptr, "zoom", DEFAULT_FLAGS, NULL, ICON_NONE); } static void node_composit_buts_bilateralblur(uiLayout *layout, @@ -1505,9 +1509,9 @@ static void node_composit_buts_bilateralblur(uiLayout *layout, uiLayout *col; col = uiLayoutColumn(layout, true); - uiItemR(col, ptr, "iterations", 0, NULL, ICON_NONE); - uiItemR(col, ptr, "sigma_color", 0, NULL, ICON_NONE); - uiItemR(col, ptr, "sigma_space", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "iterations", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(col, ptr, "sigma_color", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(col, ptr, "sigma_space", DEFAULT_FLAGS, NULL, ICON_NONE); } static void node_composit_buts_defocus(uiLayout *layout, bContext *C, PointerRNA *ptr) @@ -1516,60 +1520,60 @@ static void node_composit_buts_defocus(uiLayout *layout, bContext *C, PointerRNA col = uiLayoutColumn(layout, false); uiItemL(col, IFACE_("Bokeh Type:"), ICON_NONE); - uiItemR(col, ptr, "bokeh", 0, "", ICON_NONE); - uiItemR(col, ptr, "angle", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "bokeh", DEFAULT_FLAGS, "", ICON_NONE); + uiItemR(col, ptr, "angle", DEFAULT_FLAGS, NULL, ICON_NONE); - uiItemR(layout, ptr, "use_gamma_correction", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "use_gamma_correction", DEFAULT_FLAGS, NULL, ICON_NONE); col = uiLayoutColumn(layout, false); uiLayoutSetActive(col, RNA_boolean_get(ptr, "use_zbuffer") == true); - uiItemR(col, ptr, "f_stop", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "f_stop", DEFAULT_FLAGS, NULL, ICON_NONE); - uiItemR(layout, ptr, "blur_max", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "threshold", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "blur_max", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(layout, ptr, "threshold", DEFAULT_FLAGS, NULL, ICON_NONE); col = uiLayoutColumn(layout, false); - uiItemR(col, ptr, "use_preview", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "use_preview", DEFAULT_FLAGS, NULL, ICON_NONE); uiTemplateID(layout, C, ptr, "scene", NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL, false, NULL); col = uiLayoutColumn(layout, false); - uiItemR(col, ptr, "use_zbuffer", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "use_zbuffer", DEFAULT_FLAGS, NULL, ICON_NONE); sub = uiLayoutColumn(col, false); uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_zbuffer") == false); - uiItemR(sub, ptr, "z_scale", 0, NULL, ICON_NONE); + uiItemR(sub, ptr, "z_scale", DEFAULT_FLAGS, NULL, ICON_NONE); } /* qdn: glare node */ static void node_composit_buts_glare(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "glare_type", 0, "", ICON_NONE); - uiItemR(layout, ptr, "quality", 0, "", ICON_NONE); + uiItemR(layout, ptr, "glare_type", DEFAULT_FLAGS, "", ICON_NONE); + uiItemR(layout, ptr, "quality", DEFAULT_FLAGS, "", ICON_NONE); if (RNA_enum_get(ptr, "glare_type") != 1) { - uiItemR(layout, ptr, "iterations", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "iterations", DEFAULT_FLAGS, NULL, ICON_NONE); if (RNA_enum_get(ptr, "glare_type") != 0) { - uiItemR(layout, ptr, "color_modulation", UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(layout, ptr, "color_modulation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); } } - uiItemR(layout, ptr, "mix", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "threshold", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "mix", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(layout, ptr, "threshold", DEFAULT_FLAGS, NULL, ICON_NONE); if (RNA_enum_get(ptr, "glare_type") == 2) { - uiItemR(layout, ptr, "streaks", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "angle_offset", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "streaks", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(layout, ptr, "angle_offset", DEFAULT_FLAGS, NULL, ICON_NONE); } if (RNA_enum_get(ptr, "glare_type") == 0 || RNA_enum_get(ptr, "glare_type") == 2) { - uiItemR(layout, ptr, "fade", UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(layout, ptr, "fade", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); if (RNA_enum_get(ptr, "glare_type") == 0) { - uiItemR(layout, ptr, "use_rotate_45", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "use_rotate_45", DEFAULT_FLAGS, NULL, ICON_NONE); } } if (RNA_enum_get(ptr, "glare_type") == 1) { - uiItemR(layout, ptr, "size", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "size", DEFAULT_FLAGS, NULL, ICON_NONE); } } @@ -1578,17 +1582,17 @@ static void node_composit_buts_tonemap(uiLayout *layout, bContext *UNUSED(C), Po uiLayout *col; col = uiLayoutColumn(layout, false); - uiItemR(col, ptr, "tonemap_type", 0, "", ICON_NONE); + uiItemR(col, ptr, "tonemap_type", DEFAULT_FLAGS, "", ICON_NONE); if (RNA_enum_get(ptr, "tonemap_type") == 0) { - uiItemR(col, ptr, "key", UI_ITEM_R_SLIDER, NULL, ICON_NONE); - uiItemR(col, ptr, "offset", 0, NULL, ICON_NONE); - uiItemR(col, ptr, "gamma", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "key", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(col, ptr, "offset", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(col, ptr, "gamma", DEFAULT_FLAGS, NULL, ICON_NONE); } else { - uiItemR(col, ptr, "intensity", 0, NULL, ICON_NONE); - uiItemR(col, ptr, "contrast", UI_ITEM_R_SLIDER, NULL, ICON_NONE); - uiItemR(col, ptr, "adaptation", UI_ITEM_R_SLIDER, NULL, ICON_NONE); - uiItemR(col, ptr, "correction", UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(col, ptr, "intensity", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(col, ptr, "contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(col, ptr, "adaptation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(col, ptr, "correction", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); } } @@ -1597,12 +1601,12 @@ static void node_composit_buts_lensdist(uiLayout *layout, bContext *UNUSED(C), P uiLayout *col; col = uiLayoutColumn(layout, false); - uiItemR(col, ptr, "use_projector", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "use_projector", DEFAULT_FLAGS, NULL, ICON_NONE); col = uiLayoutColumn(col, false); uiLayoutSetActive(col, RNA_boolean_get(ptr, "use_projector") == false); - uiItemR(col, ptr, "use_jitter", 0, NULL, ICON_NONE); - uiItemR(col, ptr, "use_fit", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "use_jitter", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(col, ptr, "use_fit", DEFAULT_FLAGS, NULL, ICON_NONE); } static void node_composit_buts_vecblur(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) @@ -1610,46 +1614,46 @@ static void node_composit_buts_vecblur(uiLayout *layout, bContext *UNUSED(C), Po uiLayout *col; col = uiLayoutColumn(layout, false); - uiItemR(col, ptr, "samples", 0, NULL, ICON_NONE); - uiItemR(col, ptr, "factor", 0, IFACE_("Blur"), ICON_NONE); + uiItemR(col, ptr, "samples", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(col, ptr, "factor", DEFAULT_FLAGS, IFACE_("Blur"), ICON_NONE); col = uiLayoutColumn(layout, true); uiItemL(col, IFACE_("Speed:"), ICON_NONE); - uiItemR(col, ptr, "speed_min", 0, IFACE_("Min"), ICON_NONE); - uiItemR(col, ptr, "speed_max", 0, IFACE_("Max"), ICON_NONE); + uiItemR(col, ptr, "speed_min", DEFAULT_FLAGS, IFACE_("Min"), ICON_NONE); + uiItemR(col, ptr, "speed_max", DEFAULT_FLAGS, IFACE_("Max"), ICON_NONE); - uiItemR(layout, ptr, "use_curved", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "use_curved", DEFAULT_FLAGS, NULL, ICON_NONE); } static void node_composit_buts_filter(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "filter_type", 0, "", ICON_NONE); + uiItemR(layout, ptr, "filter_type", DEFAULT_FLAGS, "", ICON_NONE); } static void node_composit_buts_flip(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "axis", 0, "", ICON_NONE); + uiItemR(layout, ptr, "axis", DEFAULT_FLAGS, "", ICON_NONE); } static void node_composit_buts_crop(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiLayout *col; - uiItemR(layout, ptr, "use_crop_size", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "relative", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "use_crop_size", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(layout, ptr, "relative", DEFAULT_FLAGS, NULL, ICON_NONE); col = uiLayoutColumn(layout, true); if (RNA_boolean_get(ptr, "relative")) { - uiItemR(col, ptr, "rel_min_x", 0, IFACE_("Left"), ICON_NONE); - uiItemR(col, ptr, "rel_max_x", 0, IFACE_("Right"), ICON_NONE); - uiItemR(col, ptr, "rel_min_y", 0, IFACE_("Up"), ICON_NONE); - uiItemR(col, ptr, "rel_max_y", 0, IFACE_("Down"), ICON_NONE); + uiItemR(col, ptr, "rel_min_x", DEFAULT_FLAGS, IFACE_("Left"), ICON_NONE); + uiItemR(col, ptr, "rel_max_x", DEFAULT_FLAGS, IFACE_("Right"), ICON_NONE); + uiItemR(col, ptr, "rel_min_y", DEFAULT_FLAGS, IFACE_("Up"), ICON_NONE); + uiItemR(col, ptr, "rel_max_y", DEFAULT_FLAGS, IFACE_("Down"), ICON_NONE); } else { - uiItemR(col, ptr, "min_x", 0, IFACE_("Left"), ICON_NONE); - uiItemR(col, ptr, "max_x", 0, IFACE_("Right"), ICON_NONE); - uiItemR(col, ptr, "min_y", 0, IFACE_("Up"), ICON_NONE); - uiItemR(col, ptr, "max_y", 0, IFACE_("Down"), ICON_NONE); + uiItemR(col, ptr, "min_x", DEFAULT_FLAGS, IFACE_("Left"), ICON_NONE); + uiItemR(col, ptr, "max_x", DEFAULT_FLAGS, IFACE_("Right"), ICON_NONE); + uiItemR(col, ptr, "min_y", DEFAULT_FLAGS, IFACE_("Up"), ICON_NONE); + uiItemR(col, ptr, "max_y", DEFAULT_FLAGS, IFACE_("Down"), ICON_NONE); } } @@ -1659,8 +1663,8 @@ static void node_composit_buts_splitviewer(uiLayout *layout, bContext *UNUSED(C) col = uiLayoutColumn(layout, false); row = uiLayoutRow(col, false); - uiItemR(row, ptr, "axis", UI_ITEM_R_EXPAND, NULL, ICON_NONE); - uiItemR(col, ptr, "factor", 0, NULL, ICON_NONE); + uiItemR(row, ptr, "axis", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE); + uiItemR(col, ptr, "factor", DEFAULT_FLAGS, NULL, ICON_NONE); } static void node_composit_buts_double_edge_mask(uiLayout *layout, @@ -1672,9 +1676,9 @@ static void node_composit_buts_double_edge_mask(uiLayout *layout, col = uiLayoutColumn(layout, false); uiItemL(col, IFACE_("Inner Edge:"), ICON_NONE); - uiItemR(col, ptr, "inner_mode", 0, "", ICON_NONE); + uiItemR(col, ptr, "inner_mode", DEFAULT_FLAGS, "", ICON_NONE); uiItemL(col, IFACE_("Buffer Edge:"), ICON_NONE); - uiItemR(col, ptr, "edge_mode", 0, "", ICON_NONE); + uiItemR(col, ptr, "edge_mode", DEFAULT_FLAGS, "", ICON_NONE); } static void node_composit_buts_map_range(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) @@ -1682,7 +1686,7 @@ static void node_composit_buts_map_range(uiLayout *layout, bContext *UNUSED(C), uiLayout *col; col = uiLayoutColumn(layout, true); - uiItemR(col, ptr, "use_clamp", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "use_clamp", DEFAULT_FLAGS, NULL, ICON_NONE); } static void node_composit_buts_map_value(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) @@ -1690,20 +1694,20 @@ static void node_composit_buts_map_value(uiLayout *layout, bContext *UNUSED(C), uiLayout *sub, *col; col = uiLayoutColumn(layout, true); - uiItemR(col, ptr, "offset", 0, NULL, ICON_NONE); - uiItemR(col, ptr, "size", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "offset", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(col, ptr, "size", DEFAULT_FLAGS, NULL, ICON_NONE); col = uiLayoutColumn(layout, true); - uiItemR(col, ptr, "use_min", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "use_min", DEFAULT_FLAGS, NULL, ICON_NONE); sub = uiLayoutColumn(col, false); uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_min")); - uiItemR(sub, ptr, "min", 0, "", ICON_NONE); + uiItemR(sub, ptr, "min", DEFAULT_FLAGS, "", ICON_NONE); col = uiLayoutColumn(layout, true); - uiItemR(col, ptr, "use_max", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "use_max", DEFAULT_FLAGS, NULL, ICON_NONE); sub = uiLayoutColumn(col, false); uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_max")); - uiItemR(sub, ptr, "max", 0, "", ICON_NONE); + uiItemR(sub, ptr, "max", DEFAULT_FLAGS, "", ICON_NONE); } static void node_composit_buts_alphaover(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) @@ -1711,8 +1715,8 @@ static void node_composit_buts_alphaover(uiLayout *layout, bContext *UNUSED(C), uiLayout *col; col = uiLayoutColumn(layout, true); - uiItemR(col, ptr, "use_premultiply", 0, NULL, ICON_NONE); - uiItemR(col, ptr, "premul", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "use_premultiply", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(col, ptr, "premul", DEFAULT_FLAGS, NULL, ICON_NONE); } static void node_composit_buts_zcombine(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) @@ -1720,27 +1724,27 @@ static void node_composit_buts_zcombine(uiLayout *layout, bContext *UNUSED(C), P uiLayout *col; col = uiLayoutColumn(layout, true); - uiItemR(col, ptr, "use_alpha", 0, NULL, ICON_NONE); - uiItemR(col, ptr, "use_antialias_z", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "use_alpha", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(col, ptr, "use_antialias_z", DEFAULT_FLAGS, NULL, ICON_NONE); } static void node_composit_buts_dilateerode(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "mode", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "distance", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "mode", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(layout, ptr, "distance", DEFAULT_FLAGS, NULL, ICON_NONE); switch (RNA_enum_get(ptr, "mode")) { case CMP_NODE_DILATEERODE_DISTANCE_THRESH: - uiItemR(layout, ptr, "edge", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "edge", DEFAULT_FLAGS, NULL, ICON_NONE); break; case CMP_NODE_DILATEERODE_DISTANCE_FEATHER: - uiItemR(layout, ptr, "falloff", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "falloff", DEFAULT_FLAGS, NULL, ICON_NONE); break; } } static void node_composit_buts_inpaint(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "distance", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "distance", DEFAULT_FLAGS, NULL, ICON_NONE); } static void node_composit_buts_despeckle(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) @@ -1748,8 +1752,8 @@ static void node_composit_buts_despeckle(uiLayout *layout, bContext *UNUSED(C), uiLayout *col; col = uiLayoutColumn(layout, false); - uiItemR(col, ptr, "threshold", 0, NULL, ICON_NONE); - uiItemR(col, ptr, "threshold_neighbor", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "threshold", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(col, ptr, "threshold_neighbor", DEFAULT_FLAGS, NULL, ICON_NONE); } static void node_composit_buts_diff_matte(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) @@ -1757,8 +1761,8 @@ static void node_composit_buts_diff_matte(uiLayout *layout, bContext *UNUSED(C), uiLayout *col; col = uiLayoutColumn(layout, true); - uiItemR(col, ptr, "tolerance", UI_ITEM_R_SLIDER, NULL, ICON_NONE); - uiItemR(col, ptr, "falloff", UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(col, ptr, "tolerance", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(col, ptr, "falloff", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); } static void node_composit_buts_distance_matte(uiLayout *layout, @@ -1771,10 +1775,10 @@ static void node_composit_buts_distance_matte(uiLayout *layout, uiItemL(layout, IFACE_("Color Space:"), ICON_NONE); row = uiLayoutRow(layout, false); - uiItemR(row, ptr, "channel", UI_ITEM_R_EXPAND, NULL, ICON_NONE); + uiItemR(row, ptr, "channel", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE); - uiItemR(col, ptr, "tolerance", UI_ITEM_R_SLIDER, NULL, ICON_NONE); - uiItemR(col, ptr, "falloff", UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(col, ptr, "tolerance", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(col, ptr, "falloff", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); } static void node_composit_buts_color_spill(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) @@ -1783,23 +1787,23 @@ static void node_composit_buts_color_spill(uiLayout *layout, bContext *UNUSED(C) uiItemL(layout, IFACE_("Despill Channel:"), ICON_NONE); row = uiLayoutRow(layout, false); - uiItemR(row, ptr, "channel", UI_ITEM_R_EXPAND, NULL, ICON_NONE); + uiItemR(row, ptr, "channel", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE); col = uiLayoutColumn(layout, false); - uiItemR(col, ptr, "limit_method", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "limit_method", DEFAULT_FLAGS, NULL, ICON_NONE); if (RNA_enum_get(ptr, "limit_method") == 0) { uiItemL(col, IFACE_("Limiting Channel:"), ICON_NONE); row = uiLayoutRow(col, false); - uiItemR(row, ptr, "limit_channel", UI_ITEM_R_EXPAND, NULL, ICON_NONE); + uiItemR(row, ptr, "limit_channel", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE); } - uiItemR(col, ptr, "ratio", UI_ITEM_R_SLIDER, NULL, ICON_NONE); - uiItemR(col, ptr, "use_unspill", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "ratio", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(col, ptr, "use_unspill", DEFAULT_FLAGS, NULL, ICON_NONE); if (RNA_boolean_get(ptr, "use_unspill") == true) { - uiItemR(col, ptr, "unspill_red", UI_ITEM_R_SLIDER, NULL, ICON_NONE); - uiItemR(col, ptr, "unspill_green", UI_ITEM_R_SLIDER, NULL, ICON_NONE); - uiItemR(col, ptr, "unspill_blue", UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(col, ptr, "unspill_red", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(col, ptr, "unspill_green", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(col, ptr, "unspill_blue", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); } } @@ -1808,12 +1812,12 @@ static void node_composit_buts_chroma_matte(uiLayout *layout, bContext *UNUSED(C uiLayout *col; col = uiLayoutColumn(layout, false); - uiItemR(col, ptr, "tolerance", 0, NULL, ICON_NONE); - uiItemR(col, ptr, "threshold", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "tolerance", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(col, ptr, "threshold", DEFAULT_FLAGS, NULL, ICON_NONE); col = uiLayoutColumn(layout, true); /*uiItemR(col, ptr, "lift", UI_ITEM_R_SLIDER, NULL, ICON_NONE); Removed for now */ - uiItemR(col, ptr, "gain", UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(col, ptr, "gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); /*uiItemR(col, ptr, "shadow_adjust", UI_ITEM_R_SLIDER, NULL, ICON_NONE); Removed for now*/ } @@ -1822,9 +1826,9 @@ static void node_composit_buts_color_matte(uiLayout *layout, bContext *UNUSED(C) uiLayout *col; col = uiLayoutColumn(layout, true); - uiItemR(col, ptr, "color_hue", UI_ITEM_R_SLIDER, NULL, ICON_NONE); - uiItemR(col, ptr, "color_saturation", UI_ITEM_R_SLIDER, NULL, ICON_NONE); - uiItemR(col, ptr, "color_value", UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(col, ptr, "color_hue", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(col, ptr, "color_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(col, ptr, "color_value", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); } static void node_composit_buts_channel_matte(uiLayout *layout, @@ -1835,24 +1839,24 @@ static void node_composit_buts_channel_matte(uiLayout *layout, uiItemL(layout, IFACE_("Color Space:"), ICON_NONE); row = uiLayoutRow(layout, false); - uiItemR(row, ptr, "color_space", UI_ITEM_R_EXPAND, NULL, ICON_NONE); + uiItemR(row, ptr, "color_space", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE); col = uiLayoutColumn(layout, false); uiItemL(col, IFACE_("Key Channel:"), ICON_NONE); row = uiLayoutRow(col, false); - uiItemR(row, ptr, "matte_channel", UI_ITEM_R_EXPAND, NULL, ICON_NONE); + uiItemR(row, ptr, "matte_channel", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE); col = uiLayoutColumn(layout, false); - uiItemR(col, ptr, "limit_method", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "limit_method", DEFAULT_FLAGS, NULL, ICON_NONE); if (RNA_enum_get(ptr, "limit_method") == 0) { uiItemL(col, IFACE_("Limiting Channel:"), ICON_NONE); row = uiLayoutRow(col, false); - uiItemR(row, ptr, "limit_channel", UI_ITEM_R_EXPAND, NULL, ICON_NONE); + uiItemR(row, ptr, "limit_channel", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE); } - uiItemR(col, ptr, "limit_max", UI_ITEM_R_SLIDER, NULL, ICON_NONE); - uiItemR(col, ptr, "limit_min", UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(col, ptr, "limit_max", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(col, ptr, "limit_min", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); } static void node_composit_buts_luma_matte(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) @@ -1860,19 +1864,19 @@ static void node_composit_buts_luma_matte(uiLayout *layout, bContext *UNUSED(C), uiLayout *col; col = uiLayoutColumn(layout, true); - uiItemR(col, ptr, "limit_max", UI_ITEM_R_SLIDER, NULL, ICON_NONE); - uiItemR(col, ptr, "limit_min", UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(col, ptr, "limit_max", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(col, ptr, "limit_min", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); } static void node_composit_buts_map_uv(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "alpha", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "alpha", DEFAULT_FLAGS, NULL, ICON_NONE); } static void node_composit_buts_id_mask(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "index", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "use_antialiasing", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "index", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(layout, ptr, "use_antialiasing", DEFAULT_FLAGS, NULL, ICON_NONE); } static void node_composit_buts_file_output(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) @@ -1886,7 +1890,7 @@ static void node_composit_buts_file_output(uiLayout *layout, bContext *UNUSED(C) else { uiItemL(layout, IFACE_("Base Path:"), ICON_NONE); } - uiItemR(layout, ptr, "base_path", 0, "", ICON_NONE); + uiItemR(layout, ptr, "base_path", DEFAULT_FLAGS, "", ICON_NONE); } static void node_composit_buts_file_output_ex(uiLayout *layout, bContext *C, PointerRNA *ptr) { @@ -1972,7 +1976,7 @@ static void node_composit_buts_file_output_ex(uiLayout *layout, bContext *C, Poi uiItemL(col, IFACE_("Layer:"), ICON_NONE); row = uiLayoutRow(col, false); - uiItemR(row, &active_input_ptr, "name", 0, "", ICON_NONE); + uiItemR(row, &active_input_ptr, "name", DEFAULT_FLAGS, "", ICON_NONE); uiItemFullO(row, "NODE_OT_output_file_remove_active_socket", "", @@ -1987,7 +1991,7 @@ static void node_composit_buts_file_output_ex(uiLayout *layout, bContext *C, Poi uiItemL(col, IFACE_("File Subpath:"), ICON_NONE); row = uiLayoutRow(col, false); - uiItemR(row, &active_input_ptr, "path", 0, "", ICON_NONE); + uiItemR(row, &active_input_ptr, "path", DEFAULT_FLAGS, "", ICON_NONE); uiItemFullO(row, "NODE_OT_output_file_remove_active_socket", "", @@ -2002,7 +2006,7 @@ static void node_composit_buts_file_output_ex(uiLayout *layout, bContext *C, Poi col = uiLayoutColumn(layout, true); uiItemL(col, IFACE_("Format:"), ICON_NONE); - uiItemR(col, &active_input_ptr, "use_node_format", 0, NULL, ICON_NONE); + uiItemR(col, &active_input_ptr, "use_node_format", DEFAULT_FLAGS, NULL, ICON_NONE); col = uiLayoutColumn(layout, false); uiLayoutSetActive(col, RNA_boolean_get(&active_input_ptr, "use_node_format") == false); @@ -2017,20 +2021,20 @@ static void node_composit_buts_file_output_ex(uiLayout *layout, bContext *C, Poi static void node_composit_buts_scale(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "space", 0, "", ICON_NONE); + uiItemR(layout, ptr, "space", DEFAULT_FLAGS, "", ICON_NONE); if (RNA_enum_get(ptr, "space") == CMP_SCALE_RENDERPERCENT) { uiLayout *row; - uiItemR(layout, ptr, "frame_method", UI_ITEM_R_EXPAND, NULL, ICON_NONE); + uiItemR(layout, ptr, "frame_method", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE); row = uiLayoutRow(layout, true); - uiItemR(row, ptr, "offset_x", 0, "X", ICON_NONE); - uiItemR(row, ptr, "offset_y", 0, "Y", ICON_NONE); + uiItemR(row, ptr, "offset_x", DEFAULT_FLAGS, "X", ICON_NONE); + uiItemR(row, ptr, "offset_y", DEFAULT_FLAGS, "Y", ICON_NONE); } } static void node_composit_buts_rotate(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "filter_type", 0, "", ICON_NONE); + uiItemR(layout, ptr, "filter_type", DEFAULT_FLAGS, "", ICON_NONE); } static void node_composit_buts_invert(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) @@ -2038,25 +2042,25 @@ static void node_composit_buts_invert(uiLayout *layout, bContext *UNUSED(C), Poi uiLayout *col; col = uiLayoutColumn(layout, false); - uiItemR(col, ptr, "invert_rgb", 0, NULL, ICON_NONE); - uiItemR(col, ptr, "invert_alpha", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "invert_rgb", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(col, ptr, "invert_alpha", DEFAULT_FLAGS, NULL, ICON_NONE); } static void node_composit_buts_premulkey(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "mapping", 0, "", ICON_NONE); + uiItemR(layout, ptr, "mapping", DEFAULT_FLAGS, "", ICON_NONE); } static void node_composit_buts_view_levels(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "channel", UI_ITEM_R_EXPAND, NULL, ICON_NONE); + uiItemR(layout, ptr, "channel", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE); } static void node_composit_buts_colorbalance(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiLayout *split, *col, *row; - uiItemR(layout, ptr, "correction_method", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "correction_method", DEFAULT_FLAGS, NULL, ICON_NONE); if (RNA_enum_get(ptr, "correction_method") == 0) { @@ -2064,17 +2068,17 @@ static void node_composit_buts_colorbalance(uiLayout *layout, bContext *UNUSED(C col = uiLayoutColumn(split, false); uiTemplateColorPicker(col, ptr, "lift", 1, 1, 0, 1); row = uiLayoutRow(col, false); - uiItemR(row, ptr, "lift", 0, NULL, ICON_NONE); + uiItemR(row, ptr, "lift", DEFAULT_FLAGS, NULL, ICON_NONE); col = uiLayoutColumn(split, false); uiTemplateColorPicker(col, ptr, "gamma", 1, 1, 1, 1); row = uiLayoutRow(col, false); - uiItemR(row, ptr, "gamma", 0, NULL, ICON_NONE); + uiItemR(row, ptr, "gamma", DEFAULT_FLAGS, NULL, ICON_NONE); col = uiLayoutColumn(split, false); uiTemplateColorPicker(col, ptr, "gain", 1, 1, 1, 1); row = uiLayoutRow(col, false); - uiItemR(row, ptr, "gain", 0, NULL, ICON_NONE); + uiItemR(row, ptr, "gain", DEFAULT_FLAGS, NULL, ICON_NONE); } else { @@ -2082,46 +2086,46 @@ static void node_composit_buts_colorbalance(uiLayout *layout, bContext *UNUSED(C col = uiLayoutColumn(split, false); uiTemplateColorPicker(col, ptr, "offset", 1, 1, 0, 1); row = uiLayoutRow(col, false); - uiItemR(row, ptr, "offset", 0, NULL, ICON_NONE); - uiItemR(col, ptr, "offset_basis", 0, NULL, ICON_NONE); + uiItemR(row, ptr, "offset", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(col, ptr, "offset_basis", DEFAULT_FLAGS, NULL, ICON_NONE); col = uiLayoutColumn(split, false); uiTemplateColorPicker(col, ptr, "power", 1, 1, 0, 1); row = uiLayoutRow(col, false); - uiItemR(row, ptr, "power", 0, NULL, ICON_NONE); + uiItemR(row, ptr, "power", DEFAULT_FLAGS, NULL, ICON_NONE); col = uiLayoutColumn(split, false); uiTemplateColorPicker(col, ptr, "slope", 1, 1, 0, 1); row = uiLayoutRow(col, false); - uiItemR(row, ptr, "slope", 0, NULL, ICON_NONE); + uiItemR(row, ptr, "slope", DEFAULT_FLAGS, NULL, ICON_NONE); } } static void node_composit_buts_colorbalance_ex(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "correction_method", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "correction_method", DEFAULT_FLAGS, NULL, ICON_NONE); if (RNA_enum_get(ptr, "correction_method") == 0) { uiTemplateColorPicker(layout, ptr, "lift", 1, 1, 0, 1); - uiItemR(layout, ptr, "lift", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "lift", DEFAULT_FLAGS, NULL, ICON_NONE); uiTemplateColorPicker(layout, ptr, "gamma", 1, 1, 1, 1); - uiItemR(layout, ptr, "gamma", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "gamma", DEFAULT_FLAGS, NULL, ICON_NONE); uiTemplateColorPicker(layout, ptr, "gain", 1, 1, 1, 1); - uiItemR(layout, ptr, "gain", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "gain", DEFAULT_FLAGS, NULL, ICON_NONE); } else { uiTemplateColorPicker(layout, ptr, "offset", 1, 1, 0, 1); - uiItemR(layout, ptr, "offset", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "offset", DEFAULT_FLAGS, NULL, ICON_NONE); uiTemplateColorPicker(layout, ptr, "power", 1, 1, 0, 1); - uiItemR(layout, ptr, "power", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "power", DEFAULT_FLAGS, NULL, ICON_NONE); uiTemplateColorPicker(layout, ptr, "slope", 1, 1, 0, 1); - uiItemR(layout, ptr, "slope", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "slope", DEFAULT_FLAGS, NULL, ICON_NONE); } } @@ -2143,7 +2147,7 @@ static void node_composit_buts_huecorrect(uiLayout *layout, bContext *UNUSED(C), static void node_composit_buts_ycc(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "mode", 0, "", ICON_NONE); + uiItemR(layout, ptr, "mode", DEFAULT_FLAGS, "", ICON_NONE); } static void node_composit_buts_movieclip(uiLayout *layout, bContext *C, PointerRNA *ptr) @@ -2180,19 +2184,19 @@ static void node_composit_buts_stabilize2d(uiLayout *layout, bContext *C, Pointe return; } - uiItemR(layout, ptr, "filter_type", 0, "", ICON_NONE); - uiItemR(layout, ptr, "invert", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "filter_type", DEFAULT_FLAGS, "", ICON_NONE); + uiItemR(layout, ptr, "invert", DEFAULT_FLAGS, NULL, ICON_NONE); } static void node_composit_buts_translate(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "use_relative", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "wrap_axis", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "use_relative", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(layout, ptr, "wrap_axis", DEFAULT_FLAGS, NULL, ICON_NONE); } static void node_composit_buts_transform(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "filter_type", 0, "", ICON_NONE); + uiItemR(layout, ptr, "filter_type", DEFAULT_FLAGS, "", ICON_NONE); } static void node_composit_buts_moviedistortion(uiLayout *layout, bContext *C, PointerRNA *ptr) @@ -2206,7 +2210,7 @@ static void node_composit_buts_moviedistortion(uiLayout *layout, bContext *C, Po return; } - uiItemR(layout, ptr, "distortion_type", 0, "", ICON_NONE); + uiItemR(layout, ptr, "distortion_type", DEFAULT_FLAGS, "", ICON_NONE); } static void node_composit_buts_colorcorrection(uiLayout *layout, @@ -2216,9 +2220,9 @@ static void node_composit_buts_colorcorrection(uiLayout *layout, uiLayout *row; row = uiLayoutRow(layout, false); - uiItemR(row, ptr, "red", 0, NULL, ICON_NONE); - uiItemR(row, ptr, "green", 0, NULL, ICON_NONE); - uiItemR(row, ptr, "blue", 0, NULL, ICON_NONE); + uiItemR(row, ptr, "red", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(row, ptr, "green", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(row, ptr, "blue", DEFAULT_FLAGS, NULL, ICON_NONE); row = uiLayoutRow(layout, false); uiItemL(row, "", ICON_NONE); @@ -2230,39 +2234,39 @@ static void node_composit_buts_colorcorrection(uiLayout *layout, row = uiLayoutRow(layout, false); uiItemL(row, IFACE_("Master"), ICON_NONE); - uiItemR(row, ptr, "master_saturation", UI_ITEM_R_SLIDER, "", ICON_NONE); - uiItemR(row, ptr, "master_contrast", UI_ITEM_R_SLIDER, "", ICON_NONE); - uiItemR(row, ptr, "master_gamma", UI_ITEM_R_SLIDER, "", ICON_NONE); - uiItemR(row, ptr, "master_gain", UI_ITEM_R_SLIDER, "", ICON_NONE); - uiItemR(row, ptr, "master_lift", UI_ITEM_R_SLIDER, "", ICON_NONE); + uiItemR(row, ptr, "master_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE); + uiItemR(row, ptr, "master_contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE); + uiItemR(row, ptr, "master_gamma", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE); + uiItemR(row, ptr, "master_gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE); + uiItemR(row, ptr, "master_lift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE); row = uiLayoutRow(layout, false); uiItemL(row, IFACE_("Highlights"), ICON_NONE); - uiItemR(row, ptr, "highlights_saturation", UI_ITEM_R_SLIDER, "", ICON_NONE); - uiItemR(row, ptr, "highlights_contrast", UI_ITEM_R_SLIDER, "", ICON_NONE); - uiItemR(row, ptr, "highlights_gamma", UI_ITEM_R_SLIDER, "", ICON_NONE); - uiItemR(row, ptr, "highlights_gain", UI_ITEM_R_SLIDER, "", ICON_NONE); - uiItemR(row, ptr, "highlights_lift", UI_ITEM_R_SLIDER, "", ICON_NONE); + uiItemR(row, ptr, "highlights_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE); + uiItemR(row, ptr, "highlights_contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE); + uiItemR(row, ptr, "highlights_gamma", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE); + uiItemR(row, ptr, "highlights_gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE); + uiItemR(row, ptr, "highlights_lift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE); row = uiLayoutRow(layout, false); uiItemL(row, IFACE_("Midtones"), ICON_NONE); - uiItemR(row, ptr, "midtones_saturation", UI_ITEM_R_SLIDER, "", ICON_NONE); - uiItemR(row, ptr, "midtones_contrast", UI_ITEM_R_SLIDER, "", ICON_NONE); - uiItemR(row, ptr, "midtones_gamma", UI_ITEM_R_SLIDER, "", ICON_NONE); - uiItemR(row, ptr, "midtones_gain", UI_ITEM_R_SLIDER, "", ICON_NONE); - uiItemR(row, ptr, "midtones_lift", UI_ITEM_R_SLIDER, "", ICON_NONE); + uiItemR(row, ptr, "midtones_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE); + uiItemR(row, ptr, "midtones_contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE); + uiItemR(row, ptr, "midtones_gamma", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE); + uiItemR(row, ptr, "midtones_gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE); + uiItemR(row, ptr, "midtones_lift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE); row = uiLayoutRow(layout, false); uiItemL(row, IFACE_("Shadows"), ICON_NONE); - uiItemR(row, ptr, "shadows_saturation", UI_ITEM_R_SLIDER, "", ICON_NONE); - uiItemR(row, ptr, "shadows_contrast", UI_ITEM_R_SLIDER, "", ICON_NONE); - uiItemR(row, ptr, "shadows_gamma", UI_ITEM_R_SLIDER, "", ICON_NONE); - uiItemR(row, ptr, "shadows_gain", UI_ITEM_R_SLIDER, "", ICON_NONE); - uiItemR(row, ptr, "shadows_lift", UI_ITEM_R_SLIDER, "", ICON_NONE); + uiItemR(row, ptr, "shadows_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE); + uiItemR(row, ptr, "shadows_contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE); + uiItemR(row, ptr, "shadows_gamma", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE); + uiItemR(row, ptr, "shadows_gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE); + uiItemR(row, ptr, "shadows_lift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE); row = uiLayoutRow(layout, false); - uiItemR(row, ptr, "midtones_start", UI_ITEM_R_SLIDER, NULL, ICON_NONE); - uiItemR(row, ptr, "midtones_end", UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(row, ptr, "midtones_start", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(row, ptr, "midtones_end", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); } static void node_composit_buts_colorcorrection_ex(uiLayout *layout, @@ -2272,48 +2276,48 @@ static void node_composit_buts_colorcorrection_ex(uiLayout *layout, uiLayout *row; row = uiLayoutRow(layout, false); - uiItemR(row, ptr, "red", 0, NULL, ICON_NONE); - uiItemR(row, ptr, "green", 0, NULL, ICON_NONE); - uiItemR(row, ptr, "blue", 0, NULL, ICON_NONE); + uiItemR(row, ptr, "red", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(row, ptr, "green", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(row, ptr, "blue", DEFAULT_FLAGS, NULL, ICON_NONE); row = layout; uiItemL(row, IFACE_("Saturation"), ICON_NONE); - uiItemR(row, ptr, "master_saturation", UI_ITEM_R_SLIDER, NULL, ICON_NONE); - uiItemR(row, ptr, "highlights_saturation", UI_ITEM_R_SLIDER, NULL, ICON_NONE); - uiItemR(row, ptr, "midtones_saturation", UI_ITEM_R_SLIDER, NULL, ICON_NONE); - uiItemR(row, ptr, "shadows_saturation", UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(row, ptr, "master_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(row, ptr, "highlights_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(row, ptr, "midtones_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(row, ptr, "shadows_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); uiItemL(row, IFACE_("Contrast"), ICON_NONE); - uiItemR(row, ptr, "master_contrast", UI_ITEM_R_SLIDER, NULL, ICON_NONE); - uiItemR(row, ptr, "highlights_contrast", UI_ITEM_R_SLIDER, NULL, ICON_NONE); - uiItemR(row, ptr, "midtones_contrast", UI_ITEM_R_SLIDER, NULL, ICON_NONE); - uiItemR(row, ptr, "shadows_contrast", UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(row, ptr, "master_contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(row, ptr, "highlights_contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(row, ptr, "midtones_contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(row, ptr, "shadows_contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); uiItemL(row, IFACE_("Gamma"), ICON_NONE); - uiItemR(row, ptr, "master_gamma", UI_ITEM_R_SLIDER, NULL, ICON_NONE); - uiItemR(row, ptr, "highlights_gamma", UI_ITEM_R_SLIDER, NULL, ICON_NONE); - uiItemR(row, ptr, "midtones_gamma", UI_ITEM_R_SLIDER, NULL, ICON_NONE); - uiItemR(row, ptr, "shadows_gamma", UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(row, ptr, "master_gamma", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(row, ptr, "highlights_gamma", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(row, ptr, "midtones_gamma", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(row, ptr, "shadows_gamma", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); uiItemL(row, IFACE_("Gain"), ICON_NONE); - uiItemR(row, ptr, "master_gain", UI_ITEM_R_SLIDER, NULL, ICON_NONE); - uiItemR(row, ptr, "highlights_gain", UI_ITEM_R_SLIDER, NULL, ICON_NONE); - uiItemR(row, ptr, "midtones_gain", UI_ITEM_R_SLIDER, NULL, ICON_NONE); - uiItemR(row, ptr, "shadows_gain", UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(row, ptr, "master_gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(row, ptr, "highlights_gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(row, ptr, "midtones_gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(row, ptr, "shadows_gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); uiItemL(row, IFACE_("Lift"), ICON_NONE); - uiItemR(row, ptr, "master_lift", UI_ITEM_R_SLIDER, NULL, ICON_NONE); - uiItemR(row, ptr, "highlights_lift", UI_ITEM_R_SLIDER, NULL, ICON_NONE); - uiItemR(row, ptr, "midtones_lift", UI_ITEM_R_SLIDER, NULL, ICON_NONE); - uiItemR(row, ptr, "shadows_lift", UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(row, ptr, "master_lift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(row, ptr, "highlights_lift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(row, ptr, "midtones_lift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(row, ptr, "shadows_lift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); row = uiLayoutRow(layout, false); - uiItemR(row, ptr, "midtones_start", 0, NULL, ICON_NONE); - uiItemR(row, ptr, "midtones_end", 0, NULL, ICON_NONE); + uiItemR(row, ptr, "midtones_start", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(row, ptr, "midtones_end", DEFAULT_FLAGS, NULL, ICON_NONE); } static void node_composit_buts_switch(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "check", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "check", DEFAULT_FLAGS, NULL, ICON_NONE); } static void node_composit_buts_switch_view_ex(uiLayout *layout, @@ -2335,32 +2339,32 @@ static void node_composit_buts_boxmask(uiLayout *layout, bContext *UNUSED(C), Po uiLayout *row; row = uiLayoutRow(layout, true); - uiItemR(row, ptr, "x", 0, NULL, ICON_NONE); - uiItemR(row, ptr, "y", 0, NULL, ICON_NONE); + uiItemR(row, ptr, "x", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(row, ptr, "y", DEFAULT_FLAGS, NULL, ICON_NONE); row = uiLayoutRow(layout, true); - uiItemR(row, ptr, "width", UI_ITEM_R_SLIDER, NULL, ICON_NONE); - uiItemR(row, ptr, "height", UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(row, ptr, "width", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(row, ptr, "height", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); - uiItemR(layout, ptr, "rotation", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "mask_type", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "rotation", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(layout, ptr, "mask_type", DEFAULT_FLAGS, NULL, ICON_NONE); } static void node_composit_buts_bokehimage(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "flaps", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "angle", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "rounding", UI_ITEM_R_SLIDER, NULL, ICON_NONE); - uiItemR(layout, ptr, "catadioptric", UI_ITEM_R_SLIDER, NULL, ICON_NONE); - uiItemR(layout, ptr, "shift", UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(layout, ptr, "flaps", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(layout, ptr, "angle", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(layout, ptr, "rounding", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(layout, ptr, "catadioptric", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(layout, ptr, "shift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); } static void node_composit_buts_bokehblur(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "use_variable_size", 0, NULL, ICON_NONE); - // uiItemR(layout, ptr, "f_stop", 0, NULL, ICON_NONE); // UNUSED - uiItemR(layout, ptr, "blur_max", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "use_extended_bounds", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "use_variable_size", DEFAULT_FLAGS, NULL, ICON_NONE); + // uiItemR(layout, ptr, "f_stop", DEFAULT_FLAGS, NULL, ICON_NONE); // UNUSED + uiItemR(layout, ptr, "blur_max", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(layout, ptr, "use_extended_bounds", DEFAULT_FLAGS, NULL, ICON_NONE); } static void node_composit_backdrop_viewer( @@ -2486,36 +2490,36 @@ static void node_composit_buts_ellipsemask(uiLayout *layout, bContext *UNUSED(C) { uiLayout *row; row = uiLayoutRow(layout, true); - uiItemR(row, ptr, "x", 0, NULL, ICON_NONE); - uiItemR(row, ptr, "y", 0, NULL, ICON_NONE); + uiItemR(row, ptr, "x", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(row, ptr, "y", DEFAULT_FLAGS, NULL, ICON_NONE); row = uiLayoutRow(layout, true); - uiItemR(row, ptr, "width", UI_ITEM_R_SLIDER, NULL, ICON_NONE); - uiItemR(row, ptr, "height", UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(row, ptr, "width", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(row, ptr, "height", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); - uiItemR(layout, ptr, "rotation", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "mask_type", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "rotation", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(layout, ptr, "mask_type", DEFAULT_FLAGS, NULL, ICON_NONE); } static void node_composit_buts_composite(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "use_alpha", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "use_alpha", DEFAULT_FLAGS, NULL, ICON_NONE); } static void node_composit_buts_viewer(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "use_alpha", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "use_alpha", DEFAULT_FLAGS, NULL, ICON_NONE); } static void node_composit_buts_viewer_ex(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiLayout *col; - uiItemR(layout, ptr, "use_alpha", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "tile_order", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "use_alpha", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(layout, ptr, "tile_order", DEFAULT_FLAGS, NULL, ICON_NONE); if (RNA_enum_get(ptr, "tile_order") == 0) { col = uiLayoutColumn(layout, true); - uiItemR(col, ptr, "center_x", 0, NULL, ICON_NONE); - uiItemR(col, ptr, "center_y", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "center_x", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(col, ptr, "center_y", DEFAULT_FLAGS, NULL, ICON_NONE); } } @@ -2524,19 +2528,19 @@ static void node_composit_buts_mask(uiLayout *layout, bContext *C, PointerRNA *p bNode *node = ptr->data; uiTemplateID(layout, C, ptr, "mask", NULL, NULL, NULL, UI_TEMPLATE_ID_FILTER_ALL, false, NULL); - uiItemR(layout, ptr, "use_feather", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "use_feather", DEFAULT_FLAGS, NULL, ICON_NONE); - uiItemR(layout, ptr, "size_source", 0, "", ICON_NONE); + uiItemR(layout, ptr, "size_source", DEFAULT_FLAGS, "", ICON_NONE); if (node->custom1 & (CMP_NODEFLAG_MASK_FIXED | CMP_NODEFLAG_MASK_FIXED_SCENE)) { - uiItemR(layout, ptr, "size_x", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "size_y", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "size_x", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(layout, ptr, "size_y", DEFAULT_FLAGS, NULL, ICON_NONE); } - uiItemR(layout, ptr, "use_motion_blur", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "use_motion_blur", DEFAULT_FLAGS, NULL, ICON_NONE); if (node->custom1 & CMP_NODEFLAG_MASK_MOTION_BLUR) { - uiItemR(layout, ptr, "motion_blur_samples", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "motion_blur_shutter", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "motion_blur_samples", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(layout, ptr, "motion_blur_shutter", DEFAULT_FLAGS, NULL, ICON_NONE); } } @@ -2562,18 +2566,18 @@ static void node_composit_buts_keying(uiLayout *layout, bContext *UNUSED(C), Poi { /* bNode *node = ptr->data; */ /* UNUSED */ - uiItemR(layout, ptr, "blur_pre", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "screen_balance", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "despill_factor", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "despill_balance", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "edge_kernel_radius", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "edge_kernel_tolerance", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "clip_black", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "clip_white", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "dilate_distance", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "feather_falloff", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "feather_distance", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "blur_post", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "blur_pre", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(layout, ptr, "screen_balance", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(layout, ptr, "despill_factor", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(layout, ptr, "despill_balance", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(layout, ptr, "edge_kernel_radius", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(layout, ptr, "edge_kernel_tolerance", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(layout, ptr, "clip_black", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(layout, ptr, "clip_white", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(layout, ptr, "dilate_distance", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(layout, ptr, "feather_falloff", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(layout, ptr, "feather_distance", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(layout, ptr, "blur_post", DEFAULT_FLAGS, NULL, ICON_NONE); } static void node_composit_buts_trackpos(uiLayout *layout, bContext *C, PointerRNA *ptr) @@ -2605,13 +2609,13 @@ static void node_composit_buts_trackpos(uiLayout *layout, bContext *C, PointerRN uiItemPointerR(col, ptr, "track_name", &object_ptr, "tracks", "", ICON_ANIM_DATA); } else { - uiItemR(layout, ptr, "track_name", 0, "", ICON_ANIM_DATA); + uiItemR(layout, ptr, "track_name", DEFAULT_FLAGS, "", ICON_ANIM_DATA); } - uiItemR(layout, ptr, "position", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "position", DEFAULT_FLAGS, NULL, ICON_NONE); if (ELEM(node->custom1, CMP_TRACKPOS_RELATIVE_FRAME, CMP_TRACKPOS_ABSOLUTE_FRAME)) { - uiItemR(layout, ptr, "frame_relative", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "frame_relative", DEFAULT_FLAGS, NULL, ICON_NONE); } } } @@ -2650,10 +2654,10 @@ static void node_composit_buts_planetrackdeform(uiLayout *layout, bContext *C, P } } - uiItemR(layout, ptr, "use_motion_blur", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "use_motion_blur", DEFAULT_FLAGS, NULL, ICON_NONE); if (data->flag & CMP_NODEFLAG_PLANETRACKDEFORM_MOTION_BLUR) { - uiItemR(layout, ptr, "motion_blur_samples", 0, NULL, ICON_NONE); - uiItemR(layout, ptr, "motion_blur_shutter", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "motion_blur_samples", DEFAULT_FLAGS, NULL, ICON_NONE); + uiItemR(layout, ptr, "motion_blur_shutter", DEFAULT_FLAGS, NULL, ICON_NONE); } } @@ -2665,8 +2669,8 @@ static void node_composit_buts_cornerpin(uiLayout *UNUSED(layout), static void node_composit_buts_sunbeams(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "source", UI_ITEM_R_EXPAND, "", ICON_NONE); - uiItemR(layout, ptr, "ray_length", UI_ITEM_R_SLIDER, NULL, ICON_NONE); + uiItemR(layout, ptr, "source", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, "", ICON_NONE); + uiItemR(layout, ptr, "ray_length", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, NULL, ICON_NONE); } static void node_composit_buts_cryptomatte(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) @@ -2679,7 +2683,7 @@ static void node_composit_buts_cryptomatte(uiLayout *layout, bContext *UNUSED(C) uiTemplateCryptoPicker(row, ptr, "add"); uiTemplateCryptoPicker(row, ptr, "remove"); - uiItemR(col, ptr, "matte_id", 0, "", ICON_NONE); + uiItemR(col, ptr, "matte_id", DEFAULT_FLAGS, "", ICON_NONE); } static void node_composit_buts_cryptomatte_ex(uiLayout *layout, @@ -2694,7 +2698,7 @@ static void node_composit_buts_brightcontrast(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "use_premultiply", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "use_premultiply", DEFAULT_FLAGS, NULL, ICON_NONE); } static void node_composit_buts_denoise(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) @@ -2707,7 +2711,7 @@ static void node_composit_buts_denoise(uiLayout *layout, bContext *UNUSED(C), Po } #endif - uiItemR(layout, ptr, "use_hdr", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "use_hdr", DEFAULT_FLAGS, NULL, ICON_NONE); } /* only once called */ @@ -2957,12 +2961,12 @@ static void node_texture_buts_bricks(uiLayout *layout, bContext *UNUSED(C), Poin uiLayout *col; col = uiLayoutColumn(layout, true); - uiItemR(col, ptr, "offset", UI_ITEM_R_SLIDER, IFACE_("Offset"), ICON_NONE); - uiItemR(col, ptr, "offset_frequency", 0, IFACE_("Frequency"), ICON_NONE); + uiItemR(col, ptr, "offset", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, IFACE_("Offset"), ICON_NONE); + uiItemR(col, ptr, "offset_frequency", DEFAULT_FLAGS, IFACE_("Frequency"), ICON_NONE); col = uiLayoutColumn(layout, true); - uiItemR(col, ptr, "squash", 0, IFACE_("Squash"), ICON_NONE); - uiItemR(col, ptr, "squash_frequency", 0, IFACE_("Frequency"), ICON_NONE); + uiItemR(col, ptr, "squash", DEFAULT_FLAGS, IFACE_("Squash"), ICON_NONE); + uiItemR(col, ptr, "squash_frequency", DEFAULT_FLAGS, IFACE_("Frequency"), ICON_NONE); } static void node_texture_buts_proc(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) @@ -2979,68 +2983,73 @@ static void node_texture_buts_proc(uiLayout *layout, bContext *UNUSED(C), Pointe switch (tex->type) { case TEX_BLEND: - uiItemR(col, &tex_ptr, "progression", 0, "", ICON_NONE); + uiItemR(col, &tex_ptr, "progression", DEFAULT_FLAGS, "", ICON_NONE); row = uiLayoutRow(col, false); - uiItemR(row, &tex_ptr, "use_flip_axis", UI_ITEM_R_EXPAND, NULL, ICON_NONE); + uiItemR(row, &tex_ptr, "use_flip_axis", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE); break; case TEX_MARBLE: row = uiLayoutRow(col, false); - uiItemR(row, &tex_ptr, "marble_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE); + uiItemR(row, &tex_ptr, "marble_type", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE); row = uiLayoutRow(col, false); - uiItemR(row, &tex_ptr, "noise_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE); + uiItemR(row, &tex_ptr, "noise_type", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE); row = uiLayoutRow(col, false); - uiItemR(row, &tex_ptr, "noise_basis", 0, "", ICON_NONE); + uiItemR(row, &tex_ptr, "noise_basis", DEFAULT_FLAGS, "", ICON_NONE); row = uiLayoutRow(col, false); - uiItemR(row, &tex_ptr, "noise_basis_2", UI_ITEM_R_EXPAND, NULL, ICON_NONE); + uiItemR(row, &tex_ptr, "noise_basis_2", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE); break; case TEX_MAGIC: - uiItemR(col, &tex_ptr, "noise_depth", 0, NULL, ICON_NONE); + uiItemR(col, &tex_ptr, "noise_depth", DEFAULT_FLAGS, NULL, ICON_NONE); break; case TEX_STUCCI: row = uiLayoutRow(col, false); - uiItemR(row, &tex_ptr, "stucci_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE); + uiItemR(row, &tex_ptr, "stucci_type", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE); row = uiLayoutRow(col, false); - uiItemR(row, &tex_ptr, "noise_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE); - uiItemR(col, &tex_ptr, "noise_basis", 0, "", ICON_NONE); + uiItemR(row, &tex_ptr, "noise_type", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE); + uiItemR(col, &tex_ptr, "noise_basis", DEFAULT_FLAGS, "", ICON_NONE); break; case TEX_WOOD: - uiItemR(col, &tex_ptr, "noise_basis", 0, "", ICON_NONE); - uiItemR(col, &tex_ptr, "wood_type", 0, "", ICON_NONE); + uiItemR(col, &tex_ptr, "noise_basis", DEFAULT_FLAGS, "", ICON_NONE); + uiItemR(col, &tex_ptr, "wood_type", DEFAULT_FLAGS, "", ICON_NONE); row = uiLayoutRow(col, false); - uiItemR(row, &tex_ptr, "noise_basis_2", UI_ITEM_R_EXPAND, NULL, ICON_NONE); + uiItemR(row, &tex_ptr, "noise_basis_2", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE); row = uiLayoutRow(col, false); uiLayoutSetActive(row, !(ELEM(tex->stype, TEX_BAND, TEX_RING))); - uiItemR(row, &tex_ptr, "noise_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE); + uiItemR(row, &tex_ptr, "noise_type", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE); break; case TEX_CLOUDS: - uiItemR(col, &tex_ptr, "noise_basis", 0, "", ICON_NONE); + uiItemR(col, &tex_ptr, "noise_basis", DEFAULT_FLAGS, "", ICON_NONE); row = uiLayoutRow(col, false); - uiItemR(row, &tex_ptr, "cloud_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE); + uiItemR(row, &tex_ptr, "cloud_type", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE); row = uiLayoutRow(col, false); - uiItemR(row, &tex_ptr, "noise_type", UI_ITEM_R_EXPAND, NULL, ICON_NONE); - uiItemR(col, &tex_ptr, "noise_depth", UI_ITEM_R_EXPAND, IFACE_("Depth"), ICON_NONE); + uiItemR(row, &tex_ptr, "noise_type", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, NULL, ICON_NONE); + uiItemR(col, + &tex_ptr, + "noise_depth", + DEFAULT_FLAGS | UI_ITEM_R_EXPAND, + IFACE_("Depth"), + ICON_NONE); break; case TEX_DISTNOISE: - uiItemR(col, &tex_ptr, "noise_basis", 0, "", ICON_NONE); - uiItemR(col, &tex_ptr, "noise_distortion", 0, "", ICON_NONE); + uiItemR(col, &tex_ptr, "noise_basis", DEFAULT_FLAGS, "", ICON_NONE); + uiItemR(col, &tex_ptr, "noise_distortion", DEFAULT_FLAGS, "", ICON_NONE); break; case TEX_MUSGRAVE: - uiItemR(col, &tex_ptr, "musgrave_type", 0, "", ICON_NONE); - uiItemR(col, &tex_ptr, "noise_basis", 0, "", ICON_NONE); + uiItemR(col, &tex_ptr, "musgrave_type", DEFAULT_FLAGS, "", ICON_NONE); + uiItemR(col, &tex_ptr, "noise_basis", DEFAULT_FLAGS, "", ICON_NONE); break; case TEX_VORONOI: - uiItemR(col, &tex_ptr, "distance_metric", 0, "", ICON_NONE); + uiItemR(col, &tex_ptr, "distance_metric", DEFAULT_FLAGS, "", ICON_NONE); if (tex->vn_distm == TEX_MINKOVSKY) { - uiItemR(col, &tex_ptr, "minkovsky_exponent", 0, NULL, ICON_NONE); + uiItemR(col, &tex_ptr, "minkovsky_exponent", DEFAULT_FLAGS, NULL, ICON_NONE); } - uiItemR(col, &tex_ptr, "color_mode", 0, "", ICON_NONE); + uiItemR(col, &tex_ptr, "color_mode", DEFAULT_FLAGS, "", ICON_NONE); break; } } @@ -3070,7 +3079,7 @@ static void node_texture_buts_image_ex(uiLayout *layout, bContext *C, PointerRNA static void node_texture_buts_output(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { - uiItemR(layout, ptr, "filepath", 0, "", ICON_NONE); + uiItemR(layout, ptr, "filepath", DEFAULT_FLAGS, "", ICON_NONE); } /* only once called */ @@ -3122,6 +3131,96 @@ static void node_texture_set_butfunc(bNodeType *ntype) } } +/* ****************** BUTTON CALLBACKS FOR SIMULATION NODES ***************** */ + +static void node_simulation_buts_particle_simulation(uiLayout *layout, + bContext *UNUSED(C), + PointerRNA *ptr) +{ + uiItemR(layout, ptr, "name", DEFAULT_FLAGS, "", ICON_NONE); +} + +static void node_simulation_buts_particle_time_step_event(uiLayout *layout, + bContext *UNUSED(C), + PointerRNA *ptr) +{ + uiItemR(layout, ptr, "mode", DEFAULT_FLAGS, "", ICON_NONE); +} + +static void node_simulation_buts_particle_attribute(uiLayout *layout, + bContext *UNUSED(C), + PointerRNA *ptr) +{ + uiItemR(layout, ptr, "data_type", DEFAULT_FLAGS, "", ICON_NONE); +} + +static void node_simulation_buts_set_particle_attribute(uiLayout *layout, + bContext *UNUSED(C), + PointerRNA *ptr) +{ + uiItemR(layout, ptr, "data_type", DEFAULT_FLAGS, "", ICON_NONE); +} + +static void node_simulation_buts_time(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiItemR(layout, ptr, "mode", DEFAULT_FLAGS, "", ICON_NONE); +} + +static void node_simulation_set_butfunc(bNodeType *ntype) +{ + switch (ntype->type) { + case SIM_NODE_PARTICLE_SIMULATION: + ntype->draw_buttons = node_simulation_buts_particle_simulation; + break; + case SIM_NODE_PARTICLE_TIME_STEP_EVENT: + ntype->draw_buttons = node_simulation_buts_particle_time_step_event; + break; + case SIM_NODE_PARTICLE_ATTRIBUTE: + ntype->draw_buttons = node_simulation_buts_particle_attribute; + break; + case SIM_NODE_SET_PARTICLE_ATTRIBUTE: + ntype->draw_buttons = node_simulation_buts_set_particle_attribute; + break; + case SIM_NODE_TIME: + ntype->draw_buttons = node_simulation_buts_time; + break; + } +} + +/* ****************** BUTTON CALLBACKS FOR FUNCTION NODES ***************** */ + +static void node_function_buts_boolean_math(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiItemR(layout, ptr, "operation", DEFAULT_FLAGS, "", ICON_NONE); +} + +static void node_function_buts_float_compare(uiLayout *layout, + bContext *UNUSED(C), + PointerRNA *ptr) +{ + uiItemR(layout, ptr, "operation", DEFAULT_FLAGS, "", ICON_NONE); +} + +static void node_function_buts_switch(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiItemR(layout, ptr, "data_type", DEFAULT_FLAGS, "", ICON_NONE); +} + +static void node_function_set_butfunc(bNodeType *ntype) +{ + switch (ntype->type) { + case FN_NODE_BOOLEAN_MATH: + ntype->draw_buttons = node_function_buts_boolean_math; + break; + case FN_NODE_FLOAT_COMPARE: + ntype->draw_buttons = node_function_buts_float_compare; + break; + case FN_NODE_SWITCH: + ntype->draw_buttons = node_function_buts_switch; + break; + } +} + /* ****** init draw callbacks for all tree types, only called in usiblender.c, once ************ */ static void node_property_update_default(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr) @@ -3230,6 +3329,8 @@ void ED_node_init_butfuncs(void) node_composit_set_butfunc(ntype); node_shader_set_butfunc(ntype); node_texture_set_butfunc(ntype); + node_simulation_set_butfunc(ntype); + node_function_set_butfunc(ntype); /* define update callbacks for socket properties */ node_template_properties_update(ntype); @@ -3240,6 +3341,7 @@ void ED_node_init_butfuncs(void) ntreeType_Composite->ui_icon = ICON_NODE_COMPOSITING; ntreeType_Shader->ui_icon = ICON_NODE_MATERIAL; ntreeType_Texture->ui_icon = ICON_NODE_TEXTURE; + ntreeType_Simulation->ui_icon = ICON_PHYSICS; /* TODO: Use correct icon. */ } void ED_init_custom_node_type(bNodeType *ntype) @@ -3268,6 +3370,12 @@ static const float std_node_socket_colors[][4] = { {0.0, 0.0, 0.0, 1.0}, /*__SOCK_MESH (deprecated) */ {0.06, 0.52, 0.15, 1.0}, /* SOCK_INT */ {0.39, 0.39, 0.39, 1.0}, /* SOCK_STRING */ + {0.40, 0.10, 0.10, 1.0}, /* SOCK_OBJECT */ + {0.10, 0.40, 0.10, 1.0}, /* SOCK_IMAGE */ + {0.80, 0.80, 0.20, 1.0}, /* SOCK_EMITTERS */ + {0.80, 0.20, 0.80, 1.0}, /* SOCK_EVENTS */ + {0.20, 0.80, 0.80, 1.0}, /* SOCK_FORCES */ + {0.30, 0.30, 0.30, 1.0}, /* SOCK_CONTROL_FLOW */ }; /* common color callbacks for standard types */ @@ -3362,7 +3470,7 @@ static void std_node_socket_draw( case SOCK_FLOAT: case SOCK_INT: case SOCK_BOOLEAN: - uiItemR(layout, ptr, "default_value", 0, text, 0); + uiItemR(layout, ptr, "default_value", DEFAULT_FLAGS, text, 0); break; case SOCK_VECTOR: if (sock->flag & SOCK_COMPACT) { @@ -3370,11 +3478,11 @@ static void std_node_socket_draw( } else { if (sock->typeinfo->subtype == PROP_DIRECTION) { - uiItemR(layout, ptr, "default_value", 0, "", ICON_NONE); + uiItemR(layout, ptr, "default_value", DEFAULT_FLAGS, "", ICON_NONE); } else { uiLayout *column = uiLayoutColumn(layout, true); - uiItemR(column, ptr, "default_value", 0, text, ICON_NONE); + uiItemR(column, ptr, "default_value", DEFAULT_FLAGS, text, ICON_NONE); } } break; @@ -3382,7 +3490,15 @@ static void std_node_socket_draw( case SOCK_STRING: { uiLayout *row = uiLayoutSplit(layout, 0.5f, false); uiItemL(row, text, 0); - uiItemR(row, ptr, "default_value", 0, "", 0); + uiItemR(row, ptr, "default_value", DEFAULT_FLAGS, "", 0); + break; + } + case SOCK_OBJECT: { + uiItemR(layout, ptr, "default_value", DEFAULT_FLAGS, text, 0); + break; + } + case SOCK_IMAGE: { + uiItemR(layout, ptr, "default_value", DEFAULT_FLAGS, text, 0); break; } default: @@ -3400,32 +3516,32 @@ static void std_node_socket_interface_draw(bContext *UNUSED(C), uiLayout *layout switch (type) { case SOCK_FLOAT: { uiLayout *row; - uiItemR(layout, ptr, "default_value", 0, NULL, 0); + uiItemR(layout, ptr, "default_value", DEFAULT_FLAGS, NULL, 0); row = uiLayoutRow(layout, true); - uiItemR(row, ptr, "min_value", 0, IFACE_("Min"), 0); - uiItemR(row, ptr, "max_value", 0, IFACE_("Max"), 0); + uiItemR(row, ptr, "min_value", DEFAULT_FLAGS, IFACE_("Min"), 0); + uiItemR(row, ptr, "max_value", DEFAULT_FLAGS, IFACE_("Max"), 0); break; } case SOCK_INT: { uiLayout *row; - uiItemR(layout, ptr, "default_value", 0, NULL, 0); + uiItemR(layout, ptr, "default_value", DEFAULT_FLAGS, NULL, 0); row = uiLayoutRow(layout, true); - uiItemR(row, ptr, "min_value", 0, IFACE_("Min"), 0); - uiItemR(row, ptr, "max_value", 0, IFACE_("Max"), 0); + uiItemR(row, ptr, "min_value", DEFAULT_FLAGS, IFACE_("Min"), 0); + uiItemR(row, ptr, "max_value", DEFAULT_FLAGS, IFACE_("Max"), 0); break; } case SOCK_VECTOR: { uiLayout *row; - uiItemR(layout, ptr, "default_value", UI_ITEM_R_EXPAND, NULL, 0); + uiItemR(layout, ptr, "default_value", UI_ITEM_R_EXPAND, NULL, DEFAULT_FLAGS); row = uiLayoutRow(layout, true); - uiItemR(row, ptr, "min_value", 0, IFACE_("Min"), 0); - uiItemR(row, ptr, "max_value", 0, IFACE_("Max"), 0); + uiItemR(row, ptr, "min_value", DEFAULT_FLAGS, IFACE_("Min"), 0); + uiItemR(row, ptr, "max_value", DEFAULT_FLAGS, IFACE_("Max"), 0); break; } case SOCK_BOOLEAN: case SOCK_RGBA: case SOCK_STRING: { - uiItemR(layout, ptr, "default_value", 0, NULL, 0); + uiItemR(layout, ptr, "default_value", DEFAULT_FLAGS, NULL, 0); break; } } diff --git a/source/blender/editors/space_node/node_buttons.c b/source/blender/editors/space_node/node_buttons.c index 4cf67dddb57..8fc343a9ed4 100644 --- a/source/blender/editors/space_node/node_buttons.c +++ b/source/blender/editors/space_node/node_buttons.c @@ -84,7 +84,7 @@ static void node_sockets_panel(const bContext *C, Panel *panel) split = uiLayoutSplit(layout, 0.35f, false); uiItemL(split, name, ICON_NONE); - uiTemplateNodeLink(split, ntree, node, sock); + uiTemplateNodeLink(split, (bContext *)C, ntree, node, sock); } } diff --git a/source/blender/editors/space_node/node_draw.c b/source/blender/editors/space_node/node_draw.c index 0552660b9bf..bd8950c5085 100644 --- a/source/blender/editors/space_node/node_draw.c +++ b/source/blender/editors/space_node/node_draw.c @@ -94,23 +94,11 @@ void ED_node_tree_update(const bContext *C) static bNodeTree *node_tree_from_ID(ID *id) { if (id) { - short idtype = GS(id->name); - - switch (idtype) { - case ID_NT: - return (bNodeTree *)id; - case ID_MA: - return ((Material *)id)->nodetree; - case ID_LA: - return ((Light *)id)->nodetree; - case ID_WO: - return ((World *)id)->nodetree; - case ID_SCE: - return ((Scene *)id)->nodetree; - case ID_TE: - return ((Tex *)id)->nodetree; - case ID_LS: - return ((FreestyleLineStyle *)id)->nodetree; + if (GS(id->name) == ID_NT) { + return (bNodeTree *)id; + } + else { + return ntreeFromID(id); } } @@ -719,39 +707,19 @@ static void node_draw_mute_line(View2D *v2d, SpaceNode *snode, bNode *node) #define MARKER_SHAPE_CIRCLE 0x2 #define MARKER_SHAPE_INNER_DOT 0x10 -static void node_socket_draw(const bContext *C, - bNodeTree *ntree, - PointerRNA node_ptr, - bNodeSocket *sock, +static void node_socket_draw(const bNodeSocket *sock, + const float color[4], + const float color_outline[4], + float size, + int locx, + int locy, uint pos_id, uint col_id, uint shape_id, uint size_id, - uint outline_col_id, - float size, - bool selected) + uint outline_col_id) { - PointerRNA ptr; - float color[4]; - float outline_color[4]; - uint flags = 0; - - RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, sock, &ptr); - sock->typeinfo->draw_color((bContext *)C, &ptr, &node_ptr, color); - - bNode *node = node_ptr.data; - if (node->flag & NODE_MUTED) { - color[3] *= 0.25f; - } - - if (selected) { - UI_GetThemeColor4fv(TH_TEXT_HI, outline_color); - outline_color[3] = 0.9f; - } - else { - copy_v4_fl(outline_color, 0.0f); - outline_color[3] = 0.6f; - } + int flags; /* sets shape flags */ switch (sock->display_shape) { @@ -780,8 +748,120 @@ static void node_socket_draw(const bContext *C, immAttr4fv(col_id, color); immAttr1u(shape_id, flags); immAttr1f(size_id, size); - immAttr4fv(outline_col_id, outline_color); - immVertex2f(pos_id, sock->locx, sock->locy); + immAttr4fv(outline_col_id, color_outline); + immVertex2f(pos_id, locx, locy); +} + +static void node_socket_outline_color_get(bool selected, float r_outline_color[4]) +{ + if (selected) { + UI_GetThemeColor4fv(TH_TEXT_HI, r_outline_color); + r_outline_color[3] = 0.9f; + } + else { + copy_v4_fl(r_outline_color, 0.0f); + r_outline_color[3] = 0.6f; + } +} + +/* Usual convention here would be node_socket_get_color(), but that's already used (for setting a + * color property socket). */ +void node_socket_color_get( + bContext *C, bNodeTree *ntree, PointerRNA *node_ptr, bNodeSocket *sock, float r_color[4]) +{ + PointerRNA ptr; + + BLI_assert(RNA_struct_is_a(node_ptr->type, &RNA_Node)); + RNA_pointer_create((ID *)ntree, &RNA_NodeSocket, sock, &ptr); + + sock->typeinfo->draw_color(C, &ptr, node_ptr, r_color); + + bNode *node = node_ptr->data; + if (node->flag & NODE_MUTED) { + r_color[3] *= 0.25f; + } +} + +static void node_socket_draw_nested(const bContext *C, + bNodeTree *ntree, + PointerRNA *node_ptr, + bNodeSocket *sock, + uint pos_id, + uint col_id, + uint shape_id, + uint size_id, + uint outline_col_id, + float size, + bool selected) +{ + float color[4]; + float outline_color[4]; + + node_socket_color_get((bContext *)C, ntree, node_ptr, sock, color); + node_socket_outline_color_get(selected, outline_color); + + node_socket_draw(sock, + color, + outline_color, + size, + sock->locx, + sock->locy, + pos_id, + col_id, + shape_id, + size_id, + outline_col_id); +} + +/** + * Draw a single node socket at default size. + * \note this is only called from external code, internally #node_socket_draw_nested() is used for + * optimized drawing of multiple/all sockets of a node. + */ +void ED_node_socket_draw(bNodeSocket *sock, const rcti *rect, const float color[4], float scale) +{ + const float size = 2.25f * NODE_SOCKSIZE * scale; + rcti draw_rect = *rect; + float outline_color[4] = {0}; + + node_socket_outline_color_get(sock->flag & SELECT, outline_color); + + BLI_rcti_resize(&draw_rect, size, size); + + GPUVertFormat *format = immVertexFormat(); + uint pos_id = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + uint col_id = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); + uint shape_id = GPU_vertformat_attr_add(format, "flags", GPU_COMP_U32, 1, GPU_FETCH_INT); + uint size_id = GPU_vertformat_attr_add(format, "size", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); + uint outline_col_id = GPU_vertformat_attr_add( + format, "outlineColor", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); + + gpuPushAttr(GPU_BLEND_BIT); + GPU_blend(true); + GPU_program_point_size(true); + + immBindBuiltinProgram(GPU_SHADER_KEYFRAME_DIAMOND); + immUniform1f("outline_scale", 0.7f); + immUniform2f("ViewportSize", -1.0f, -1.0f); + + /* Single point */ + immBegin(GPU_PRIM_POINTS, 1); + node_socket_draw(sock, + color, + outline_color, + BLI_rcti_size_y(&draw_rect), + BLI_rcti_cent_x(&draw_rect), + BLI_rcti_cent_y(&draw_rect), + pos_id, + col_id, + shape_id, + size_id, + outline_col_id); + immEnd(); + + immUnbindProgram(); + GPU_program_point_size(false); + gpuPopAttr(); } /* ************** Socket callbacks *********** */ @@ -974,17 +1054,17 @@ void node_draw_sockets(View2D *v2d, continue; } - node_socket_draw(C, - ntree, - node_ptr, - sock, - pos_id, - col_id, - shape_id, - size_id, - outline_col_id, - scale, - selected); + node_socket_draw_nested(C, + ntree, + &node_ptr, + sock, + pos_id, + col_id, + shape_id, + size_id, + outline_col_id, + scale, + selected); } /* socket outputs */ @@ -999,17 +1079,17 @@ void node_draw_sockets(View2D *v2d, continue; } - node_socket_draw(C, - ntree, - node_ptr, - sock, - pos_id, - col_id, - shape_id, - size_id, - outline_col_id, - scale, - selected); + node_socket_draw_nested(C, + ntree, + &node_ptr, + sock, + pos_id, + col_id, + shape_id, + size_id, + outline_col_id, + scale, + selected); } } @@ -1032,17 +1112,17 @@ void node_draw_sockets(View2D *v2d, continue; } if (select_all || (sock->flag & SELECT)) { - node_socket_draw(C, - ntree, - node_ptr, - sock, - pos_id, - col_id, - shape_id, - size_id, - outline_col_id, - scale, - selected); + node_socket_draw_nested(C, + ntree, + &node_ptr, + sock, + pos_id, + col_id, + shape_id, + size_id, + outline_col_id, + scale, + selected); if (--selected_input_len == 0) { break; /* stop as soon as last one is drawn */ } @@ -1057,17 +1137,17 @@ void node_draw_sockets(View2D *v2d, continue; } if (select_all || (sock->flag & SELECT)) { - node_socket_draw(C, - ntree, - node_ptr, - sock, - pos_id, - col_id, - shape_id, - size_id, - outline_col_id, - scale, - selected); + node_socket_draw_nested(C, + ntree, + &node_ptr, + sock, + pos_id, + col_id, + shape_id, + size_id, + outline_col_id, + scale, + selected); if (--selected_output_len == 0) { break; /* stop as soon as last one is drawn */ } diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c index a82acfc4dbe..bd5ce135f82 100644 --- a/source/blender/editors/space_node/node_edit.c +++ b/source/blender/editors/space_node/node_edit.c @@ -69,6 +69,7 @@ #include "NOD_composite.h" #include "NOD_shader.h" +#include "NOD_simulation.h" #include "NOD_texture.h" #include "node_intern.h" /* own include */ @@ -438,6 +439,11 @@ bool ED_node_is_texture(struct SpaceNode *snode) return STREQ(snode->tree_idname, ntreeType_Texture->idname); } +bool ED_node_is_simulation(struct SpaceNode *snode) +{ + return STREQ(snode->tree_idname, ntreeType_Simulation->idname); +} + /* assumes nothing being done in ntree yet, sets the default in/out node */ /* called from shading buttons or header */ void ED_node_shader_default(const bContext *C, ID *id) diff --git a/source/blender/editors/space_node/node_group.c b/source/blender/editors/space_node/node_group.c index 3a0ef45a68d..2617384d046 100644 --- a/source/blender/editors/space_node/node_group.c +++ b/source/blender/editors/space_node/node_group.c @@ -69,7 +69,8 @@ static bool node_group_operator_active(bContext *C) */ if (STREQ(snode->tree_idname, "ShaderNodeTree") || STREQ(snode->tree_idname, "CompositorNodeTree") || - STREQ(snode->tree_idname, "TextureNodeTree")) { + STREQ(snode->tree_idname, "TextureNodeTree") || + STREQ(snode->tree_idname, "SimulationNodeTree")) { return true; } } @@ -85,7 +86,8 @@ static bool node_group_operator_editable(bContext *C) * Disabled otherwise to allow pynodes define their own operators * with same keymap. */ - if (ED_node_is_shader(snode) || ED_node_is_compositor(snode) || ED_node_is_texture(snode)) { + if (ED_node_is_shader(snode) || ED_node_is_compositor(snode) || ED_node_is_texture(snode) || + ED_node_is_simulation(snode)) { return true; } } @@ -111,6 +113,9 @@ static const char *group_node_idname(bContext *C) else if (ED_node_is_texture(snode)) { return "TextureNodeGroup"; } + else if (ED_node_is_simulation(snode)) { + return "SimulationNodeGroup"; + } return ""; } diff --git a/source/blender/editors/space_node/node_intern.h b/source/blender/editors/space_node/node_intern.h index 42439e88c96..04186c3a727 100644 --- a/source/blender/editors/space_node/node_intern.h +++ b/source/blender/editors/space_node/node_intern.h @@ -38,6 +38,7 @@ struct bContext; struct bNode; struct bNodeLink; struct bNodeSocket; +struct wmGizmoGroupType; struct wmKeyConfig; struct wmWindow; @@ -77,6 +78,11 @@ void node_draw_sockets(struct View2D *v2d, void node_update_default(const struct bContext *C, struct bNodeTree *ntree, struct bNode *node); int node_select_area_default(struct bNode *node, int x, int y); int node_tweak_area_default(struct bNode *node, int x, int y); +void node_socket_color_get(struct bContext *C, + struct bNodeTree *ntree, + struct PointerRNA *node_ptr, + struct bNodeSocket *sock, + float r_color[4]); void node_update_nodetree(const struct bContext *C, struct bNodeTree *ntree); void node_draw_nodetree(const struct bContext *C, struct ARegion *region, @@ -122,7 +128,7 @@ void NODE_OT_find_node(struct wmOperatorType *ot); /* node_view.c */ int space_node_view_flag(struct bContext *C, - SpaceNode *snode, + struct SpaceNode *snode, ARegion *region, const int node_flag, const int smooth_viewtx); @@ -196,7 +202,7 @@ void NODE_OT_detach(struct wmOperatorType *ot); void NODE_OT_link_viewer(struct wmOperatorType *ot); -void NODE_OT_insert_offset(wmOperatorType *ot); +void NODE_OT_insert_offset(struct wmOperatorType *ot); /* node_edit.c */ void snode_notify(struct bContext *C, struct SpaceNode *snode); @@ -207,8 +213,8 @@ void snode_update(struct SpaceNode *snode, struct bNode *node); bool composite_node_active(struct bContext *C); bool composite_node_editable(struct bContext *C); -int node_has_hidden_sockets(bNode *node); -void node_set_hidden_sockets(SpaceNode *snode, bNode *node, int set); +int node_has_hidden_sockets(struct bNode *node); +void node_set_hidden_sockets(struct SpaceNode *snode, bNode *node, int set); int node_render_changed_exec(bContext *, struct wmOperator *); int node_find_indicated_socket(struct SpaceNode *snode, struct bNode **nodep, diff --git a/source/blender/editors/space_node/node_relationships.c b/source/blender/editors/space_node/node_relationships.c index 8c2f79109f6..144e3bd3506 100644 --- a/source/blender/editors/space_node/node_relationships.c +++ b/source/blender/editors/space_node/node_relationships.c @@ -1657,7 +1657,7 @@ static bool node_link_insert_offset_frame_chain_cb(bNode *fromnode, } /** - * Applies NodeInsertOfsData.offset_x to all childs of \a parent + * Applies #NodeInsertOfsData.offset_x to all children of \a parent. */ static void node_link_insert_offset_frame_chains(const bNodeTree *ntree, const bNode *parent, diff --git a/source/blender/editors/space_node/node_select.c b/source/blender/editors/space_node/node_select.c index e96d03f70f4..9eabcc44d80 100644 --- a/source/blender/editors/space_node/node_select.c +++ b/source/blender/editors/space_node/node_select.c @@ -769,7 +769,10 @@ static int node_lasso_select_invoke(bContext *C, wmOperator *op, const wmEvent * return WM_gesture_lasso_invoke(C, op, event); } -static bool do_lasso_select_node(bContext *C, const int mcords[][2], short moves, eSelectOp sel_op) +static bool do_lasso_select_node(bContext *C, + const int mcoords[][2], + const int mcoords_len, + eSelectOp sel_op) { SpaceNode *snode = CTX_wm_space_node(C); bNode *node; @@ -786,7 +789,7 @@ static bool do_lasso_select_node(bContext *C, const int mcords[][2], short moves } /* get rectangle from operator */ - BLI_lasso_boundbox(&rect, mcords, moves); + BLI_lasso_boundbox(&rect, mcoords, mcoords_len); /* do actual selection */ for (node = snode->edittree->nodes.first; node; node = node->next) { @@ -802,7 +805,7 @@ static bool do_lasso_select_node(bContext *C, const int mcords[][2], short moves if (UI_view2d_view_to_region_clip( ®ion->v2d, cent[0], cent[1], &screen_co[0], &screen_co[1]) && BLI_rcti_isect_pt(&rect, screen_co[0], screen_co[1]) && - BLI_lasso_is_point_inside(mcords, moves, screen_co[0], screen_co[1], INT_MAX)) { + BLI_lasso_is_point_inside(mcoords, mcoords_len, screen_co[0], screen_co[1], INT_MAX)) { nodeSetSelected(node, select); changed = true; } @@ -817,15 +820,15 @@ static bool do_lasso_select_node(bContext *C, const int mcords[][2], short moves static int node_lasso_select_exec(bContext *C, wmOperator *op) { - int mcords_tot; - const int(*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot); + int mcoords_len; + const int(*mcoords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcoords_len); - if (mcords) { + if (mcoords) { const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode"); - do_lasso_select_node(C, mcords, mcords_tot, sel_op); + do_lasso_select_node(C, mcoords, mcoords_len, sel_op); - MEM_freeN((void *)mcords); + MEM_freeN((void *)mcoords); return OPERATOR_FINISHED; } @@ -1116,10 +1119,10 @@ void NODE_OT_select_same_type_step(wmOperatorType *ot) * \{ */ /* generic search invoke */ -static void node_find_cb(const struct bContext *C, - void *UNUSED(arg), - const char *str, - uiSearchItems *items) +static void node_find_update_fn(const struct bContext *C, + void *UNUSED(arg), + const char *str, + uiSearchItems *items) { SpaceNode *snode = CTX_wm_space_node(C); bNode *node; @@ -1142,7 +1145,7 @@ static void node_find_cb(const struct bContext *C, } } -static void node_find_call_cb(struct bContext *C, void *UNUSED(arg1), void *arg2) +static void node_find_exec_fn(struct bContext *C, void *UNUSED(arg1), void *arg2) { SpaceNode *snode = CTX_wm_space_node(C); bNode *active = arg2; @@ -1182,7 +1185,7 @@ static uiBlock *node_find_menu(bContext *C, ARegion *region, void *arg_op) 0, 0, ""); - UI_but_func_search_set(but, NULL, node_find_cb, op->type, NULL, node_find_call_cb, NULL, NULL); + UI_but_func_search_set(but, NULL, node_find_update_fn, op->type, NULL, node_find_exec_fn, NULL); UI_but_flag_enable(but, UI_BUT_ACTIVATE_ON_INIT); /* fake button, it holds space for search items */ diff --git a/source/blender/editors/space_node/node_templates.c b/source/blender/editors/space_node/node_templates.c index 7d4095326f8..87b1f662b59 100644 --- a/source/blender/editors/space_node/node_templates.c +++ b/source/blender/editors/space_node/node_templates.c @@ -45,6 +45,7 @@ #include "UI_interface.h" #include "ED_node.h" /* own include */ +#include "node_intern.h" #include "ED_undo.h" @@ -662,17 +663,23 @@ static void ui_template_node_link_menu(bContext *C, uiLayout *layout, void *but_ ui_node_menu_column(arg, NODE_CLASS_GROUP, N_("Group")); } -void uiTemplateNodeLink(uiLayout *layout, bNodeTree *ntree, bNode *node, bNodeSocket *sock) +void uiTemplateNodeLink( + uiLayout *layout, bContext *C, bNodeTree *ntree, bNode *node, bNodeSocket *sock) { uiBlock *block = uiLayoutGetBlock(layout); NodeLinkArg *arg; uiBut *but; + float socket_col[4]; arg = MEM_callocN(sizeof(NodeLinkArg), "NodeLinkArg"); arg->ntree = ntree; arg->node = node; arg->sock = sock; + PointerRNA node_ptr; + RNA_pointer_create((ID *)ntree, &RNA_Node, node, &node_ptr); + node_socket_color_get(C, ntree, &node_ptr, sock, socket_col); + UI_block_layout_set_current(block, layout); if (sock->link || sock->type == SOCK_SHADER || (sock->flag & SOCK_HIDE_VALUE)) { @@ -687,8 +694,9 @@ void uiTemplateNodeLink(uiLayout *layout, bNodeTree *ntree, bNode *node, bNodeSo } UI_but_type_set_menu_from_pulldown(but); + UI_but_node_link_set(but, sock, socket_col); + UI_but_drawflag_enable(but, UI_BUT_ICON_LEFT); - but->flag |= UI_BUT_NODE_LINK; but->poin = (char *)but; but->func_argN = arg; @@ -708,18 +716,14 @@ static void ui_node_draw_node( uiLayout *layout, bContext *C, bNodeTree *ntree, bNode *node, int depth) { bNodeSocket *input; - uiLayout *col, *split; PointerRNA nodeptr; RNA_pointer_create(&ntree->id, &RNA_Node, node, &nodeptr); if (node->typeinfo->draw_buttons) { if (node->type != NODE_GROUP) { - split = uiLayoutSplit(layout, 0.5f, false); - col = uiLayoutColumn(split, false); - col = uiLayoutColumn(split, false); - - node->typeinfo->draw_buttons(col, C, &nodeptr); + uiLayoutSetPropSep(layout, true); + node->typeinfo->draw_buttons(layout, C, &nodeptr); } } @@ -733,12 +737,9 @@ static void ui_node_draw_input( { PointerRNA inputptr, nodeptr; uiBlock *block = uiLayoutGetBlock(layout); - uiBut *bt; - uiLayout *split, *row, *col; + uiLayout *row = NULL; bNode *lnode; - char label[UI_MAX_NAME_STR]; - int i, indent = (depth > 1) ? 2 * (depth - 1) : 0; - int dependency_loop; + bool dependency_loop; if (input->flag & SOCK_UNAVAIL) { return; @@ -757,48 +758,43 @@ static void ui_node_draw_input( RNA_pointer_create(&ntree->id, &RNA_NodeSocket, input, &inputptr); RNA_pointer_create(&ntree->id, &RNA_Node, node, &nodeptr); - /* indented label */ - for (i = 0; i < indent; i++) { - label[i] = ' '; - } - label[indent] = '\0'; - BLI_snprintf(label + indent, UI_MAX_NAME_STR - indent, "%s", IFACE_(input->name)); + row = uiLayoutRow(layout, true); + /* Decorations are added manually here. */ + uiLayoutSetPropDecorate(row, false); - /* split in label and value */ - split = uiLayoutSplit(layout, 0.5f, false); + uiPropertySplitWrapper split_wrapper = uiItemPropertySplitWrapperCreate(row); + /* Empty decorator item for alignment. */ + bool add_dummy_decorator = false; - row = uiLayoutRow(split, true); + { + uiLayout *sub = uiLayoutRow(split_wrapper.label_column, true); - if (depth > 0) { - UI_block_emboss_set(block, UI_EMBOSS_NONE); + if (depth > 0) { + UI_block_emboss_set(block, UI_EMBOSS_NONE); - if (lnode && - (lnode->inputs.first || (lnode->typeinfo->draw_buttons && lnode->type != NODE_GROUP))) { - int icon = (input->flag & SOCK_COLLAPSED) ? ICON_DISCLOSURE_TRI_RIGHT : - ICON_DISCLOSURE_TRI_DOWN; - uiItemR(row, &inputptr, "show_expanded", UI_ITEM_R_ICON_ONLY, "", icon); - } - else { - uiItemL(row, "", ICON_BLANK1); - } + if (lnode && + (lnode->inputs.first || (lnode->typeinfo->draw_buttons && lnode->type != NODE_GROUP))) { + int icon = (input->flag & SOCK_COLLAPSED) ? ICON_DISCLOSURE_TRI_RIGHT : + ICON_DISCLOSURE_TRI_DOWN; + uiItemR(sub, &inputptr, "show_expanded", UI_ITEM_R_ICON_ONLY, "", icon); + } - bt = block->buttons.last; - bt->rect.xmax = UI_UNIT_X / 2; + UI_block_emboss_set(block, UI_EMBOSS); + } - UI_block_emboss_set(block, UI_EMBOSS); + sub = uiLayoutRow(sub, true); + uiLayoutSetAlignment(sub, UI_LAYOUT_ALIGN_RIGHT); + uiItemL(sub, IFACE_(input->name), ICON_NONE); } - uiItemL(row, label, ICON_NONE); - bt = block->buttons.last; - bt->drawflag = UI_BUT_TEXT_RIGHT; - if (dependency_loop) { - row = uiLayoutRow(split, false); uiItemL(row, IFACE_("Dependency Loop"), ICON_ERROR); + add_dummy_decorator = true; } else if (lnode) { /* input linked to a node */ - uiTemplateNodeLink(split, ntree, node, input); + uiTemplateNodeLink(row, C, ntree, node, input); + add_dummy_decorator = true; if (depth == 0 || !(input->flag & SOCK_COLLAPSED)) { if (depth == 0) { @@ -809,33 +805,41 @@ static void ui_node_draw_input( } } else { + row = uiLayoutRow(row, true); + + uiTemplateNodeLink(row, C, ntree, node, input); + + if (input->flag & SOCK_HIDE_VALUE) { + add_dummy_decorator = true; + } /* input not linked, show value */ - if (!(input->flag & SOCK_HIDE_VALUE)) { + else { + uiLayout *sub = row; + switch (input->type) { + case SOCK_VECTOR: + if (input->type == SOCK_VECTOR) { + uiItemS(row); + sub = uiLayoutColumn(row, true); + } + ATTR_FALLTHROUGH; case SOCK_FLOAT: case SOCK_INT: case SOCK_BOOLEAN: case SOCK_RGBA: case SOCK_STRING: - row = uiLayoutRow(split, true); - uiItemR(row, &inputptr, "default_value", 0, "", ICON_NONE); - break; - case SOCK_VECTOR: - row = uiLayoutRow(split, false); - col = uiLayoutColumn(row, false); - uiItemR(col, &inputptr, "default_value", 0, "", ICON_NONE); + uiItemR(sub, &inputptr, "default_value", 0, "", ICON_NONE); + uiItemDecoratorR( + split_wrapper.decorate_column, &inputptr, "default_value", RNA_NO_INDEX); break; - default: - row = uiLayoutRow(split, false); - break; + add_dummy_decorator = true; } } - else { - row = uiLayoutRow(split, false); - } + } - uiTemplateNodeLink(row, ntree, node, input); + if (add_dummy_decorator) { + uiItemDecoratorR(split_wrapper.decorate_column, NULL, NULL, 0); } /* clear */ diff --git a/source/blender/editors/space_node/node_view.c b/source/blender/editors/space_node/node_view.c index 30991768f77..e879e01ecc4 100644 --- a/source/blender/editors/space_node/node_view.c +++ b/source/blender/editors/space_node/node_view.c @@ -141,7 +141,7 @@ static int node_view_all_exec(bContext *C, wmOperator *op) void NODE_OT_view_all(wmOperatorType *ot) { /* identifiers */ - ot->name = "View All"; + ot->name = "Frame All"; ot->idname = "NODE_OT_view_all"; ot->description = "Resize view so you can see all nodes"; diff --git a/source/blender/editors/space_node/space_node.c b/source/blender/editors/space_node/space_node.c index 9df04c097bb..f339d11b842 100644 --- a/source/blender/editors/space_node/space_node.c +++ b/source/blender/editors/space_node/space_node.c @@ -936,6 +936,11 @@ static void node_space_subtype_item_extend(bContext *C, EnumPropertyItem **item, bool free; const EnumPropertyItem *item_src = RNA_enum_node_tree_types_itemf_impl(C, &free); for (const EnumPropertyItem *item_iter = item_src; item_iter->identifier; item_iter++) { +#ifndef WITH_NEW_SIMULATION_TYPE + if (STREQ(item_iter->identifier, "SimulationNodeTree")) { + continue; + } +#endif RNA_enum_item_add(item, totitem, item_iter); } if (free) { diff --git a/source/blender/editors/space_outliner/outliner_collections.c b/source/blender/editors/space_outliner/outliner_collections.c index c77ee67b859..82ff9e06194 100644 --- a/source/blender/editors/space_outliner/outliner_collections.c +++ b/source/blender/editors/space_outliner/outliner_collections.c @@ -300,19 +300,15 @@ static TreeTraversalAction collection_find_data_to_edit(TreeElement *te, void *c return TRAVERSE_CONTINUE; } -static int collection_delete_exec(bContext *C, wmOperator *op) +void outliner_collection_delete( + bContext *C, Main *bmain, Scene *scene, ReportList *reports, bool hierarchy) { - struct wmMsgBus *mbus = CTX_wm_message_bus(C); - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - const Base *basact_prev = BASACT(view_layer); SpaceOutliner *soops = CTX_wm_space_outliner(C); + struct CollectionEditData data = { .scene = scene, .soops = soops, }; - bool hierarchy = RNA_boolean_get(op->ptr, "hierarchy"); data.collections_to_edit = BLI_gset_ptr_new(__func__); @@ -358,7 +354,7 @@ static int collection_delete_exec(bContext *C, wmOperator *op) } else { BKE_reportf( - op->reports, + reports, RPT_WARNING, "Cannot delete linked collection '%s', it is used by other linked scenes/collections", collection->id.name + 2); @@ -367,6 +363,17 @@ static int collection_delete_exec(bContext *C, wmOperator *op) } BLI_gset_free(data.collections_to_edit, NULL); +} + +static int collection_hierarchy_delete_exec(bContext *C, wmOperator *op) +{ + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + struct wmMsgBus *mbus = CTX_wm_message_bus(C); + const Base *basact_prev = BASACT(view_layer); + + outliner_collection_delete(C, bmain, scene, op->reports, true); DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE); DEG_relations_tag_update(bmain); @@ -382,24 +389,19 @@ static int collection_delete_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } -void OUTLINER_OT_collection_delete(wmOperatorType *ot) +void OUTLINER_OT_collection_hierarchy_delete(wmOperatorType *ot) { /* identifiers */ - ot->name = "Delete Collection"; - ot->idname = "OUTLINER_OT_collection_delete"; - ot->description = "Delete selected collections"; + ot->name = "Delete Hierarchy"; + ot->idname = "OUTLINER_OT_collection_hierarchy_delete"; + ot->description = "Delete selected collection hierarchies"; /* api callbacks */ - ot->exec = collection_delete_exec; + ot->exec = collection_hierarchy_delete_exec; ot->poll = ED_outliner_collections_editor_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* properties */ - PropertyRNA *prop = RNA_def_boolean( - ot->srna, "hierarchy", false, "Hierarchy", "Delete child objects and collections"); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); } /** \} */ diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c index 49fee033de0..7d3b95721c6 100644 --- a/source/blender/editors/space_outliner/outliner_draw.c +++ b/source/blender/editors/space_outliner/outliner_draw.c @@ -2193,6 +2193,9 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te) case eModifierType_WeightedNormal: data.icon = ICON_MOD_NORMALEDIT; break; + case eModifierType_Simulation: + data.icon = ICON_PHYSICS; /* TODO: Use correct icon. */ + break; /* Default */ case eModifierType_None: case eModifierType_ShapeKey: @@ -2583,6 +2586,10 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te) case ID_PC: data.icon = ICON_CURVE_BEZCURVE; break; + case ID_SIM: + /* TODO: Use correct icon. */ + data.icon = ICON_PHYSICS; + break; default: break; } diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c index 27422e5b42a..3db75d9288b 100644 --- a/source/blender/editors/space_outliner/outliner_edit.c +++ b/source/blender/editors/space_outliner/outliner_edit.c @@ -83,9 +83,11 @@ #include "outliner_intern.h" -/* ************************************************************** */ +/** \} */ -/* Highlight --------------------------------------------------- */ +/* -------------------------------------------------------------------- */ +/** \name Highlight on Cursor Motion Operator + * \{ */ static int outliner_highlight_update(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) { @@ -140,7 +142,11 @@ void OUTLINER_OT_highlight_update(wmOperatorType *ot) ot->poll = ED_operator_outliner_active; } -/* Toggle Open/Closed ------------------------------------------- */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Toggle Open/Closed Operator + * \{ */ /* Open or close a tree element, optionally toggling all children recursively */ void outliner_item_openclose(TreeElement *te, bool open, bool toggle_all) @@ -262,8 +268,10 @@ void OUTLINER_OT_item_openclose(wmOperatorType *ot) RNA_def_boolean(ot->srna, "all", false, "All", "Close or open all items"); } +/** \} */ + /* -------------------------------------------------------------------- */ -/** \name Object Mode Enter/Exit +/** \name Object Mode Enter/Exit Utilities * \{ */ static void item_object_mode_enter_exit(bContext *C, ReportList *reports, Object *ob, bool enter) @@ -317,7 +325,9 @@ void item_object_mode_exit_cb(bContext *C, /** \} */ -/* Rename --------------------------------------------------- */ +/* -------------------------------------------------------------------- */ +/** \name Rename Operator + * \{ */ static void do_item_rename(ARegion *region, TreeElement *te, @@ -455,7 +465,11 @@ void OUTLINER_OT_item_rename(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* ID delete --------------------------------------------------- */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name ID Delete Operator + * \{ */ static void id_delete(bContext *C, ReportList *reports, TreeElement *te, TreeStoreElem *tselem) { @@ -572,7 +586,11 @@ void OUTLINER_OT_id_delete(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* ID remap --------------------------------------------------- */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name ID Remap Operator + * \{ */ static int outliner_id_remap_exec(bContext *C, wmOperator *op) { @@ -746,7 +764,11 @@ void id_remap_cb(bContext *C, WM_operator_properties_free(&op_props); } -/* ID copy/Paste ------------------------------------------------------------- */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name ID Copy Operator + * \{ */ static int outliner_id_copy_tag(SpaceOutliner *soops, ListBase *tree) { @@ -812,6 +834,12 @@ void OUTLINER_OT_id_copy(wmOperatorType *ot) ot->flag = 0; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name ID Paste Operator + * \{ */ + static int outliner_id_paste_exec(bContext *C, wmOperator *op) { char str[FILE_MAX]; @@ -847,7 +875,11 @@ void OUTLINER_OT_id_paste(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* Library relocate/reload --------------------------------------------------- */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Library Relocate Operator + * \{ */ static int lib_relocate( bContext *C, TreeElement *te, TreeStoreElem *tselem, wmOperatorType *ot, const bool reload) @@ -994,6 +1026,12 @@ static int outliner_lib_reload_invoke(bContext *C, wmOperator *op, const wmEvent return OPERATOR_CANCELLED; } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Library Reload Operator + * \{ */ + void OUTLINER_OT_lib_reload(wmOperatorType *ot) { ot->name = "Reload Library"; @@ -1020,13 +1058,11 @@ void lib_reload_cb(bContext *C, lib_relocate(C, te, tselem, ot, true); } -/* ************************************************************** */ -/* Setting Toggling Operators */ - -/* =============================================== */ -/* Toggling Utilities (Exported) */ +/** \} */ -/* Apply Settings ------------------------------- */ +/* -------------------------------------------------------------------- */ +/** \name Apply Settings Utilities + * \{ */ static int outliner_count_levels(ListBase *lb, const int curlevel) { @@ -1108,7 +1144,11 @@ bool outliner_flag_flip(ListBase *lb, short flag) return changed; } -/* Restriction Columns ------------------------------- */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Restriction Column Utility + * \{ */ /* same check needed for both object operation and restrict column button func * return 0 when in edit mode (cannot restrict view or select) @@ -1134,10 +1174,11 @@ int common_restrict_check(bContext *C, Object *ob) return 1; } -/* =============================================== */ -/* Outliner setting toggles */ +/** \} */ -/* Toggle Expanded (Outliner) ---------------------------------------- */ +/* -------------------------------------------------------------------- */ +/** \name Toggle Expanded (Outliner) Operator + * \{ */ static int outliner_toggle_expanded_exec(bContext *C, wmOperator *UNUSED(op)) { @@ -1170,7 +1211,11 @@ void OUTLINER_OT_expanded_toggle(wmOperatorType *ot) /* no undo or registry, UI option */ } -/* Toggle Selected (Outliner) ---------------------------------------- */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Toggle Selected (Outliner) Operator + * \{ */ static int outliner_select_all_exec(bContext *C, wmOperator *op) { @@ -1220,10 +1265,11 @@ void OUTLINER_OT_select_all(wmOperatorType *ot) WM_operator_properties_select_all(ot); } -/* ************************************************************** */ -/* Hotkey Only Operators */ +/** \} */ -/* Show Active --------------------------------------------------- */ +/* -------------------------------------------------------------------- */ +/** \name View Show Active (Outliner) Operator + * \{ */ static void outliner_set_coordinates_element_recursive(SpaceOutliner *soops, TreeElement *te, @@ -1373,7 +1419,11 @@ void OUTLINER_OT_show_active(wmOperatorType *ot) ot->poll = ED_operator_outliner_active; } -/* View Panning --------------------------------------------------- */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Panning (Outliner) Operator + * \{ */ static int outliner_scroll_page_exec(bContext *C, wmOperator *op) { @@ -1411,10 +1461,14 @@ void OUTLINER_OT_scroll_page(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_SKIP_SAVE); } -/* Search ------------------------------------------------------- */ -// TODO: probably obsolete now with filtering? +/** \} */ + +#if 0 // TODO: probably obsolete now with filtering? + +/* -------------------------------------------------------------------- */ +/** \name Search + * \{ */ -#if 0 /* find next element that has this name */ static TreeElement *outliner_find_name( @@ -1527,9 +1581,14 @@ static void outliner_find_panel( BKE_reportf(reports, RPT_WARNING, "Not found: %s", name); } } -#endif -/* Show One Level ----------------------------------------------- */ +/** \} */ + +#endif /* if 0 */ + +/* -------------------------------------------------------------------- */ +/** \name Show One Level Operator + * \{ */ /* helper function for Show/Hide one level operator */ static void outliner_openclose_level(ListBase *lb, int curlevel, int level, int open) @@ -1602,7 +1661,11 @@ void OUTLINER_OT_show_one_level(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_SKIP_SAVE); } -/* Show Hierarchy ----------------------------------------------- */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Show Hierarchy Operator + * \{ */ /* Helper function for tree_element_shwo_hierarchy() - * recursively checks whether subtrees have any objects. */ @@ -1694,11 +1757,15 @@ void OUTLINER_OT_show_hierarchy(wmOperatorType *ot) /* no undo or registry, UI option */ } -/* ************************************************************** */ -/* ANIMATO OPERATIONS */ -/* KeyingSet and Driver Creation - Helper functions */ +/** \} */ -/* specialized poll callback for these operators to work in Datablocks view only */ +/* -------------------------------------------------------------------- */ +/** \name Animation Internal Utilities + * \{ */ + +/** + * Specialized poll callback for these operators to work in data-blocks view only. + */ static bool ed_operator_outliner_datablocks_active(bContext *C) { ScrArea *area = CTX_wm_area(C); @@ -1860,19 +1927,23 @@ static void tree_element_to_path(TreeElement *te, BLI_freelistN(&hierarchy); } -/* =============================================== */ -/* Driver Operations */ +/** \} */ -/* These operators are only available in databrowser mode for now, as - * they depend on having RNA paths and/or hierarchies available. +/* -------------------------------------------------------------------- */ +/** \name Driver Internal Utilities + * \{ */ + +/** + * Driver Operations + * + * These operators are only available in data-browser mode for now, + * as they depend on having RNA paths and/or hierarchies available. */ enum { DRIVERS_EDITMODE_ADD = 0, DRIVERS_EDITMODE_REMOVE, } /*eDrivers_EditModes*/; -/* Utilities ---------------------------------- */ - /* Recursively iterate over tree, finding and working on selected items */ static void do_outliner_drivers_editop(SpaceOutliner *soops, ListBase *tree, @@ -1948,7 +2019,11 @@ static void do_outliner_drivers_editop(SpaceOutliner *soops, } } -/* Add Operator ---------------------------------- */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Driver Add Operator + * \{ */ static int outliner_drivers_addsel_exec(bContext *C, wmOperator *op) { @@ -1983,7 +2058,11 @@ void OUTLINER_OT_drivers_add_selected(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* Remove Operator ---------------------------------- */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Driver Remove Operator + * \{ */ static int outliner_drivers_deletesel_exec(bContext *C, wmOperator *op) { @@ -2018,10 +2097,16 @@ void OUTLINER_OT_drivers_delete_selected(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* =============================================== */ -/* Keying Set Operations */ +/** \} */ -/* These operators are only available in databrowser mode for now, as +/* -------------------------------------------------------------------- */ +/** \name Keying-Set Internal Utilities + * \{ */ + +/** + * Keying-Set Operations + * + * These operators are only available in data-browser mode for now, as * they depend on having RNA paths and/or hierarchies available. */ enum { @@ -2029,8 +2114,6 @@ enum { KEYINGSET_EDITMODE_REMOVE, } /*eKeyingSet_EditModes*/; -/* Utilities ---------------------------------- */ - /* find the 'active' KeyingSet, and add if not found (if adding is allowed) */ // TODO: should this be an API func? static KeyingSet *verify_active_keyingset(Scene *scene, short add) @@ -2122,7 +2205,11 @@ static void do_outliner_keyingset_editop(SpaceOutliner *soops, } } -/* Add Operator ---------------------------------- */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Keying-Set Add Operator + * \{ */ static int outliner_keyingset_additems_exec(bContext *C, wmOperator *op) { @@ -2163,7 +2250,11 @@ void OUTLINER_OT_keyingset_add_selected(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* Remove Operator ---------------------------------- */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Keying-Set Remove Operator + * \{ */ static int outliner_keyingset_removeitems_exec(bContext *C, wmOperator *UNUSED(op)) { @@ -2200,8 +2291,11 @@ void OUTLINER_OT_keyingset_remove_selected(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* ************************************************************** */ -/* ORPHANED DATABLOCKS */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Purge Orphan Data-Blocks Operator + * \{ */ static bool ed_operator_outliner_id_orphans_active(bContext *C) { @@ -2213,7 +2307,7 @@ static bool ed_operator_outliner_id_orphans_active(bContext *C) return true; } -/* Purge Orphans Operator --------------------------------------- */ +/** \} */ static void outliner_orphans_purge_tag(ID *id, int *num_tagged) { @@ -2331,3 +2425,5 @@ void OUTLINER_OT_orphans_purge(wmOperatorType *ot) PropertyRNA *prop = RNA_def_int(ot->srna, "num_deleted", 0, 0, INT_MAX, "", "", 0, INT_MAX); RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN); } + +/** \} */ diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h index 90092817acc..f2b64bc2a4b 100644 --- a/source/blender/editors/space_outliner/outliner_intern.h +++ b/source/blender/editors/space_outliner/outliner_intern.h @@ -108,7 +108,8 @@ typedef struct TreeElementIcon { ID_LP, \ ID_HA, \ ID_PT, \ - ID_VO) || /* Only in 'blendfile' mode ... :/ */ \ + ID_VO, \ + ID_SIM) || /* Only in 'blendfile' mode ... :/ */ \ ELEM(GS((_id)->name), \ ID_SCR, \ ID_WM, \ @@ -430,6 +431,7 @@ void OUTLINER_OT_animdata_operation(struct wmOperatorType *ot); void OUTLINER_OT_action_set(struct wmOperatorType *ot); void OUTLINER_OT_constraint_operation(struct wmOperatorType *ot); void OUTLINER_OT_modifier_operation(struct wmOperatorType *ot); +void OUTLINER_OT_delete(struct wmOperatorType *ot); /* ---------------------------------------------------------------- */ @@ -441,11 +443,16 @@ void outliner_keymap(struct wmKeyConfig *keyconf); bool outliner_is_collection_tree_element(const TreeElement *te); struct Collection *outliner_collection_from_tree_element(const TreeElement *te); +void outliner_collection_delete(struct bContext *C, + struct Main *bmain, + struct Scene *scene, + struct ReportList *reports, + bool hierarchy); void OUTLINER_OT_collection_new(struct wmOperatorType *ot); void OUTLINER_OT_collection_duplicate_linked(struct wmOperatorType *ot); void OUTLINER_OT_collection_duplicate(struct wmOperatorType *ot); -void OUTLINER_OT_collection_delete(struct wmOperatorType *ot); +void OUTLINER_OT_collection_hierarchy_delete(struct wmOperatorType *ot); void OUTLINER_OT_collection_objects_select(struct wmOperatorType *ot); void OUTLINER_OT_collection_objects_deselect(struct wmOperatorType *ot); void OUTLINER_OT_collection_link(struct wmOperatorType *ot); diff --git a/source/blender/editors/space_outliner/outliner_ops.c b/source/blender/editors/space_outliner/outliner_ops.c index 9d7efc7fe46..af7d97b6950 100644 --- a/source/blender/editors/space_outliner/outliner_ops.c +++ b/source/blender/editors/space_outliner/outliner_ops.c @@ -66,6 +66,7 @@ void outliner_operatortypes(void) WM_operatortype_append(OUTLINER_OT_action_set); WM_operatortype_append(OUTLINER_OT_constraint_operation); WM_operatortype_append(OUTLINER_OT_modifier_operation); + WM_operatortype_append(OUTLINER_OT_delete); WM_operatortype_append(OUTLINER_OT_show_one_level); WM_operatortype_append(OUTLINER_OT_show_active); @@ -93,7 +94,7 @@ void outliner_operatortypes(void) WM_operatortype_append(OUTLINER_OT_collection_new); WM_operatortype_append(OUTLINER_OT_collection_duplicate_linked); WM_operatortype_append(OUTLINER_OT_collection_duplicate); - WM_operatortype_append(OUTLINER_OT_collection_delete); + WM_operatortype_append(OUTLINER_OT_collection_hierarchy_delete); WM_operatortype_append(OUTLINER_OT_collection_objects_select); WM_operatortype_append(OUTLINER_OT_collection_objects_deselect); WM_operatortype_append(OUTLINER_OT_collection_link); diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c index 17970e8ed64..53f2c6a90d4 100644 --- a/source/blender/editors/space_outliner/outliner_tools.c +++ b/source/blender/editors/space_outliner/outliner_tools.c @@ -39,6 +39,7 @@ #include "DNA_pointcloud_types.h" #include "DNA_scene_types.h" #include "DNA_sequence_types.h" +#include "DNA_simulation_types.h" #include "DNA_volume_types.h" #include "DNA_world_types.h" @@ -88,9 +89,9 @@ #include "outliner_intern.h" -/* ****************************************************** */ - -/* ************ SELECTION OPERATIONS ********* */ +/* -------------------------------------------------------------------- */ +/** \name ID/Library/Data Set/Un-link Utilities + * \{ */ static void set_operation_types(SpaceOutliner *soops, ListBase *lb, @@ -160,6 +161,7 @@ static void set_operation_types(SpaceOutliner *soops, case ID_HA: case ID_PT: case ID_VO: + case ID_SIM: is_standard_id = true; break; case ID_WM: @@ -412,7 +414,12 @@ static void outliner_do_libdata_operation(bContext *C, } } -/* ******************************************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Scene Menu Operator + * \{ */ + typedef enum eOutliner_PropSceneOps { OL_SCENE_OP_DELETE = 1, } eOutliner_PropSceneOps; @@ -500,7 +507,12 @@ void OUTLINER_OT_scene_operation(wmOperatorType *ot) ot->prop = RNA_def_enum(ot->srna, "type", prop_scene_op_types, 0, "Scene Operation", ""); } -/* ******************************************** */ + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Search Utilities + * \{ */ /** * Stores the parent and a child element of a merged icon-row icon for @@ -541,10 +553,10 @@ static void merged_element_search_cb_recursive( } /* Get a list of elements that match the search string */ -static void merged_element_search_cb(const bContext *UNUSED(C), - void *data, - const char *str, - uiSearchItems *items) +static void merged_element_search_update_fn(const bContext *UNUSED(C), + void *data, + const char *str, + uiSearchItems *items) { MergedSearchData *search_data = (MergedSearchData *)data; TreeElement *parent = search_data->parent_element; @@ -556,7 +568,7 @@ static void merged_element_search_cb(const bContext *UNUSED(C), } /* Activate an element from the merged element search menu */ -static void merged_element_search_call_cb(struct bContext *C, void *UNUSED(arg1), void *element) +static void merged_element_search_exec_fn(struct bContext *C, void *UNUSED(arg1), void *element) { SpaceOutliner *soops = CTX_wm_space_outliner(C); TreeElement *te = (TreeElement *)element; @@ -588,7 +600,7 @@ static uiBlock *merged_element_search_menu(bContext *C, ARegion *region, void *d but = uiDefSearchBut( block, search, 0, ICON_VIEWZOOM, sizeof(search), 10, 10, menu_width, UI_UNIT_Y, 0, 0, ""); UI_but_func_search_set( - but, NULL, merged_element_search_cb, data, NULL, merged_element_search_call_cb, NULL, NULL); + but, NULL, merged_element_search_update_fn, data, NULL, merged_element_search_exec_fn, NULL); UI_but_flag_enable(but, UI_BUT_ACTIVATE_ON_INIT); /* Fake button to hold space for search items */ @@ -641,6 +653,12 @@ static void object_select_cb(bContext *C, } } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Callbacks (Selection, Users & Library) Utilities + * \{ */ + static void object_select_hierarchy_cb(bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), @@ -671,13 +689,10 @@ static void object_deselect_cb(bContext *C, } } -static void object_delete_cb(bContext *C, - ReportList *reports, - Scene *scene, - TreeElement *UNUSED(te), - TreeStoreElem *UNUSED(tsep), - TreeStoreElem *tselem, - void *UNUSED(user_data)) +static void outliner_object_delete(bContext *C, + ReportList *reports, + Scene *scene, + TreeStoreElem *tselem) { Object *ob = (Object *)tselem->id; if (ob) { @@ -883,7 +898,11 @@ void outliner_do_object_operation(bContext *C, outliner_do_object_operation_ex(C, reports, scene_act, soops, lb, operation_cb, NULL, true); } -/* ******************************************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Internal Tagging Utilities + * \{ */ static void clear_animdata_cb(int UNUSED(event), TreeElement *UNUSED(te), @@ -935,7 +954,11 @@ static void refreshdrivers_animdata_cb(int UNUSED(event), } } -/* --------------------------------- */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Object Operation Utilities + * \{ */ typedef enum eOutliner_PropDataOps { OL_DOP_SELECT = 1, @@ -1308,13 +1331,16 @@ static void object_batch_delete_hierarchy_cb(bContext *C, } } -/* **************************************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Object Menu Operator + * \{ */ enum { OL_OP_SELECT = 1, OL_OP_DESELECT, OL_OP_SELECT_HIERARCHY, - OL_OP_DELETE, OL_OP_DELETE_HIERARCHY, OL_OP_REMAP, OL_OP_LOCALIZED, /* disabled, see below */ @@ -1330,7 +1356,6 @@ static const EnumPropertyItem prop_object_op_types[] = { {OL_OP_SELECT, "SELECT", ICON_RESTRICT_SELECT_OFF, "Select", ""}, {OL_OP_DESELECT, "DESELECT", 0, "Deselect", ""}, {OL_OP_SELECT_HIERARCHY, "SELECT_HIERARCHY", 0, "Select Hierarchy", ""}, - {OL_OP_DELETE, "DELETE", ICON_X, "Delete", ""}, {OL_OP_DELETE_HIERARCHY, "DELETE_HIERARCHY", 0, "Delete Hierarchy", ""}, {OL_OP_REMAP, "REMAP", @@ -1386,29 +1411,6 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op) str = "Deselect Objects"; selection_changed = true; } - else if (event == OL_OP_DELETE) { - ViewLayer *view_layer = CTX_data_view_layer(C); - const Base *basact_prev = BASACT(view_layer); - - outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_delete_cb); - - /* XXX: tree management normally happens from draw_outliner(), but when - * you're clicking to fast on Delete object from context menu in - * outliner several mouse events can be handled in one cycle without - * handling notifiers/redraw which leads to deleting the same object twice. - * cleanup tree here to prevent such cases. */ - outliner_cleanup_tree(soops); - - DEG_relations_tag_update(bmain); - str = "Delete Objects"; - DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); - if (basact_prev != BASACT(view_layer)) { - WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); - WM_msg_publish_rna_prop(mbus, &scene->id, view_layer, LayerObjects, active); - } - selection_changed = true; - } else if (event == OL_OP_DELETE_HIERARCHY) { ViewLayer *view_layer = CTX_data_view_layer(C); const Base *basact_prev = BASACT(view_layer); @@ -1433,7 +1435,7 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op) BKE_id_multi_tagged_delete(bmain); } - /* XXX: See OL_OP_DELETE comment above. */ + /* XXX: See outliner_delete_exec comment below. */ outliner_cleanup_tree(soops); DEG_relations_tag_update(bmain); @@ -1503,7 +1505,85 @@ void OUTLINER_OT_object_operation(wmOperatorType *ot) ot->prop = RNA_def_enum(ot->srna, "type", prop_object_op_types, 0, "Object Operation", ""); } -/* **************************************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Delete Object/Collection Operator + * \{ */ + +static void outliner_objects_delete( + bContext *C, Scene *scene, SpaceOutliner *soops, ReportList *reports, ListBase *lb) +{ + LISTBASE_FOREACH (TreeElement *, te, lb) { + TreeStoreElem *tselem = TREESTORE(te); + + if (tselem->flag & TSE_SELECTED) { + if (tselem->type == 0 && te->idcode == ID_OB) { + outliner_object_delete(C, reports, scene, tselem); + } + } + + if (TSELEM_OPEN(tselem, soops)) { + outliner_objects_delete(C, scene, soops, reports, &te->subtree); + } + } +} + +static int outliner_delete_exec(bContext *C, wmOperator *op) +{ + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + SpaceOutliner *soops = CTX_wm_space_outliner(C); + struct wmMsgBus *mbus = CTX_wm_message_bus(C); + + ViewLayer *view_layer = CTX_data_view_layer(C); + const Base *basact_prev = BASACT(view_layer); + + outliner_collection_delete(C, bmain, scene, op->reports, false); + outliner_objects_delete(C, scene, soops, op->reports, &soops->tree); + + /* Tree management normally happens from draw_outliner(), but when + * you're clicking too fast on Delete object from context menu in + * outliner several mouse events can be handled in one cycle without + * handling notifiers/redraw which leads to deleting the same object twice. + * cleanup tree here to prevent such cases. */ + outliner_cleanup_tree(soops); + + DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE); + DEG_relations_tag_update(bmain); + + if (basact_prev != BASACT(view_layer)) { + WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); + WM_msg_publish_rna_prop(mbus, &scene->id, view_layer, LayerObjects, active); + } + + DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); + ED_outliner_select_sync_from_object_tag(C); + + return OPERATOR_FINISHED; +} + +void OUTLINER_OT_delete(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Delete"; + ot->idname = "OUTLINER_OT_delete"; + ot->description = "Delete selected objects and collections"; + + /* callbacks */ + ot->exec = outliner_delete_exec; + ot->poll = ED_operator_outliner_active; + + /* flags */ + ot->flag |= OPTYPE_REGISTER | OPTYPE_UNDO; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name ID-Data Menu Operator + * \{ */ typedef enum eOutlinerIdOpTypes { OUTLINER_IDOP_INVALID = 0, @@ -1810,7 +1890,11 @@ void OUTLINER_OT_id_operation(wmOperatorType *ot) RNA_def_enum_funcs(ot->prop, outliner_id_operation_itemf); } -/* **************************************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Library Menu Operator + * \{ */ typedef enum eOutlinerLibOpTypes { OL_LIB_INVALID = 0, @@ -1911,7 +1995,11 @@ void OUTLINER_OT_lib_operation(wmOperatorType *ot) ot->srna, "type", outliner_lib_op_type_items, 0, "Library Operation", ""); } -/* **************************************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Outliner Set Active Action Operator + * \{ */ static void outliner_do_id_set_operation( SpaceOutliner *soops, @@ -1937,8 +2025,6 @@ static void outliner_do_id_set_operation( } } -/* ------------------------------------------ */ - static void actionset_id_cb(TreeElement *UNUSED(te), TreeStoreElem *tselem, TreeStoreElem *tsep, @@ -2036,7 +2122,11 @@ void OUTLINER_OT_action_set(wmOperatorType *ot) ot->prop = prop; } -/* **************************************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Animation Menu Operator + * \{ */ typedef enum eOutliner_AnimDataOps { OUTLINER_ANIMOP_INVALID = 0, @@ -2156,7 +2246,11 @@ void OUTLINER_OT_animdata_operation(wmOperatorType *ot) ot->prop = RNA_def_enum(ot->srna, "type", prop_animdata_op_types, 0, "Animation Operation", ""); } -/* **************************************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Constraint Menu Operator + * \{ */ static const EnumPropertyItem prop_constraint_op_types[] = { {OL_CONSTRAINTOP_ENABLE, "ENABLE", ICON_HIDE_OFF, "Enable", ""}, @@ -2202,7 +2296,11 @@ void OUTLINER_OT_constraint_operation(wmOperatorType *ot) ot->srna, "type", prop_constraint_op_types, 0, "Constraint Operation", ""); } -/* ******************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Modifier Menu Operator + * \{ */ static const EnumPropertyItem prop_modifier_op_types[] = { {OL_MODIFIER_OP_TOGVIS, "TOGVIS", ICON_RESTRICT_VIEW_OFF, "Toggle viewport use", ""}, @@ -2247,7 +2345,11 @@ void OUTLINER_OT_modifier_operation(wmOperatorType *ot) ot->prop = RNA_def_enum(ot->srna, "type", prop_modifier_op_types, 0, "Modifier Operation", ""); } -/* ******************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Data Menu Operator + * \{ */ // XXX: select linked is for RNA structs only static const EnumPropertyItem prop_data_op_types[] = { @@ -2340,7 +2442,11 @@ void OUTLINER_OT_data_operation(wmOperatorType *ot) ot->prop = RNA_def_enum(ot->srna, "type", prop_data_op_types, 0, "Data Operation", ""); } -/* ******************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Context Menu Operator + * \{ */ static int outliner_operator_menu(bContext *C, const char *opname) { @@ -2505,4 +2611,4 @@ void OUTLINER_OT_operation(wmOperatorType *ot) ot->poll = ED_operator_outliner_active; } -/* ****************************************************** */ +/** \} */ diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c index b226d291188..7bb62b0d1e2 100644 --- a/source/blender/editors/space_outliner/outliner_tree.c +++ b/source/blender/editors/space_outliner/outliner_tree.c @@ -46,6 +46,7 @@ #include "DNA_pointcloud_types.h" #include "DNA_scene_types.h" #include "DNA_sequence_types.h" +#include "DNA_simulation_types.h" #include "DNA_speaker_types.h" #include "DNA_volume_types.h" #include "DNA_world_types.h" @@ -58,7 +59,7 @@ #include "BLT_translation.h" -#include "BKE_fcurve.h" +#include "BKE_fcurve_driver.h" #include "BKE_idtype.h" #include "BKE_layer.h" #include "BKE_lib_id.h" @@ -773,6 +774,13 @@ static void outliner_add_id_contents(SpaceOutliner *soops, outliner_add_element(soops, &te->subtree, volume, te, TSE_ANIM_DATA, 0); break; } + case ID_SIM: { + Simulation *simulation = (Simulation *)id; + if (outliner_animdata_test(simulation->adt)) { + outliner_add_element(soops, &te->subtree, simulation, te, TSE_ANIM_DATA, 0); + } + break; + } default: break; } diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c index 8624da9e8c2..c910f1d2382 100644 --- a/source/blender/editors/space_sequencer/sequencer_edit.c +++ b/source/blender/editors/space_sequencer/sequencer_edit.c @@ -2930,7 +2930,7 @@ static int sequencer_view_all_exec(bContext *C, wmOperator *op) void SEQUENCER_OT_view_all(wmOperatorType *ot) { /* Identifiers. */ - ot->name = "View All"; + ot->name = "Frame All"; ot->idname = "SEQUENCER_OT_view_all"; ot->description = "View all the strips in the sequencer"; @@ -3017,7 +3017,7 @@ static int sequencer_view_all_preview_exec(bContext *C, wmOperator *UNUSED(op)) void SEQUENCER_OT_view_all_preview(wmOperatorType *ot) { /* Identifiers. */ - ot->name = "View All"; + ot->name = "Frame All"; ot->idname = "SEQUENCER_OT_view_all_preview"; ot->description = "Zoom preview to fit in the area"; diff --git a/source/blender/editors/space_sequencer/sequencer_scopes.c b/source/blender/editors/space_sequencer/sequencer_scopes.c index b06bc7ad8b7..243a6e193eb 100644 --- a/source/blender/editors/space_sequencer/sequencer_scopes.c +++ b/source/blender/editors/space_sequencer/sequencer_scopes.c @@ -447,7 +447,6 @@ static void draw_histogram_bar(ImBuf *ibuf, int x, float val, int col) typedef struct MakeHistogramViewData { const ImBuf *ibuf; - uint32_t (*bins)[HIS_STEPS]; } MakeHistogramViewData; static void make_histogram_view_from_ibuf_byte_fn(void *__restrict userdata, @@ -469,17 +468,16 @@ static void make_histogram_view_from_ibuf_byte_fn(void *__restrict userdata, } } -static void make_histogram_view_from_ibuf_finalize(void *__restrict userdata, - void *__restrict userdata_chunk) +static void make_histogram_view_from_ibuf_reduce(const void *__restrict UNUSED(userdata), + void *__restrict chunk_join, + void *__restrict chunk) { - MakeHistogramViewData *data = userdata; - uint32_t(*bins)[HIS_STEPS] = data->bins; - - uint32_t(*cur_bins)[HIS_STEPS] = userdata_chunk; + uint32_t(*join_bins)[HIS_STEPS] = chunk_join; + uint32_t(*bins)[HIS_STEPS] = chunk; for (int j = 3; j--;) { for (int i = 0; i < HIS_STEPS; i++) { - bins[j][i] += cur_bins[j][i]; + join_bins[j][i] += bins[j][i]; } } } @@ -496,14 +494,13 @@ static ImBuf *make_histogram_view_from_ibuf_byte(ImBuf *ibuf) MakeHistogramViewData data = { .ibuf = ibuf, - .bins = bins, }; TaskParallelSettings settings; BLI_parallel_range_settings_defaults(&settings); settings.use_threading = (ibuf->y >= 256); settings.userdata_chunk = bins; settings.userdata_chunk_size = sizeof(bins); - settings.func_finalize = make_histogram_view_from_ibuf_finalize; + settings.func_reduce = make_histogram_view_from_ibuf_reduce; BLI_task_parallel_range(0, ibuf->y, &data, make_histogram_view_from_ibuf_byte_fn, &settings); nr = nb = ng = 0; @@ -582,14 +579,13 @@ static ImBuf *make_histogram_view_from_ibuf_float(ImBuf *ibuf) MakeHistogramViewData data = { .ibuf = ibuf, - .bins = bins, }; TaskParallelSettings settings; BLI_parallel_range_settings_defaults(&settings); settings.use_threading = (ibuf->y >= 256); settings.userdata_chunk = bins; settings.userdata_chunk_size = sizeof(bins); - settings.func_finalize = make_histogram_view_from_ibuf_finalize; + settings.func_reduce = make_histogram_view_from_ibuf_reduce; BLI_task_parallel_range(0, ibuf->y, &data, make_histogram_view_from_ibuf_float_fn, &settings); nr = nb = ng = 0; diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index e58559f4f6b..fac378ae104 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -63,6 +63,7 @@ #include "ED_armature.h" #include "ED_gpencil.h" +#include "ED_info.h" #include "ED_keyframing.h" #include "ED_screen.h" #include "ED_screen_types.h" @@ -101,6 +102,8 @@ #define M_GOLDEN_RATIO_CONJUGATE 0.618033988749895f +#define VIEW3D_OVERLAY_LINEHEIGHT (0.9f * U.widget_unit) + /* -------------------------------------------------------------------- */ /** \name General Functions * \{ */ @@ -1341,7 +1344,7 @@ static void draw_viewport_name(ARegion *region, View3D *v3d, int xoffset, int *y UI_FontThemeColor(BLF_default(), TH_TEXT_HI); - *yoffset -= U.widget_unit; + *yoffset -= VIEW3D_OVERLAY_LINEHEIGHT; BLF_draw_default(xoffset, *yoffset, 0.0f, name, sizeof(tmpstr)); @@ -1473,7 +1476,7 @@ static void draw_selected_name( BLF_shadow(font_id, 5, (const float[4]){0.0f, 0.0f, 0.0f, 1.0f}); BLF_shadow_offset(font_id, 1, -1); - *yoffset -= U.widget_unit; + *yoffset -= VIEW3D_OVERLAY_LINEHEIGHT; BLF_draw_default(xoffset, *yoffset, 0.0f, info, sizeof(info)); BLF_disable(font_id, BLF_SHADOW); @@ -1494,7 +1497,7 @@ static void draw_grid_unit_name( BLI_snprintf(numstr, sizeof(numstr), "%s x %.4g", grid_unit, v3d->grid); } - *yoffset -= U.widget_unit; + *yoffset -= VIEW3D_OVERLAY_LINEHEIGHT; BLF_enable(font_id, BLF_SHADOW); BLF_shadow(font_id, 5, (const float[4]){0.0f, 0.0f, 0.0f, 1.0f}); BLF_shadow_offset(font_id, 1, -1); @@ -1515,6 +1518,8 @@ void view3d_draw_region_info(const bContext *C, ARegion *region) View3D *v3d = CTX_wm_view3d(C); Scene *scene = CTX_data_scene(C); wmWindowManager *wm = CTX_wm_manager(C); + Main *bmain = CTX_data_main(C); + ViewLayer *view_layer = CTX_data_view_layer(C); #ifdef WITH_INPUT_NDOF if ((U.ndof_flag & NDOF_SHOW_GUIDE) && ((RV3D_LOCK_FLAGS(rv3d) & RV3D_LOCK_ROTATION) == 0) && @@ -1550,8 +1555,8 @@ void view3d_draw_region_info(const bContext *C, ARegion *region) } } - int xoffset = rect->xmin + U.widget_unit; - int yoffset = rect->ymax; + int xoffset = rect->xmin + (0.5f * U.widget_unit); + int yoffset = rect->ymax - (0.1f * U.widget_unit); if ((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0 && (v3d->overlay.flag & V3D_OVERLAY_HIDE_TEXT) == 0) { if ((U.uiflag & USER_SHOW_FPS) && ED_screen_animation_no_scrub(wm)) { @@ -1562,7 +1567,6 @@ void view3d_draw_region_info(const bContext *C, ARegion *region) } if (U.uiflag & USER_DRAWVIEWINFO) { - ViewLayer *view_layer = CTX_data_view_layer(C); Object *ob = OBACT(view_layer); draw_selected_name(scene, view_layer, ob, xoffset, &yoffset); } @@ -1571,10 +1575,12 @@ void view3d_draw_region_info(const bContext *C, ARegion *region) /* draw below the viewport name */ draw_grid_unit_name(scene, rv3d, v3d, xoffset, &yoffset); } + + DRW_draw_region_engine_info(xoffset, &yoffset, VIEW3D_OVERLAY_LINEHEIGHT); } - if ((v3d->overlay.flag & V3D_OVERLAY_HIDE_TEXT) == 0) { - DRW_draw_region_engine_info(xoffset, yoffset); + if ((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0 && (v3d->overlay.flag & V3D_OVERLAY_STATS)) { + ED_info_draw_stats(bmain, scene, view_layer, xoffset, &yoffset, VIEW3D_OVERLAY_LINEHEIGHT); } BLF_batch_draw_end(); @@ -2493,7 +2499,7 @@ void ED_scene_draw_fps(const Scene *scene, int xoffset, int *yoffset) BLF_shadow(font_id, 5, (const float[4]){0.0f, 0.0f, 0.0f, 1.0f}); BLF_shadow_offset(font_id, 1, -1); - *yoffset -= U.widget_unit; + *yoffset -= VIEW3D_OVERLAY_LINEHEIGHT; #ifdef WITH_INTERNATIONAL BLF_draw_default(xoffset, *yoffset, 0.0f, printable, sizeof(printable)); diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index 0a30336aed8..5cdf6ce28cb 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -2980,7 +2980,7 @@ static int view3d_all_exec(bContext *C, wmOperator *op) void VIEW3D_OT_view_all(wmOperatorType *ot) { /* identifiers */ - ot->name = "View All"; + ot->name = "Frame All"; ot->description = "View all objects in scene"; ot->idname = "VIEW3D_OT_view_all"; @@ -5372,6 +5372,7 @@ void VIEW3D_OT_toggle_xray(wmOperatorType *ot) /* identifiers */ ot->name = "Toggle X-Ray"; ot->idname = "VIEW3D_OT_toggle_xray"; + ot->description = "Transparent scene display. Allow selecting through items"; /* api callbacks */ ot->exec = toggle_xray_exec; diff --git a/source/blender/editors/space_view3d/view3d_iterators.c b/source/blender/editors/space_view3d/view3d_iterators.c index 3436aad9523..2ad7797f6c8 100644 --- a/source/blender/editors/space_view3d/view3d_iterators.c +++ b/source/blender/editors/space_view3d/view3d_iterators.c @@ -388,7 +388,7 @@ void mesh_foreachScreenFace( BM_mesh_elem_table_ensure(vc->em->bm, BM_FACE); - if (modifiers_usesSubsurfFacedots(vc->scene, vc->obedit)) { + if (BKE_modifiers_uses_subsurf_facedots(vc->scene, vc->obedit)) { BKE_mesh_foreach_mapped_subdiv_face_center( me, mesh_foreachScreenFace__mapFunc, &data, MESH_FOREACH_NOP); } diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c index 67c61b4ecac..2ce2edb98fe 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.c @@ -408,8 +408,8 @@ typedef struct LassoSelectUserData { const rcti *rect; const rctf *rect_fl; rctf _rect_fl; - const int (*mcords)[2]; - int moves; + const int (*mcoords)[2]; + int mcoords_len; eSelectOp sel_op; /* runtime */ @@ -421,8 +421,8 @@ typedef struct LassoSelectUserData { static void view3d_userdata_lassoselect_init(LassoSelectUserData *r_data, ViewContext *vc, const rcti *rect, - const int (*mcords)[2], - const int moves, + const int (*mcoords)[2], + const int mcoords_len, const eSelectOp sel_op) { r_data->vc = vc; @@ -431,8 +431,8 @@ static void view3d_userdata_lassoselect_init(LassoSelectUserData *r_data, r_data->rect_fl = &r_data->_rect_fl; BLI_rctf_rcti_copy(&r_data->_rect_fl, rect); - r_data->mcords = mcords; - r_data->moves = moves; + r_data->mcoords = mcoords; + r_data->mcoords_len = mcoords_len; r_data->sel_op = sel_op; /* runtime */ @@ -527,7 +527,8 @@ static void do_lasso_select_pose__do_tag(void *userData, if (screen_co_a[0] != IS_CLIPPED) { points_proj_tot++; if (BLI_rcti_isect_pt(data->rect, UNPACK2(screen_co_a)) && - BLI_lasso_is_point_inside(data->mcords, data->moves, UNPACK2(screen_co_a), INT_MAX)) { + BLI_lasso_is_point_inside( + data->mcoords, data->mcoords_len, UNPACK2(screen_co_a), INT_MAX)) { is_point_done = true; } } @@ -536,22 +537,28 @@ static void do_lasso_select_pose__do_tag(void *userData, if (screen_co_b[0] != IS_CLIPPED) { points_proj_tot++; if (BLI_rcti_isect_pt(data->rect, UNPACK2(screen_co_b)) && - BLI_lasso_is_point_inside(data->mcords, data->moves, UNPACK2(screen_co_b), INT_MAX)) { + BLI_lasso_is_point_inside( + data->mcoords, data->mcoords_len, UNPACK2(screen_co_b), INT_MAX)) { is_point_done = true; } } /* if one of points selected, we skip the bone itself */ - if ((is_point_done == true) || - ((is_point_done == false) && (points_proj_tot == 2) && - BLI_lasso_is_edge_inside( - data->mcords, data->moves, UNPACK2(screen_co_a), UNPACK2(screen_co_b), INT_MAX))) { + if ((is_point_done == true) || ((is_point_done == false) && (points_proj_tot == 2) && + BLI_lasso_is_edge_inside(data->mcoords, + data->mcoords_len, + UNPACK2(screen_co_a), + UNPACK2(screen_co_b), + INT_MAX))) { pchan->bone->flag |= BONE_DONE; } data->is_changed |= is_point_done; } } -static void do_lasso_tag_pose(ViewContext *vc, Object *ob, const int mcords[][2], short moves) +static void do_lasso_tag_pose(ViewContext *vc, + Object *ob, + const int mcoords[][2], + const int mcoords_len) { ViewContext vc_tmp; LassoSelectUserData data; @@ -564,9 +571,9 @@ static void do_lasso_tag_pose(ViewContext *vc, Object *ob, const int mcords[][2] vc_tmp = *vc; vc_tmp.obact = ob; - BLI_lasso_boundbox(&rect, mcords, moves); + BLI_lasso_boundbox(&rect, mcoords, mcoords_len); - view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, 0); + view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, 0); ED_view3d_init_mats_rv3d(vc_tmp.obact, vc->rv3d); @@ -574,8 +581,8 @@ static void do_lasso_tag_pose(ViewContext *vc, Object *ob, const int mcords[][2] } static bool do_lasso_select_objects(ViewContext *vc, - const int mcords[][2], - const short moves, + const int mcoords[][2], + const int mcoords_len, const eSelectOp sel_op) { View3D *v3d = vc->v3d; @@ -591,7 +598,7 @@ static bool do_lasso_select_objects(ViewContext *vc, const bool is_select = base->flag & BASE_SELECTED; const bool is_inside = ((ED_view3d_project_base(vc->region, base) == V3D_PROJ_RET_OK) && BLI_lasso_is_point_inside( - mcords, moves, base->sx, base->sy, IS_CLIPPED)); + mcoords, mcoords_len, base->sx, base->sy, IS_CLIPPED)); const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside); if (sel_op_result != -1) { ED_object_base_select(base, sel_op_result ? BA_SELECT : BA_DESELECT); @@ -685,8 +692,8 @@ static bool do_pose_tag_select_op_exec(Base **bases, const uint bases_len, const } static bool do_lasso_select_pose(ViewContext *vc, - const int mcords[][2], - const short moves, + const int mcoords[][2], + const int mcoords_len, const eSelectOp sel_op) { uint bases_len; @@ -695,7 +702,7 @@ static bool do_lasso_select_pose(ViewContext *vc, for (int i = 0; i < bases_len; i++) { Base *base_iter = bases[i]; Object *ob_iter = base_iter->object; - do_lasso_tag_pose(vc, ob_iter, mcords, moves); + do_lasso_tag_pose(vc, ob_iter, mcoords, mcoords_len); } const bool changed_multi = do_pose_tag_select_op_exec(bases, bases_len, sel_op); @@ -715,9 +722,10 @@ static void do_lasso_select_mesh__doSelectVert(void *userData, { LassoSelectUserData *data = userData; const bool is_select = BM_elem_flag_test(eve, BM_ELEM_SELECT); - const bool is_inside = (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) && - BLI_lasso_is_point_inside( - data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED)); + const bool is_inside = + (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) && + BLI_lasso_is_point_inside( + data->mcoords, data->mcoords_len, screen_co[0], screen_co[1], IS_CLIPPED)); const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); if (sel_op_result != -1) { BM_vert_select_set(data->vc->em->bm, eve, sel_op_result); @@ -746,8 +754,10 @@ static void do_lasso_select_mesh__doSelectEdge_pass0(void *user_data, const bool is_select = BM_elem_flag_test(eed, BM_ELEM_SELECT); const bool is_inside = (is_visible && edge_fully_inside_rect(data->rect_fl, screen_co_a, screen_co_b) && - BLI_lasso_is_point_inside(data->mcords, data->moves, UNPACK2(screen_co_a), IS_CLIPPED) && - BLI_lasso_is_point_inside(data->mcords, data->moves, UNPACK2(screen_co_b), IS_CLIPPED)); + BLI_lasso_is_point_inside( + data->mcoords, data->mcoords_len, UNPACK2(screen_co_a), IS_CLIPPED) && + BLI_lasso_is_point_inside( + data->mcoords, data->mcoords_len, UNPACK2(screen_co_b), IS_CLIPPED)); const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); if (sel_op_result != -1) { BM_edge_select_set(data->vc->em->bm, eed, sel_op_result); @@ -770,8 +780,8 @@ static void do_lasso_select_mesh__doSelectEdge_pass1(void *user_data, } const bool is_select = BM_elem_flag_test(eed, BM_ELEM_SELECT); - const bool is_inside = (is_visible && BLI_lasso_is_edge_inside(data->mcords, - data->moves, + const bool is_inside = (is_visible && BLI_lasso_is_edge_inside(data->mcoords, + data->mcoords_len, UNPACK2(screen_co_a), UNPACK2(screen_co_b), IS_CLIPPED)); @@ -789,9 +799,10 @@ static void do_lasso_select_mesh__doSelectFace(void *userData, { LassoSelectUserData *data = userData; const bool is_select = BM_elem_flag_test(efa, BM_ELEM_SELECT); - const bool is_inside = (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) && - BLI_lasso_is_point_inside( - data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED)); + const bool is_inside = + (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) && + BLI_lasso_is_point_inside( + data->mcoords, data->mcoords_len, screen_co[0], screen_co[1], IS_CLIPPED)); const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); if (sel_op_result != -1) { BM_face_select_set(data->vc->em->bm, efa, sel_op_result); @@ -801,8 +812,8 @@ static void do_lasso_select_mesh__doSelectFace(void *userData, static bool do_lasso_select_mesh(ViewContext *vc, wmGenericUserData *wm_userdata, - const int mcords[][2], - short moves, + const int mcoords[][2], + const int mcoords_len, const eSelectOp sel_op) { LassoSelectUserData data; @@ -812,9 +823,9 @@ static bool do_lasso_select_mesh(ViewContext *vc, /* set editmesh */ vc->em = BKE_editmesh_from_object(vc->obedit); - BLI_lasso_boundbox(&rect, mcords, moves); + BLI_lasso_boundbox(&rect, mcoords, mcoords_len); - view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, sel_op); + view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, sel_op); if (SEL_OP_USE_PRE_DESELECT(sel_op)) { if (vc->em->bm->totvertsel) { @@ -836,7 +847,7 @@ static bool do_lasso_select_mesh(ViewContext *vc, editselect_buf_cache_init_with_generic_userdata(wm_userdata, vc, ts->selectmode); esel = wm_userdata->data; esel->select_bitmap = DRW_select_buffer_bitmap_from_poly( - vc->depsgraph, vc->region, vc->v3d, mcords, moves, &rect, NULL); + vc->depsgraph, vc->region, vc->v3d, mcoords, mcoords_len, &rect, NULL); } } @@ -897,7 +908,7 @@ static void do_lasso_select_curve__doSelect(void *userData, LassoSelectUserData *data = userData; const bool is_inside = BLI_lasso_is_point_inside( - data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED); + data->mcoords, data->mcoords_len, screen_co[0], screen_co[1], IS_CLIPPED); if (bp) { const bool is_select = bp->f1 & SELECT; const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); @@ -930,16 +941,16 @@ static void do_lasso_select_curve__doSelect(void *userData, } static bool do_lasso_select_curve(ViewContext *vc, - const int mcords[][2], - short moves, + const int mcoords[][2], + const int mcoords_len, const eSelectOp sel_op) { LassoSelectUserData data; rcti rect; - BLI_lasso_boundbox(&rect, mcords, moves); + BLI_lasso_boundbox(&rect, mcoords, mcoords_len); - view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, sel_op); + view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, sel_op); if (SEL_OP_USE_PRE_DESELECT(sel_op)) { Curve *curve = (Curve *)vc->obedit->data; @@ -958,9 +969,10 @@ static void do_lasso_select_lattice__doSelect(void *userData, BPoint *bp, const { LassoSelectUserData *data = userData; const bool is_select = bp->f1 & SELECT; - const bool is_inside = (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) && - BLI_lasso_is_point_inside( - data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED)); + const bool is_inside = + (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) && + BLI_lasso_is_point_inside( + data->mcoords, data->mcoords_len, screen_co[0], screen_co[1], IS_CLIPPED)); const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); if (sel_op_result != -1) { SET_FLAG_FROM_TEST(bp->f1, sel_op_result, SELECT); @@ -968,16 +980,16 @@ static void do_lasso_select_lattice__doSelect(void *userData, BPoint *bp, const } } static bool do_lasso_select_lattice(ViewContext *vc, - const int mcords[][2], - short moves, + const int mcoords[][2], + const int mcoords_len, const eSelectOp sel_op) { LassoSelectUserData data; rcti rect; - BLI_lasso_boundbox(&rect, mcords, moves); + BLI_lasso_boundbox(&rect, mcoords, mcoords_len); - view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, sel_op); + view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, sel_op); if (SEL_OP_USE_PRE_DESELECT(sel_op)) { data.is_changed |= ED_lattice_flags_set(vc->obedit, 0); @@ -1002,7 +1014,8 @@ static void do_lasso_select_armature__doSelectBone(void *userData, if (screen_co_a[0] != IS_CLIPPED) { if (BLI_rcti_isect_pt(data->rect, UNPACK2(screen_co_a)) && - BLI_lasso_is_point_inside(data->mcords, data->moves, UNPACK2(screen_co_a), INT_MAX)) { + BLI_lasso_is_point_inside( + data->mcoords, data->mcoords_len, UNPACK2(screen_co_a), INT_MAX)) { is_inside_flag |= BONESEL_ROOT; } } @@ -1012,7 +1025,8 @@ static void do_lasso_select_armature__doSelectBone(void *userData, if (screen_co_b[0] != IS_CLIPPED) { if (BLI_rcti_isect_pt(data->rect, UNPACK2(screen_co_b)) && - BLI_lasso_is_point_inside(data->mcords, data->moves, UNPACK2(screen_co_b), INT_MAX)) { + BLI_lasso_is_point_inside( + data->mcoords, data->mcoords_len, UNPACK2(screen_co_b), INT_MAX)) { is_inside_flag |= BONESEL_TIP; } } @@ -1022,8 +1036,11 @@ static void do_lasso_select_armature__doSelectBone(void *userData, if (is_ignore_flag == 0) { if (is_inside_flag == (BONE_ROOTSEL | BONE_TIPSEL) || - BLI_lasso_is_edge_inside( - data->mcords, data->moves, UNPACK2(screen_co_a), UNPACK2(screen_co_b), INT_MAX)) { + BLI_lasso_is_edge_inside(data->mcoords, + data->mcoords_len, + UNPACK2(screen_co_a), + UNPACK2(screen_co_b), + INT_MAX)) { is_inside_flag |= BONESEL_BONE; } } @@ -1033,16 +1050,16 @@ static void do_lasso_select_armature__doSelectBone(void *userData, } static bool do_lasso_select_armature(ViewContext *vc, - const int mcords[][2], - short moves, + const int mcoords[][2], + const int mcoords_len, const eSelectOp sel_op) { LassoSelectUserData data; rcti rect; - BLI_lasso_boundbox(&rect, mcords, moves); + BLI_lasso_boundbox(&rect, mcoords, mcoords_len); - view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, sel_op); + view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, sel_op); if (SEL_OP_USE_PRE_DESELECT(sel_op)) { data.is_changed |= ED_armature_edit_deselect_all_visible(vc->obedit); @@ -1071,9 +1088,10 @@ static void do_lasso_select_mball__doSelectElem(void *userData, { LassoSelectUserData *data = userData; const bool is_select = ml->flag & SELECT; - const bool is_inside = (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) && - BLI_lasso_is_point_inside( - data->mcords, data->moves, screen_co[0], screen_co[1], INT_MAX)); + const bool is_inside = + (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) && + BLI_lasso_is_point_inside( + data->mcoords, data->mcoords_len, screen_co[0], screen_co[1], INT_MAX)); const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); if (sel_op_result != -1) { SET_FLAG_FROM_TEST(ml->flag, sel_op_result, SELECT); @@ -1081,8 +1099,8 @@ static void do_lasso_select_mball__doSelectElem(void *userData, } } static bool do_lasso_select_meta(ViewContext *vc, - const int mcords[][2], - short moves, + const int mcoords[][2], + const int mcoords_len, const eSelectOp sel_op) { LassoSelectUserData data; @@ -1090,9 +1108,9 @@ static bool do_lasso_select_meta(ViewContext *vc, MetaBall *mb = (MetaBall *)vc->obedit->data; - BLI_lasso_boundbox(&rect, mcords, moves); + BLI_lasso_boundbox(&rect, mcoords, mcoords_len); - view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, sel_op); + view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, sel_op); if (SEL_OP_USE_PRE_DESELECT(sel_op)) { data.is_changed |= BKE_mball_deselect_all(mb); @@ -1113,9 +1131,10 @@ static void do_lasso_select_meshobject__doSelectVert(void *userData, { LassoSelectUserData *data = userData; const bool is_select = mv->flag & SELECT; - const bool is_inside = (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) && - BLI_lasso_is_point_inside( - data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED)); + const bool is_inside = + (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) && + BLI_lasso_is_point_inside( + data->mcoords, data->mcoords_len, screen_co[0], screen_co[1], IS_CLIPPED)); const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); if (sel_op_result != -1) { SET_FLAG_FROM_TEST(mv->flag, sel_op_result, SELECT); @@ -1124,8 +1143,8 @@ static void do_lasso_select_meshobject__doSelectVert(void *userData, } static bool do_lasso_select_paintvert(ViewContext *vc, wmGenericUserData *wm_userdata, - const int mcords[][2], - short moves, + const int mcoords[][2], + const int mcoords_len, const eSelectOp sel_op) { const bool use_zbuf = !XRAY_ENABLED(vc->v3d); @@ -1143,7 +1162,7 @@ static bool do_lasso_select_paintvert(ViewContext *vc, changed |= paintvert_deselect_all_visible(ob, SEL_DESELECT, false); } - BLI_lasso_boundbox(&rect, mcords, moves); + BLI_lasso_boundbox(&rect, mcoords, mcoords_len); struct EditSelectBuf_Cache *esel = wm_userdata->data; if (use_zbuf) { @@ -1151,7 +1170,7 @@ static bool do_lasso_select_paintvert(ViewContext *vc, editselect_buf_cache_init_with_generic_userdata(wm_userdata, vc, SCE_SELECT_VERTEX); esel = wm_userdata->data; esel->select_bitmap = DRW_select_buffer_bitmap_from_poly( - vc->depsgraph, vc->region, vc->v3d, mcords, moves, &rect, NULL); + vc->depsgraph, vc->region, vc->v3d, mcoords, mcoords_len, &rect, NULL); } } @@ -1163,7 +1182,7 @@ static bool do_lasso_select_paintvert(ViewContext *vc, else { LassoSelectUserData data; - view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, sel_op); + view3d_userdata_lassoselect_init(&data, vc, &rect, mcoords, mcoords_len, sel_op); ED_view3d_init_mats_rv3d(vc->obact, vc->rv3d); @@ -1185,8 +1204,8 @@ static bool do_lasso_select_paintvert(ViewContext *vc, } static bool do_lasso_select_paintface(ViewContext *vc, wmGenericUserData *wm_userdata, - const int mcords[][2], - short moves, + const int mcoords[][2], + const int mcoords_len, const eSelectOp sel_op) { Object *ob = vc->obact; @@ -1203,14 +1222,14 @@ static bool do_lasso_select_paintface(ViewContext *vc, changed |= paintface_deselect_all_visible(vc->C, ob, SEL_DESELECT, false); } - BLI_lasso_boundbox(&rect, mcords, moves); + BLI_lasso_boundbox(&rect, mcoords, mcoords_len); struct EditSelectBuf_Cache *esel = wm_userdata->data; if (esel == NULL) { editselect_buf_cache_init_with_generic_userdata(wm_userdata, vc, SCE_SELECT_FACE); esel = wm_userdata->data; esel->select_bitmap = DRW_select_buffer_bitmap_from_poly( - vc->depsgraph, vc->region, vc->v3d, mcords, moves, &rect, NULL); + vc->depsgraph, vc->region, vc->v3d, mcoords, mcoords_len, &rect, NULL); } if (esel->select_bitmap) { @@ -1224,7 +1243,7 @@ static bool do_lasso_select_paintface(ViewContext *vc, } #if 0 -static void do_lasso_select_node(int mcords[][2], short moves, const eSelectOp sel_op) +static void do_lasso_select_node(int mcoords[][2], const int mcoords_len, const eSelectOp sel_op) { SpaceNode *snode = area->spacedata.first; @@ -1234,7 +1253,7 @@ static void do_lasso_select_node(int mcords[][2], short moves, const eSelectOp s float node_centf[2]; bool changed = false; - BLI_lasso_boundbox(&rect, mcords, moves); + BLI_lasso_boundbox(&rect, mcoords, mcoords_len); /* store selection in temp test flag */ for (node = snode->edittree->nodes.first; node; node = node->next) { @@ -1244,7 +1263,7 @@ static void do_lasso_select_node(int mcords[][2], short moves, const eSelectOp s ipoco_to_areaco_noclip(G.v2d, node_centf, node_cent); const bool is_select = node->flag & SELECT; const bool is_inside = (BLI_rcti_isect_pt_v(&rect, node_cent) && - BLI_lasso_is_point_inside(mcords, moves, node_cent[0], node_cent[1])); + BLI_lasso_is_point_inside(mcoords, mcoords_len, node_cent[0], node_cent[1])); const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside); if (sel_op_result != -1) { SET_FLAG_FROM_TEST(node->flag, sel_op_result, SELECT); @@ -1257,8 +1276,11 @@ static void do_lasso_select_node(int mcords[][2], short moves, const eSelectOp s } #endif -static bool view3d_lasso_select( - bContext *C, ViewContext *vc, const int mcords[][2], short moves, const eSelectOp sel_op) +static bool view3d_lasso_select(bContext *C, + ViewContext *vc, + const int mcoords[][2], + const int mcoords_len, + const eSelectOp sel_op) { Object *ob = CTX_data_active_object(C); bool changed_multi = false; @@ -1268,26 +1290,26 @@ static bool view3d_lasso_select( if (vc->obedit == NULL) { /* Object Mode */ if (BKE_paint_select_face_test(ob)) { - changed_multi |= do_lasso_select_paintface(vc, wm_userdata, mcords, moves, sel_op); + changed_multi |= do_lasso_select_paintface(vc, wm_userdata, mcoords, mcoords_len, sel_op); } else if (BKE_paint_select_vert_test(ob)) { - changed_multi |= do_lasso_select_paintvert(vc, wm_userdata, mcords, moves, sel_op); + changed_multi |= do_lasso_select_paintvert(vc, wm_userdata, mcoords, mcoords_len, sel_op); } else if (ob && (ob->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | OB_MODE_TEXTURE_PAINT))) { /* pass */ } else if (ob && (ob->mode & OB_MODE_PARTICLE_EDIT)) { - changed_multi |= PE_lasso_select(C, mcords, moves, sel_op); + changed_multi |= PE_lasso_select(C, mcoords, mcoords_len, sel_op); } else if (ob && (ob->mode & OB_MODE_POSE)) { - changed_multi |= do_lasso_select_pose(vc, mcords, moves, sel_op); + changed_multi |= do_lasso_select_pose(vc, mcoords, mcoords_len, sel_op); if (changed_multi) { ED_outliner_select_sync_from_pose_bone_tag(C); } } else { - changed_multi |= do_lasso_select_objects(vc, mcords, moves, sel_op); + changed_multi |= do_lasso_select_objects(vc, mcoords, mcoords_len, sel_op); if (changed_multi) { ED_outliner_select_sync_from_object_tag(C); } @@ -1300,23 +1322,23 @@ static bool view3d_lasso_select( switch (vc->obedit->type) { case OB_MESH: - changed = do_lasso_select_mesh(vc, wm_userdata, mcords, moves, sel_op); + changed = do_lasso_select_mesh(vc, wm_userdata, mcoords, mcoords_len, sel_op); break; case OB_CURVE: case OB_SURF: - changed = do_lasso_select_curve(vc, mcords, moves, sel_op); + changed = do_lasso_select_curve(vc, mcoords, mcoords_len, sel_op); break; case OB_LATTICE: - changed = do_lasso_select_lattice(vc, mcords, moves, sel_op); + changed = do_lasso_select_lattice(vc, mcoords, mcoords_len, sel_op); break; case OB_ARMATURE: - changed = do_lasso_select_armature(vc, mcords, moves, sel_op); + changed = do_lasso_select_armature(vc, mcoords, mcoords_len, sel_op); if (changed) { ED_outliner_select_sync_from_edit_bone_tag(C); } break; case OB_MBALL: - changed = do_lasso_select_meta(vc, mcords, moves, sel_op); + changed = do_lasso_select_meta(vc, mcoords, mcoords_len, sel_op); break; default: BLI_assert(!"lasso select on incorrect object type"); @@ -1342,10 +1364,10 @@ static bool view3d_lasso_select( static int view3d_lasso_select_exec(bContext *C, wmOperator *op) { ViewContext vc; - int mcords_tot; - const int(*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot); + int mcoords_len; + const int(*mcoords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcoords_len); - if (mcords) { + if (mcoords) { Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); view3d_operator_needs_opengl(C); BKE_object_update_select_id(CTX_data_main(C)); @@ -1354,9 +1376,9 @@ static int view3d_lasso_select_exec(bContext *C, wmOperator *op) ED_view3d_viewcontext_init(C, &vc, depsgraph); eSelectOp sel_op = RNA_enum_get(op->ptr, "mode"); - bool changed_multi = view3d_lasso_select(C, &vc, mcords, mcords_tot, sel_op); + bool changed_multi = view3d_lasso_select(C, &vc, mcoords, mcoords_len, sel_op); - MEM_freeN((void *)mcords); + MEM_freeN((void *)mcoords); if (changed_multi) { return OPERATOR_FINISHED; @@ -1982,7 +2004,7 @@ static bool ed_object_select_pick(bContext *C, /* setup view context for argument to callbacks */ ED_view3d_viewcontext_init(C, &vc, depsgraph); - ARegion *region = CTX_wm_region(C); + const ARegion *region = CTX_wm_region(C); Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); View3D *v3d = CTX_wm_view3d(C); diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c index b90f7aa870e..fe77ca05a04 100644 --- a/source/blender/editors/space_view3d/view3d_view.c +++ b/source/blender/editors/space_view3d/view3d_view.c @@ -1062,7 +1062,7 @@ int view3d_opengl_select(ViewContext *vc, * the number of items is nearly always 1, maybe 2..3 in rare cases. */ LinkNode *ob_pose_list = NULL; VirtualModifierData virtualModifierData; - const ModifierData *md = modifiers_getVirtualModifierList(obact, &virtualModifierData); + const ModifierData *md = BKE_modifiers_get_virtual_modifierlist(obact, &virtualModifierData); for (; md; md = md->next) { if (md->type == eModifierType_Armature) { ArmatureModifierData *amd = (ArmatureModifierData *)md; diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index d376c71d867..5fc65522fe6 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -778,9 +778,10 @@ wmKeyMap *transform_modal_keymap(wmKeyConfig *keyconf) return keymap; } -static void transform_event_xyz_constraint(TransInfo *t, short key_type, char cmode, bool is_plane) +static void transform_event_xyz_constraint(TransInfo *t, short key_type, bool is_plane) { if (!(t->flag & T_NO_CONSTRAINT)) { + char cmode = constraintModeToChar(t); int constraint_axis, constraint_plane; const bool edit_2d = (t->flag & T_2D_EDIT) != 0; const char *msg1 = "", *msg2 = "", *msg3 = ""; @@ -824,11 +825,17 @@ static void transform_event_xyz_constraint(TransInfo *t, short key_type, char cm } } else if (!edit_2d) { - if (cmode != axis) { - /* First press, constraint to an axis. */ - t->orientation.index = 0; - const short *orientation_ptr = t->orientation.types[t->orientation.index]; - const short orientation = orientation_ptr ? *orientation_ptr : V3D_ORIENT_GLOBAL; + if (t->orient_curr == 0 || ELEM(cmode, '\0', axis)) { + /* Successive presses on existing axis, cycle orientation modes. */ + t->orient_curr = (short)((t->orient_curr + 1) % (int)ARRAY_SIZE(t->orient)); + transform_orientations_current_set(t, t->orient_curr); + } + + if (t->orient_curr == 0) { + stopConstraint(t); + } + else { + const short orientation = t->orient[t->orient_curr].type; if (is_plane == false) { setUserConstraint(t, orientation, constraint_axis, msg2); } @@ -836,24 +843,6 @@ static void transform_event_xyz_constraint(TransInfo *t, short key_type, char cm setUserConstraint(t, orientation, constraint_plane, msg3); } } - else { - /* Successive presses on existing axis, cycle orientation modes. */ - t->orientation.index = (t->orientation.index + 1) % ARRAY_SIZE(t->orientation.types); - - if (t->orientation.index == 0) { - stopConstraint(t); - } - else { - const short *orientation_ptr = t->orientation.types[t->orientation.index]; - const short orientation = orientation_ptr ? *orientation_ptr : V3D_ORIENT_GLOBAL; - if (is_plane == false) { - setUserConstraint(t, orientation, constraint_axis, msg2); - } - else { - setUserConstraint(t, orientation, constraint_plane, msg3); - } - } - } } t->redraw |= TREDRAW_HARD; } @@ -861,7 +850,6 @@ static void transform_event_xyz_constraint(TransInfo *t, short key_type, char cm int transformEvent(TransInfo *t, const wmEvent *event) { - char cmode = constraintModeToChar(t); bool handled = false; const int modifiers_prev = t->modifiers; const int mode_prev = t->mode; @@ -908,74 +896,59 @@ int transformEvent(TransInfo *t, const wmEvent *event) break; case TFM_MODAL_TRANSLATE: /* only switch when... */ - if (ELEM(t->mode, - TFM_ROTATION, - TFM_RESIZE, - TFM_TRACKBALL, - TFM_EDGE_SLIDE, - TFM_VERT_SLIDE)) { - restoreTransObjects(t); - resetTransModal(t); - resetTransRestrictions(t); - transform_mode_init(t, NULL, TFM_TRANSLATION); - initSnapping(t, NULL); // need to reinit after mode change - t->redraw |= TREDRAW_HARD; - handled = true; - } - else if (t->mode == TFM_SEQ_SLIDE) { - t->flag ^= T_ALT_TRANSFORM; - t->redraw |= TREDRAW_HARD; - handled = true; - } - else { - if (t->obedit_type == OB_MESH) { - if ((t->mode == TFM_TRANSLATION) && (t->spacetype == SPACE_VIEW3D)) { - restoreTransObjects(t); + if (t->mode == TFM_TRANSLATION) { + if ((t->obedit_type == OB_MESH) && (t->spacetype == SPACE_VIEW3D)) { + restoreTransObjects(t); + resetTransModal(t); + resetTransRestrictions(t); + + /* first try edge slide */ + transform_mode_init(t, NULL, TFM_EDGE_SLIDE); + /* if that fails, do vertex slide */ + if (t->state == TRANS_CANCEL) { + resetTransModal(t); + t->state = TRANS_STARTING; + transform_mode_init(t, NULL, TFM_VERT_SLIDE); + } + /* vert slide can fail on unconnected vertices (rare but possible) */ + if (t->state == TRANS_CANCEL) { resetTransModal(t); + t->state = TRANS_STARTING; + restoreTransObjects(t); resetTransRestrictions(t); - - /* first try edge slide */ - transform_mode_init(t, NULL, TFM_EDGE_SLIDE); - /* if that fails, do vertex slide */ - if (t->state == TRANS_CANCEL) { - resetTransModal(t); - t->state = TRANS_STARTING; - transform_mode_init(t, NULL, TFM_VERT_SLIDE); - } - /* vert slide can fail on unconnected vertices (rare but possible) */ - if (t->state == TRANS_CANCEL) { - resetTransModal(t); - t->state = TRANS_STARTING; - restoreTransObjects(t); - resetTransRestrictions(t); - transform_mode_init(t, NULL, TFM_TRANSLATION); - } - initSnapping(t, NULL); // need to reinit after mode change - t->redraw |= TREDRAW_HARD; - handled = true; + transform_mode_init(t, NULL, TFM_TRANSLATION); } + initSnapping(t, NULL); // need to reinit after mode change + t->redraw |= TREDRAW_HARD; + handled = true; } else if (t->options & (CTX_MOVIECLIP | CTX_MASK)) { - if (t->mode == TFM_TRANSLATION) { - restoreTransObjects(t); + restoreTransObjects(t); - t->flag ^= T_ALT_TRANSFORM; - t->redraw |= TREDRAW_HARD; - handled = true; - } + t->flag ^= T_ALT_TRANSFORM; + t->redraw |= TREDRAW_HARD; + handled = true; } } + else if (t->mode == TFM_SEQ_SLIDE) { + t->flag ^= T_ALT_TRANSFORM; + t->redraw |= TREDRAW_HARD; + handled = true; + } + else if (transform_mode_is_changeable(t->mode)) { + restoreTransObjects(t); + resetTransModal(t); + resetTransRestrictions(t); + transform_mode_init(t, NULL, TFM_TRANSLATION); + initSnapping(t, NULL); // need to reinit after mode change + t->redraw |= TREDRAW_HARD; + handled = true; + } break; case TFM_MODAL_ROTATE: /* only switch when... */ if (!(t->options & CTX_TEXTURE) && !(t->options & (CTX_MOVIECLIP | CTX_MASK))) { - if (ELEM(t->mode, - TFM_ROTATION, - TFM_RESIZE, - TFM_TRACKBALL, - TFM_TRANSLATION, - TFM_EDGE_SLIDE, - TFM_VERT_SLIDE)) { + if (transform_mode_is_changeable(t->mode)) { restoreTransObjects(t); resetTransModal(t); resetTransRestrictions(t); @@ -994,15 +967,23 @@ int transformEvent(TransInfo *t, const wmEvent *event) break; case TFM_MODAL_RESIZE: /* only switch when... */ - if (ELEM(t->mode, - TFM_ROTATION, - TFM_TRANSLATION, - TFM_TRACKBALL, - TFM_EDGE_SLIDE, - TFM_VERT_SLIDE)) { + if (t->mode == TFM_RESIZE) { + if (t->options & CTX_MOVIECLIP) { + restoreTransObjects(t); + t->flag ^= T_ALT_TRANSFORM; + t->redraw |= TREDRAW_HARD; + handled = true; + } + } + else if (t->mode == TFM_SHRINKFATTEN) { + t->flag ^= T_ALT_TRANSFORM; + t->redraw |= TREDRAW_HARD; + handled = true; + } + else if (transform_mode_is_changeable(t->mode)) { /* Scale isn't normally very useful after extrude along normals, see T39756 */ - if ((t->con.mode & CON_APPLY) && (t->con.orientation == V3D_ORIENT_NORMAL)) { + if ((t->con.mode & CON_APPLY) && (t->orient[t->orient_curr].type == V3D_ORIENT_NORMAL)) { stopConstraint(t); } @@ -1014,20 +995,6 @@ int transformEvent(TransInfo *t, const wmEvent *event) t->redraw |= TREDRAW_HARD; handled = true; } - else if (t->mode == TFM_SHRINKFATTEN) { - t->flag ^= T_ALT_TRANSFORM; - t->redraw |= TREDRAW_HARD; - handled = true; - } - else if (t->mode == TFM_RESIZE) { - if (t->options & CTX_MOVIECLIP) { - restoreTransObjects(t); - - t->flag ^= T_ALT_TRANSFORM; - t->redraw |= TREDRAW_HARD; - handled = true; - } - } break; case TFM_MODAL_SNAP_INV_ON: @@ -1047,42 +1014,42 @@ int transformEvent(TransInfo *t, const wmEvent *event) break; case TFM_MODAL_AXIS_X: if (!(t->flag & T_NO_CONSTRAINT)) { - transform_event_xyz_constraint(t, EVT_XKEY, cmode, false); + transform_event_xyz_constraint(t, EVT_XKEY, false); t->redraw |= TREDRAW_HARD; handled = true; } break; case TFM_MODAL_AXIS_Y: if ((t->flag & T_NO_CONSTRAINT) == 0) { - transform_event_xyz_constraint(t, EVT_YKEY, cmode, false); + transform_event_xyz_constraint(t, EVT_YKEY, false); t->redraw |= TREDRAW_HARD; handled = true; } break; case TFM_MODAL_AXIS_Z: if ((t->flag & (T_NO_CONSTRAINT)) == 0) { - transform_event_xyz_constraint(t, EVT_ZKEY, cmode, false); + transform_event_xyz_constraint(t, EVT_ZKEY, false); t->redraw |= TREDRAW_HARD; handled = true; } break; case TFM_MODAL_PLANE_X: if ((t->flag & (T_NO_CONSTRAINT | T_2D_EDIT)) == 0) { - transform_event_xyz_constraint(t, EVT_XKEY, cmode, true); + transform_event_xyz_constraint(t, EVT_XKEY, true); t->redraw |= TREDRAW_HARD; handled = true; } break; case TFM_MODAL_PLANE_Y: if ((t->flag & (T_NO_CONSTRAINT | T_2D_EDIT)) == 0) { - transform_event_xyz_constraint(t, EVT_YKEY, cmode, true); + transform_event_xyz_constraint(t, EVT_YKEY, true); t->redraw |= TREDRAW_HARD; handled = true; } break; case TFM_MODAL_PLANE_Z: if ((t->flag & (T_NO_CONSTRAINT | T_2D_EDIT)) == 0) { - transform_event_xyz_constraint(t, EVT_ZKEY, cmode, true); + transform_event_xyz_constraint(t, EVT_ZKEY, true); t->redraw |= TREDRAW_HARD; handled = true; } @@ -1228,17 +1195,7 @@ int transformEvent(TransInfo *t, const wmEvent *event) stopConstraint(t); } else { - if (event->shift) { - /* bit hackish... but it prevents mmb select to print the - * orientation from menu */ - float mati[3][3]; - strcpy(t->spacename, "global"); - unit_m3(mati); - initSelectConstraint(t, mati); - } - else { - initSelectConstraint(t, t->spacemtx); - } + initSelectConstraint(t, event->shift); postSelectConstraint(t); } } @@ -1251,7 +1208,7 @@ int transformEvent(TransInfo *t, const wmEvent *event) break; } /* only switch when... */ - if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL)) { + if (t->mode != TFM_TRANSLATION && transform_mode_is_changeable(t->mode)) { restoreTransObjects(t); resetTransModal(t); resetTransRestrictions(t); @@ -1266,7 +1223,7 @@ int transformEvent(TransInfo *t, const wmEvent *event) break; } /* only switch when... */ - if (ELEM(t->mode, TFM_ROTATION, TFM_TRANSLATION, TFM_TRACKBALL)) { + if (t->mode != TFM_RESIZE && transform_mode_is_changeable(t->mode)) { restoreTransObjects(t); resetTransModal(t); resetTransRestrictions(t); @@ -1282,7 +1239,7 @@ int transformEvent(TransInfo *t, const wmEvent *event) } /* only switch when... */ if (!(t->options & CTX_TEXTURE)) { - if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL, TFM_TRANSLATION)) { + if (transform_mode_is_changeable(t->mode)) { restoreTransObjects(t); resetTransModal(t); resetTransRestrictions(t); @@ -1637,6 +1594,17 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op) int proportional = 0; PropertyRNA *prop; + if (!(t->con.mode & CON_APPLY) && (t->flag & T_MODAL) && + ELEM(t->mode, TFM_TRANSLATION, TFM_RESIZE)) { + /* When redoing these modes the first time, it's more convenient to save + * the Global orientation. */ + mul_m3_v3(t->spacemtx, t->values_final); + unit_m3(t->spacemtx); + + BLI_assert(t->orient_curr == 0); + t->orient[0].type = V3D_ORIENT_GLOBAL; + } + // Save back mode in case we're in the generic operator if ((prop = RNA_struct_find_property(op->ptr, "mode"))) { RNA_property_enum_set(op->ptr, prop, t->mode); @@ -1699,18 +1667,6 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op) ts->prop_mode = t->prop_mode; } } - - if (t->spacetype == SPACE_VIEW3D) { - if ((prop = RNA_struct_find_property(op->ptr, "orient_type")) && - !RNA_property_is_set(op->ptr, prop) && - (t->orientation.user != V3D_ORIENT_CUSTOM_MATRIX)) { - TransformOrientationSlot *orient_slot = &t->scene->orientation_slots[SCE_ORIENT_DEFAULT]; - orient_slot->type = t->orientation.user; - BLI_assert(((orient_slot->index_custom == -1) && (t->orientation.custom == NULL)) || - (BKE_scene_transform_orientation_get_index(t->scene, t->orientation.custom) == - orient_slot->index_custom)); - } - } } if (t->flag & T_MODAL) { @@ -1737,34 +1693,6 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op) RNA_property_boolean_set(op->ptr, prop, (t->flag & T_NO_MIRROR) == 0); } - /* Orientation used for redo. */ - const bool use_orient_axis = (t->orient_matrix_is_set && - (RNA_struct_find_property(op->ptr, "orient_axis") != NULL)); - short orientation; - if (t->con.mode & CON_APPLY) { - orientation = t->con.orientation; - if (orientation == V3D_ORIENT_CUSTOM) { - const int orientation_index_custom = BKE_scene_transform_orientation_get_index( - t->scene, t->orientation.custom); - /* Maybe we need a t->con.custom_orientation? - * Seems like it would always match t->orientation.custom. */ - orientation = V3D_ORIENT_CUSTOM + orientation_index_custom; - BLI_assert(orientation >= V3D_ORIENT_CUSTOM); - } - } - else if ((t->orientation.user == V3D_ORIENT_CUSTOM_MATRIX) && - (prop = RNA_struct_find_property(op->ptr, "orient_matrix_type"))) { - orientation = RNA_property_enum_get(op->ptr, prop); - } - else if (use_orient_axis) { - /* We're not using an orientation, use the fallback. */ - orientation = t->orientation.unset; - } - else { - orientation = V3D_ORIENT_GLOBAL; - unit_m3(t->spacemtx); - } - if ((prop = RNA_struct_find_property(op->ptr, "orient_axis"))) { if (t->flag & T_MODAL) { if (t->con.mode & CON_APPLY) { @@ -1784,56 +1712,41 @@ void saveTransform(bContext *C, TransInfo *t, wmOperator *op) } } - if ((prop = RNA_struct_find_property(op->ptr, "orient_matrix"))) { - if (t->flag & T_MODAL) { - if (orientation != V3D_ORIENT_CUSTOM_MATRIX) { - if (t->flag & T_MODAL) { - RNA_enum_set(op->ptr, "orient_matrix_type", orientation); - } - } - if (t->con.mode & CON_APPLY) { - RNA_float_set_array(op->ptr, "orient_matrix", &t->con.mtx[0][0]); - } - else if (use_orient_axis) { - RNA_float_set_array(op->ptr, "orient_matrix", &t->orient_matrix[0][0]); - } - else { - RNA_float_set_array(op->ptr, "orient_matrix", &t->spacemtx[0][0]); - } - } - } - if ((prop = RNA_struct_find_property(op->ptr, "orient_type"))) { - /* constraint orientation can be global, even if user selects something else - * so use the orientation in the constraint if set */ + short orient_type_set, orient_type_curr; + orient_type_set = RNA_property_is_set(op->ptr, prop) ? RNA_property_enum_get(op->ptr, prop) : + -1; + orient_type_curr = t->orient[t->orient_curr].type; - /* Use 'orient_matrix' instead. */ - if (t->flag & T_MODAL) { - if (orientation != V3D_ORIENT_CUSTOM_MATRIX) { - RNA_property_enum_set(op->ptr, prop, orientation); - } + if (!ELEM(orient_type_curr, orient_type_set, V3D_ORIENT_CUSTOM_MATRIX)) { + RNA_property_enum_set(op->ptr, prop, orient_type_curr); + orient_type_set = orient_type_curr; + } + + if (((prop = RNA_struct_find_property(op->ptr, "orient_matrix_type")) && + !RNA_property_is_set(op->ptr, prop))) { + /* Set the first time to register on redo. */ + RNA_property_enum_set(op->ptr, prop, orient_type_set); + RNA_float_set_array(op->ptr, "orient_matrix", &t->spacemtx[0][0]); } } if ((prop = RNA_struct_find_property(op->ptr, "constraint_axis"))) { bool constraint_axis[3] = {false, false, false}; - if (t->flag & T_MODAL) { - /* Only set if needed, so we can hide in the UI when nothing is set. - * See 'transform_poll_property'. */ - if (t->con.mode & CON_APPLY) { - if (t->con.mode & CON_AXIS0) { - constraint_axis[0] = true; - } - if (t->con.mode & CON_AXIS1) { - constraint_axis[1] = true; - } - if (t->con.mode & CON_AXIS2) { - constraint_axis[2] = true; - } + if (t->con.mode & CON_APPLY) { + if (t->con.mode & CON_AXIS0) { + constraint_axis[0] = true; + } + if (t->con.mode & CON_AXIS1) { + constraint_axis[1] = true; } - if (ELEM(true, UNPACK3(constraint_axis))) { - RNA_property_boolean_set_array(op->ptr, prop, constraint_axis); + if (t->con.mode & CON_AXIS2) { + constraint_axis[2] = true; } + RNA_property_boolean_set_array(op->ptr, prop, constraint_axis); + } + else { + RNA_property_unset(op->ptr, prop); } } @@ -1959,7 +1872,10 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve unit_m3(t->spacemtx); initTransInfo(C, t, op, event); - initTransformOrientation(C, t); + + /* Use the custom orientation when it is set. */ + short orient_index = t->orient[0].type == V3D_ORIENT_CUSTOM_MATRIX ? 0 : t->orient_curr; + transform_orientations_current_set(t, orient_index); if (t->spacetype == SPACE_VIEW3D) { t->draw_handle_apply = ED_region_draw_cb_activate( @@ -2084,33 +2000,6 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve calculatePropRatio(t); calculateCenter(t); - /* Overwrite initial values if operator supplied a non-null vector. - * - * Run before init functions so 'values_modal_offset' can be applied on mouse input. - */ - BLI_assert(is_zero_v4(t->values_modal_offset)); - if ((prop = RNA_struct_find_property(op->ptr, "value")) && RNA_property_is_set(op->ptr, prop)) { - float values[4] = {0}; /* in case value isn't length 4, avoid uninitialized memory */ - - if (RNA_property_array_check(prop)) { - RNA_float_get_array(op->ptr, "value", values); - } - else { - values[0] = RNA_float_get(op->ptr, "value"); - } - - copy_v4_v4(t->values, values); - - if (t->flag & T_MODAL) { - copy_v4_v4(t->values_modal_offset, values); - t->redraw = TREDRAW_HARD; - } - else { - copy_v4_v4(t->values, values); - t->flag |= T_INPUT_IS_VALUES_FINAL; - } - } - if (event) { /* Initialize accurate transform to settings requested by keymap. */ bool use_accurate = false; @@ -2141,38 +2030,8 @@ bool initTransform(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve } /* Constraint init from operator */ - if ((t->flag & T_MODAL) || - /* For mirror operator the constraint axes are effectively the values. */ - (RNA_struct_find_property(op->ptr, "value") == NULL)) { - if ((prop = RNA_struct_find_property(op->ptr, "constraint_axis")) && - RNA_property_is_set(op->ptr, prop)) { - bool constraint_axis[3]; - - RNA_property_boolean_get_array(op->ptr, prop, constraint_axis); - - if (constraint_axis[0] || constraint_axis[1] || constraint_axis[2]) { - t->con.mode |= CON_APPLY; - - if (constraint_axis[0]) { - t->con.mode |= CON_AXIS0; - } - if (constraint_axis[1]) { - t->con.mode |= CON_AXIS1; - } - if (constraint_axis[2]) { - t->con.mode |= CON_AXIS2; - } - - setUserConstraint(t, t->orientation.user, t->con.mode, "%s"); - } - } - } - else { - /* So we can adjust in non global orientation. */ - if (t->orientation.user != V3D_ORIENT_GLOBAL) { - t->con.mode |= CON_APPLY | CON_AXIS0 | CON_AXIS1 | CON_AXIS2; - setUserConstraint(t, t->orientation.user, t->con.mode, "%s"); - } + if (t->con.mode & CON_APPLY) { + setUserConstraint(t, t->orient[t->orient_curr].type, t->con.mode, "%s"); } /* Don't write into the values when non-modal because they are already set from operator redo diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index 701e068d3fa..7720660e2e8 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -113,13 +113,8 @@ typedef struct TransSnap { } TransSnap; typedef struct TransCon { - short orientation; /** Description of the constraint for header_print. */ char text[50]; - /** Matrix of the constraint space. */ - float mtx[3][3]; - /** Inverse matrix of the constraint space. */ - float imtx[3][3]; /** Projection constraint matrix (same as #imtx with some axis == 0). */ float pmtx[3][3]; /** Initial mouse value for visual calculation @@ -139,8 +134,7 @@ typedef struct TransCon { struct TransDataContainer *tc, struct TransData *td, const float in[3], - float out[3], - float pvec[3]); + float out[3]); /** Apply function pointer for size transformation. */ void (*applySize)(struct TransInfo *t, struct TransDataContainer *tc, @@ -520,6 +514,7 @@ typedef struct TransInfo { /** orientation matrix of the current space. */ float spacemtx[3][3]; + float spacemtx_inv[3][3]; /** name of the current space, MAX_NAME. */ char spacename[64]; @@ -531,18 +526,11 @@ typedef struct TransInfo { bool is_launch_event_tweak; struct { - /** Orientation type when when we're not constrained. - * nearly always global except for rotate which defaults to screen-space orientation. */ - short unset; - /** Orientation to use when a key is pressed. */ - short user; - /* Used when user is global. */ - short user_alt; - short index; - short *types[2]; - /* this gets used when custom_orientation is V3D_ORIENT_CUSTOM */ - struct TransformOrientation *custom; - } orientation; + short type; + float matrix[3][3]; + } orient[3]; + short orient_curr; + /** backup from view3d, to restore on end. */ short gizmo_flag; @@ -566,15 +554,6 @@ typedef struct TransInfo { /** Secondary axis, shear uses this. */ int orient_axis_ortho; - /** Often this matrix has similar usage to #TransInfo.spacemtx however this - * is used to define extra axes to operate on, not necessarily a space. - * - * For example, by default rotation operates on the view (`orient_matrix[2]`), - * even when the current space isn't set to the view. */ - float orient_matrix[3][3]; - /** Don't overwrite when set by operator redo defines the orientation axis. */ - bool orient_matrix_is_set; - /** remove elements if operator is canceled. */ bool remove_on_cancel; @@ -677,6 +656,10 @@ enum { T_MODAL_CURSOR_SET = 1 << 26, T_CLNOR_REBUILD = 1 << 27, + + /* Special Aftertrans. */ + T_AUTOMERGE = 1 << 28, + T_AUTOSPLIT = 1 << 29, }; /** #TransInfo.modifiers */ @@ -921,8 +904,13 @@ void getViewVector(const TransInfo *t, const float coord[3], float vec[3]); void transform_data_ext_rotate(TransData *td, float mat[3][3], bool use_drot); /*********************** Transform Orientations ******************************/ - -void initTransformOrientation(struct bContext *C, TransInfo *t); +short transform_orientation_matrix_get(struct bContext *C, + TransInfo *t, + const short orientation, + const float custom[3][3], + float r_spacemtx[3][3]); +const char *transform_orientations_spacename_get(TransInfo *t, const short orient_type); +void transform_orientations_current_set(struct TransInfo *t, const short orient_index); /* Those two fill in mat and return non-zero on success */ bool createSpaceNormal(float mat[3][3], const float normal[3]); diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c index cdff9fdf750..0a6e0d6b7f5 100644 --- a/source/blender/editors/transform/transform_constraints.c +++ b/source/blender/editors/transform/transform_constraints.c @@ -42,6 +42,7 @@ #include "BLI_utildefines.h" #include "BKE_context.h" +#include "BKE_scene.h" #include "ED_view3d.h" @@ -57,6 +58,27 @@ static void drawObjectConstraint(TransInfo *t); +static void projection_matrix_calc(const TransInfo *t, float r_pmtx[3][3]) +{ + unit_m3(r_pmtx); + + if (!(t->con.mode & CON_AXIS0)) { + zero_v3(r_pmtx[0]); + } + + if (!(t->con.mode & CON_AXIS1)) { + zero_v3(r_pmtx[1]); + } + + if (!(t->con.mode & CON_AXIS2)) { + zero_v3(r_pmtx[2]); + } + + float mat[3][3]; + mul_m3_m3m3(mat, r_pmtx, t->spacemtx_inv); + mul_m3_m3m3(r_pmtx, t->spacemtx, mat); +} + /* ************************** CONSTRAINTS ************************* */ static void constraintValuesFinal(TransInfo *t, float vec[3]) { @@ -121,11 +143,9 @@ void constraintNumInput(TransInfo *t, float vec[3]) } } -static void postConstraintChecks(TransInfo *t, float vec[3], float pvec[3]) +static void postConstraintChecks(TransInfo *t, float vec[3]) { - int i = 0; - - mul_m3_v3(t->con.imtx, vec); + mul_m3_v3(t->spacemtx_inv, vec); snapGridIncrement(t, vec); @@ -155,17 +175,7 @@ static void postConstraintChecks(TransInfo *t, float vec[3], float pvec[3]) /* inverse transformation at the end */ } - if (t->con.mode & CON_AXIS0) { - pvec[i++] = vec[0]; - } - if (t->con.mode & CON_AXIS1) { - pvec[i++] = vec[1]; - } - if (t->con.mode & CON_AXIS2) { - pvec[i++] = vec[2]; - } - - mul_m3_v3(t->con.mtx, vec); + mul_m3_v3(t->spacemtx, vec); } static void viewAxisCorrectCenter(const TransInfo *t, float t_con_center[3]) @@ -298,7 +308,7 @@ static bool isPlaneProjectionViewAligned(const TransInfo *t) int n = 0; for (int i = 0; i < 3; i++) { if (t->con.mode & (CON_AXIS0 << i)) { - constraint_vector[n++] = t->con.mtx[i]; + constraint_vector[n++] = t->spacemtx[i]; if (n == 2) { break; } @@ -346,12 +356,8 @@ static void planeProjection(const TransInfo *t, const float in[3], float out[3]) * (in perspective mode, the view vector is relative to the position on screen) */ -static void applyAxisConstraintVec(TransInfo *t, - TransDataContainer *UNUSED(tc), - TransData *td, - const float in[3], - float out[3], - float pvec[3]) +static void applyAxisConstraintVec( + TransInfo *t, TransDataContainer *UNUSED(tc), TransData *td, const float in[3], float out[3]) { copy_v3_v3(out, in); if (!td && t->con.mode & CON_APPLY) { @@ -371,25 +377,25 @@ static void applyAxisConstraintVec(TransInfo *t, float c[3]; if (t->con.mode & CON_AXIS0) { - copy_v3_v3(c, t->con.mtx[0]); + copy_v3_v3(c, t->spacemtx[0]); } else if (t->con.mode & CON_AXIS1) { - copy_v3_v3(c, t->con.mtx[1]); + copy_v3_v3(c, t->spacemtx[1]); } else if (t->con.mode & CON_AXIS2) { - copy_v3_v3(c, t->con.mtx[2]); + copy_v3_v3(c, t->spacemtx[2]); } axisProjection(t, c, in, out); } } - postConstraintChecks(t, out, pvec); + postConstraintChecks(t, out); } } /* * Generic callback for object based spatial constraints applied to linear motion * - * At first, the following is applied to the first data in the array + * At first, the following is applied without orientation * The IN vector in projected into the constrained space and then further * projected along the view vector. * (in perspective mode, the view vector is relative to the position on screen) @@ -397,61 +403,19 @@ static void applyAxisConstraintVec(TransInfo *t, * Further down, that vector is mapped to each data's space. */ -static void applyObjectConstraintVec(TransInfo *t, - TransDataContainer *tc, - TransData *td, - const float in[3], - float out[3], - float pvec[3]) +static void applyObjectConstraintVec( + TransInfo *t, TransDataContainer *tc, TransData *td, const float in[3], float out[3]) { - copy_v3_v3(out, in); - if (t->con.mode & CON_APPLY) { - if (!td) { - mul_m3_v3(t->con.pmtx, out); - - const int dims = getConstraintSpaceDimension(t); - if (dims == 2) { - if (!is_zero_v3(out)) { - if (!isPlaneProjectionViewAligned(t)) { - planeProjection(t, in, out); - } - } - } - else if (dims == 1) { - float c[3]; - - if (t->con.mode & CON_AXIS0) { - copy_v3_v3(c, t->con.mtx[0]); - } - else if (t->con.mode & CON_AXIS1) { - copy_v3_v3(c, t->con.mtx[1]); - } - else if (t->con.mode & CON_AXIS2) { - copy_v3_v3(c, t->con.mtx[2]); - } - axisProjection(t, c, in, out); - } - postConstraintChecks(t, out, pvec); - copy_v3_v3(out, pvec); - } - else { - int i = 0; - - out[0] = out[1] = out[2] = 0.0f; - if (t->con.mode & CON_AXIS0) { - out[0] = in[i++]; - } - if (t->con.mode & CON_AXIS1) { - out[1] = in[i++]; - } - if (t->con.mode & CON_AXIS2) { - out[2] = in[i++]; - } - - mul_m3_v3(td->axismtx, out); - if (t->flag & T_EDIT) { - mul_m3_v3(tc->mat3_unit, out); - } + if (!td) { + applyAxisConstraintVec(t, tc, td, in, out); + } + else { + /* Specific TransData's space. */ + copy_v3_v3(out, in); + mul_m3_v3(t->spacemtx_inv, out); + mul_m3_v3(td->axismtx, out); + if (t->flag & T_EDIT) { + mul_m3_v3(tc->mat3_unit, out); } } } @@ -478,8 +442,8 @@ static void applyAxisConstraintSize(TransInfo *t, smat[2][2] = 1.0f; } - mul_m3_m3m3(tmat, smat, t->con.imtx); - mul_m3_m3m3(smat, t->con.mtx, tmat); + mul_m3_m3m3(tmat, smat, t->spacemtx_inv); + mul_m3_m3m3(smat, t->spacemtx, tmat); } } @@ -539,15 +503,15 @@ static void applyAxisConstraintRot( switch (mode) { case CON_AXIS0: case (CON_AXIS1 | CON_AXIS2): - copy_v3_v3(vec, t->con.mtx[0]); + copy_v3_v3(vec, t->spacemtx[0]); break; case CON_AXIS1: case (CON_AXIS0 | CON_AXIS2): - copy_v3_v3(vec, t->con.mtx[1]); + copy_v3_v3(vec, t->spacemtx[1]); break; case CON_AXIS2: case (CON_AXIS0 | CON_AXIS1): - copy_v3_v3(vec, t->con.mtx[2]); + copy_v3_v3(vec, t->spacemtx[2]); break; } /* don't flip axis if asked to or if num input */ @@ -620,12 +584,11 @@ static void applyObjectConstraintRot( /*--------------------- INTERNAL SETUP CALLS ------------------*/ -void setConstraint(TransInfo *t, float space[3][3], int mode, const char text[]) +void setConstraint(TransInfo *t, int mode, const char text[]) { BLI_strncpy(t->con.text + 1, text, sizeof(t->con.text) - 1); - copy_m3_m3(t->con.mtx, space); t->con.mode = mode; - getConstraintMatrix(t); + projection_matrix_calc(t, t->con.pmtx); startConstraint(t); @@ -639,41 +602,25 @@ void setConstraint(TransInfo *t, float space[3][3], int mode, const char text[]) /* applies individual td->axismtx constraints */ void setAxisMatrixConstraint(TransInfo *t, int mode, const char text[]) { - TransDataContainer *tc = t->data_container; - if (t->data_len_all == 1) { - float axismtx[3][3]; - if (t->flag & T_EDIT) { - mul_m3_m3m3(axismtx, tc->mat3_unit, tc->data->axismtx); - } - else { - copy_m3_m3(axismtx, tc->data->axismtx); - } - - setConstraint(t, axismtx, mode, text); - } - else { - BLI_strncpy(t->con.text + 1, text, sizeof(t->con.text) - 1); - copy_m3_m3(t->con.mtx, tc->data->axismtx); - t->con.mode = mode; - getConstraintMatrix(t); + BLI_strncpy(t->con.text + 1, text, sizeof(t->con.text) - 1); + t->con.mode = mode; + projection_matrix_calc(t, t->con.pmtx); - startConstraint(t); + startConstraint(t); - t->con.drawExtra = drawObjectConstraint; - t->con.applyVec = applyObjectConstraintVec; - t->con.applySize = applyObjectConstraintSize; - t->con.applyRot = applyObjectConstraintRot; - t->redraw = TREDRAW_HARD; - } + t->con.drawExtra = drawObjectConstraint; + t->con.applyVec = applyObjectConstraintVec; + t->con.applySize = applyObjectConstraintSize; + t->con.applyRot = applyObjectConstraintRot; + t->redraw = TREDRAW_HARD; } void setLocalConstraint(TransInfo *t, int mode, const char text[]) { - /* edit-mode now allows local transforms too */ if (t->flag & T_EDIT) { - /* Use the active (first) edit object. */ - TransDataContainer *tc = t->data_container; - setConstraint(t, tc->mat3_unit, mode, text); + /* Although in edit-mode each object has its local space, use the + * orientation of the active object. */ + setConstraint(t, mode, text); } else { setAxisMatrixConstraint(t, mode, text); @@ -689,59 +636,30 @@ void setLocalConstraint(TransInfo *t, int mode, const char text[]) void setUserConstraint(TransInfo *t, short orientation, int mode, const char ftext[]) { char text[256]; + const char *spacename = transform_orientations_spacename_get(t, orientation); + BLI_snprintf(text, sizeof(text), ftext, spacename); switch (orientation) { - case V3D_ORIENT_GLOBAL: { - float mtx[3][3]; - BLI_snprintf(text, sizeof(text), ftext, TIP_("global")); - unit_m3(mtx); - setConstraint(t, mtx, mode, text); - break; - } case V3D_ORIENT_LOCAL: - BLI_snprintf(text, sizeof(text), ftext, TIP_("local")); setLocalConstraint(t, mode, text); break; case V3D_ORIENT_NORMAL: - BLI_snprintf(text, sizeof(text), ftext, TIP_("normal")); if (checkUseAxisMatrix(t)) { setAxisMatrixConstraint(t, mode, text); + break; } - else { - setConstraint(t, t->spacemtx, mode, text); - } - break; + ATTR_FALLTHROUGH; + case V3D_ORIENT_GLOBAL: case V3D_ORIENT_VIEW: - BLI_snprintf(text, sizeof(text), ftext, TIP_("view")); - setConstraint(t, t->spacemtx, mode, text); - break; case V3D_ORIENT_CURSOR: - BLI_snprintf(text, sizeof(text), ftext, TIP_("cursor")); - setConstraint(t, t->spacemtx, mode, text); - break; case V3D_ORIENT_GIMBAL: - BLI_snprintf(text, sizeof(text), ftext, TIP_("gimbal")); - setConstraint(t, t->spacemtx, mode, text); - break; case V3D_ORIENT_CUSTOM_MATRIX: - BLI_snprintf(text, sizeof(text), ftext, TIP_("custom matrix")); - setConstraint(t, t->spacemtx, mode, text); - break; - case V3D_ORIENT_CUSTOM: { - char orientation_str[128]; - BLI_snprintf(orientation_str, - sizeof(orientation_str), - "%s \"%s\"", - TIP_("custom orientation"), - t->orientation.custom->name); - BLI_snprintf(text, sizeof(text), ftext, orientation_str); - setConstraint(t, t->spacemtx, mode, text); + case V3D_ORIENT_CUSTOM: + default: { + setConstraint(t, mode, text); break; } } - - t->con.orientation = orientation; - t->con.mode |= CON_USER; } @@ -772,9 +690,9 @@ void drawConstraint(TransInfo *t) convertViewVec(t, vec, (t->mval[0] - t->con.imval[0]), (t->mval[1] - t->con.imval[1])); add_v3_v3(vec, t->center_global); - drawLine(t, t->center_global, tc->mtx[0], 'X', 0); - drawLine(t, t->center_global, tc->mtx[1], 'Y', 0); - drawLine(t, t->center_global, tc->mtx[2], 'Z', 0); + drawLine(t, t->center_global, t->spacemtx[0], 'X', 0); + drawLine(t, t->center_global, t->spacemtx[1], 'Y', 0); + drawLine(t, t->center_global, t->spacemtx[2], 'Z', 0); depth_test_enabled = GPU_depth_test_enabled(); if (depth_test_enabled) { @@ -808,13 +726,13 @@ void drawConstraint(TransInfo *t) } if (tc->mode & CON_AXIS0) { - drawLine(t, t->center_global, tc->mtx[0], 'X', DRAWLIGHT); + drawLine(t, t->center_global, t->spacemtx[0], 'X', DRAWLIGHT); } if (tc->mode & CON_AXIS1) { - drawLine(t, t->center_global, tc->mtx[1], 'Y', DRAWLIGHT); + drawLine(t, t->center_global, t->spacemtx[1], 'Y', DRAWLIGHT); } if (tc->mode & CON_AXIS2) { - drawLine(t, t->center_global, tc->mtx[2], 'Z', DRAWLIGHT); + drawLine(t, t->center_global, t->spacemtx[2], 'Z', DRAWLIGHT); } } } @@ -960,41 +878,24 @@ void stopConstraint(TransInfo *t) t->num.idx_max = t->idx_max; } -void getConstraintMatrix(TransInfo *t) -{ - float mat[3][3]; - invert_m3_m3(t->con.imtx, t->con.mtx); - unit_m3(t->con.pmtx); - - if (!(t->con.mode & CON_AXIS0)) { - zero_v3(t->con.pmtx[0]); - } - - if (!(t->con.mode & CON_AXIS1)) { - zero_v3(t->con.pmtx[1]); - } - - if (!(t->con.mode & CON_AXIS2)) { - zero_v3(t->con.pmtx[2]); - } - - mul_m3_m3m3(mat, t->con.pmtx, t->con.imtx); - mul_m3_m3m3(t->con.pmtx, t->con.mtx, mat); -} - /*------------------------- MMB Select -------------------------------*/ -void initSelectConstraint(TransInfo *t, float mtx[3][3]) +void initSelectConstraint(TransInfo *t, bool force_global) { - copy_m3_m3(t->con.mtx, mtx); - t->con.mode |= CON_APPLY; - t->con.mode |= CON_SELECT; + short orientation; + if (force_global) { + orientation = V3D_ORIENT_GLOBAL; + } + else { + if (t->orient_curr == 0) { + t->orient_curr = 1; + transform_orientations_current_set(t, t->orient_curr); + } + orientation = t->orient[t->orient_curr].type; + } + setUserConstraint(t, orientation, CON_APPLY | CON_SELECT, ""); setNearestAxis(t); - t->con.drawExtra = NULL; - t->con.applyVec = applyAxisConstraintVec; - t->con.applySize = applyAxisConstraintSize; - t->con.applyRot = applyAxisConstraintRot; } void selectConstraint(TransInfo *t) @@ -1060,7 +961,7 @@ static void setNearestAxis3d(TransInfo *t) for (i = 0; i < 3; i++) { float axis[3], axis_2d[2]; - copy_v3_v3(axis, t->con.mtx[i]); + copy_v3_v3(axis, t->spacemtx[i]); mul_v3_fl(axis, zfac); /* now we can project to get window coordinate */ @@ -1129,7 +1030,7 @@ void setNearestAxis(TransInfo *t) setNearestAxis2d(t); } - getConstraintMatrix(t); + projection_matrix_calc(t, t->con.pmtx); } /*-------------- HELPER FUNCTIONS ----------------*/ diff --git a/source/blender/editors/transform/transform_constraints.h b/source/blender/editors/transform/transform_constraints.h index 8938ca93ad8..b57a7599321 100644 --- a/source/blender/editors/transform/transform_constraints.h +++ b/source/blender/editors/transform/transform_constraints.h @@ -27,7 +27,7 @@ struct TransInfo; void constraintNumInput(TransInfo *t, float vec[3]); -void setConstraint(TransInfo *t, float space[3][3], int mode, const char text[]); +void setConstraint(TransInfo *t, int mode, const char text[]); void setAxisMatrixConstraint(TransInfo *t, int mode, const char text[]); void setLocalConstraint(TransInfo *t, int mode, const char text[]); void setUserConstraint(TransInfo *t, short orientation, int mode, const char text[]); @@ -35,8 +35,7 @@ void drawConstraint(TransInfo *t); void drawPropCircle(const struct bContext *C, TransInfo *t); void startConstraint(TransInfo *t); void stopConstraint(TransInfo *t); -void getConstraintMatrix(TransInfo *t); -void initSelectConstraint(TransInfo *t, float mtx[3][3]); +void initSelectConstraint(TransInfo *t, bool force_global); void selectConstraint(TransInfo *t); void postSelectConstraint(TransInfo *t); void setNearestAxis(TransInfo *t); diff --git a/source/blender/editors/transform/transform_convert.c b/source/blender/editors/transform/transform_convert.c index ed7b6e4ba48..b91542a80fc 100644 --- a/source/blender/editors/transform/transform_convert.c +++ b/source/blender/editors/transform/transform_convert.c @@ -476,12 +476,12 @@ static void bone_children_clear_transflag(int mode, short around, ListBase *lb) } } -/* sets transform flags in the bones - * returns total number of bones with BONE_TRANSFORM */ -int count_set_pose_transflags(Object *ob, - const int mode, - const short around, - bool has_translate_rotate[2]) +/* Sets transform flags in the bones. + * Returns total number of bones with `BONE_TRANSFORM`. */ +int transform_convert_pose_transflags_update(Object *ob, + const int mode, + const short around, + bool has_translate_rotate[2]) { bArmature *arm = ob->data; bPoseChannel *pchan; @@ -1879,8 +1879,8 @@ static void special_aftertrans_update__node(bContext *C, TransInfo *t) static void special_aftertrans_update__mesh(bContext *UNUSED(C), TransInfo *t) { - /* so automerge supports mirror */ - if ((t->scene->toolsettings->automerge) && ((t->flag & T_EDIT) && t->obedit_type == OB_MESH)) { + bool use_automerge = (t->flag & (T_AUTOMERGE | T_AUTOSPLIT)) != 0; + if (use_automerge && ((t->flag & T_EDIT) && t->obedit_type == OB_MESH)) { FOREACH_TRANS_DATA_CONTAINER (t, tc) { BMEditMesh *em = BKE_editmesh_from_object(tc->obedit); @@ -1906,14 +1906,12 @@ static void special_aftertrans_update__mesh(bContext *UNUSED(C), TransInfo *t) hflag = BM_ELEM_SELECT; } - if (t->scene->toolsettings->automerge & AUTO_MERGE) { - if (t->scene->toolsettings->automerge & AUTO_MERGE_AND_SPLIT) { - EDBM_automerge_and_split( - tc->obedit, true, true, true, hflag, t->scene->toolsettings->doublimit); - } - else { - EDBM_automerge(tc->obedit, true, hflag, t->scene->toolsettings->doublimit); - } + if (t->flag & T_AUTOSPLIT) { + EDBM_automerge_and_split( + tc->obedit, true, true, true, hflag, t->scene->toolsettings->doublimit); + } + else { + EDBM_automerge(tc->obedit, true, hflag, t->scene->toolsettings->doublimit); } /* Special case, this is needed or faces won't re-select. @@ -2321,7 +2319,7 @@ void special_aftertrans_update(bContext *C, TransInfo *t) /* set BONE_TRANSFORM flags for autokey, gizmo draw might have changed them */ if (!canceled && (t->mode != TFM_DUMMY)) { - count_set_pose_transflags(ob, t->mode, t->around, NULL); + transform_convert_pose_transflags_update(ob, t->mode, t->around, NULL); } /* if target-less IK grabbing, we calculate the pchan transforms and clear flag */ @@ -2776,7 +2774,7 @@ void createTransData(bContext *C, TransInfo *t) /* important that ob_armature can be set even when its not selected [#23412] * lines below just check is also visible */ has_transform_context = false; - Object *ob_armature = modifiers_isDeformedByArmature(ob); + Object *ob_armature = BKE_modifiers_is_deformed_by_armature(ob); if (ob_armature && ob_armature->mode & OB_MODE_POSE) { Base *base_arm = BKE_view_layer_base_find(t->view_layer, ob_armature); if (base_arm) { diff --git a/source/blender/editors/transform/transform_convert.h b/source/blender/editors/transform/transform_convert.h index d4139898419..e5d758135e2 100644 --- a/source/blender/editors/transform/transform_convert.h +++ b/source/blender/editors/transform/transform_convert.h @@ -37,10 +37,10 @@ struct bKinematicConstraint; struct bPoseChannel; /* transform_convert.c */ -int count_set_pose_transflags(Object *ob, - const int mode, - const short around, - bool has_translate_rotate[2]); +int transform_convert_pose_transflags_update(Object *ob, + const int mode, + const short around, + bool has_translate_rotate[2]); void transform_autoik_update(TransInfo *t, short mode); void autokeyframe_object(struct bContext *C, struct Scene *scene, diff --git a/source/blender/editors/transform/transform_convert_armature.c b/source/blender/editors/transform/transform_convert_armature.c index 779257ef671..35bb7e3f0d8 100644 --- a/source/blender/editors/transform/transform_convert_armature.c +++ b/source/blender/editors/transform/transform_convert_armature.c @@ -609,9 +609,9 @@ void pose_transform_mirror_update(TransInfo *t, TransDataContainer *tc, Object * /* TODO(germano): Realitve Mirror support */ } data->flag |= CONSTRAINT_IK_AUTO; - /* Add a temporary auto IK constraint here, as we will only temporarly active this targetless - * bone during transform. (Targetless IK constraints are treated as if they are disabled - * unless they are transformed) */ + /* Add a temporary auto IK constraint here, as we will only temporarily active this + * target-less bone during transform. (Target-less IK constraints are treated as if they are + * disabled unless they are transformed) */ add_temporary_ik_constraint(pchan, data); Main *bmain = CTX_data_main(t->context); update_deg_with_temporary_ik(bmain, ob); @@ -669,7 +669,9 @@ void createTransPose(TransInfo *t) const bool mirror = ((pose->flag & POSE_MIRROR_EDIT) != 0); /* set flags and count total */ - tc->data_len = count_set_pose_transflags(ob, t->mode, t->around, has_translate_rotate); + tc->data_len = transform_convert_pose_transflags_update( + ob, t->mode, t->around, has_translate_rotate); + if (tc->data_len == 0) { continue; } diff --git a/source/blender/editors/transform/transform_convert_mesh.c b/source/blender/editors/transform/transform_convert_mesh.c index 2bb5b25c949..07b2f07bf2c 100644 --- a/source/blender/editors/transform/transform_convert_mesh.c +++ b/source/blender/editors/transform/transform_convert_mesh.c @@ -781,9 +781,9 @@ void createTransEditVerts(TransInfo *t) } /* detect CrazySpace [tm] */ - if (modifiers_getCageIndex(t->scene, tc->obedit, NULL, 1) != -1) { + if (BKE_modifiers_get_cage_index(t->scene, tc->obedit, NULL, 1) != -1) { int totleft = -1; - if (modifiers_isCorrectableDeformed(t->scene, tc->obedit)) { + if (BKE_modifiers_is_correctable_deformed(t->scene, tc->obedit)) { BKE_scene_graph_evaluated_ensure(t->depsgraph, CTX_data_main(t->context)); /* Use evaluated state because we need b-bone cache. */ diff --git a/source/blender/editors/transform/transform_convert_object.c b/source/blender/editors/transform/transform_convert_object.c index 9b76db7f265..8deba0f7ad0 100644 --- a/source/blender/editors/transform/transform_convert_object.c +++ b/source/blender/editors/transform/transform_convert_object.c @@ -197,7 +197,7 @@ static void ObjectToTransData(TransInfo *t, TransData *td, Object *ob) /* NOTE: This is not really following copy-on-write design and we should not * be re-evaluating the evaluated object. But as the comment above mentioned * this is part of a hack. - * More proper solution would be to make a shallow copy of the object and + * More proper solution would be to make a shallow copy of the object and * evaluate that, and access matrix of that evaluated copy of the object. * Might be more tricky than it sounds, if some logic later on accesses the * object matrix via td->ob->obmat. */ diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index 05318a5c1d3..069e49088de 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -1187,7 +1187,6 @@ void recalcData(TransInfo *t) flushTransPaintCurve(t); } else if (t->options & CTX_GPENCIL_STROKES) { - /* set recalc triangle cache flag */ recalcData_gpencil_strokes(t); } else if (t->options & CTX_SCULPT) { @@ -1431,11 +1430,6 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve unit_m3(t->mat); - unit_m3(t->orient_matrix); - negate_m3(t->orient_matrix); - /* Leave 't->orient_matrix_is_set' to false, - * so we overwrite it when we have a useful value. */ - /* Default to rotate on the Z axis. */ t->orient_axis = 2; t->orient_axis_ortho = 1; @@ -1513,22 +1507,6 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve t->around = V3D_AROUND_CURSOR; } - TransformOrientationSlot *orient_slot = &t->scene->orientation_slots[SCE_ORIENT_DEFAULT]; - t->orientation.unset = V3D_ORIENT_GLOBAL; - t->orientation.user = orient_slot->type; - t->orientation.custom = BKE_scene_transform_orientation_find(t->scene, - orient_slot->index_custom); - - t->orientation.index = 0; - ARRAY_SET_ITEMS(t->orientation.types, &t->orientation.user, NULL); - - /* Make second orientation local if both are global. */ - if (t->orientation.user == V3D_ORIENT_GLOBAL) { - t->orientation.user_alt = V3D_ORIENT_LOCAL; - t->orientation.types[0] = &t->orientation.user_alt; - SWAP(short *, t->orientation.types[0], t->orientation.types[1]); - } - /* exceptional case */ if (t->around == V3D_AROUND_LOCAL_ORIGINS) { if (ELEM(t->mode, TFM_ROTATION, TFM_RESIZE, TFM_TRACKBALL)) { @@ -1617,48 +1595,148 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve t->around = V3D_AROUND_CENTER_BOUNDS; } - if (op && (prop = RNA_struct_find_property(op->ptr, "orient_axis"))) { - t->orient_axis = RNA_property_enum_get(op->ptr, prop); - } - if (op && (prop = RNA_struct_find_property(op->ptr, "orient_axis_ortho"))) { - t->orient_axis_ortho = RNA_property_enum_get(op->ptr, prop); - } + BLI_assert(is_zero_v4(t->values_modal_offset)); + bool t_values_set_is_array = false; + if (op && (prop = RNA_struct_find_property(op->ptr, "value")) && + RNA_property_is_set(op->ptr, prop)) { + float values[4] = {0}; /* in case value isn't length 4, avoid uninitialized memory */ + if (RNA_property_array_check(prop)) { + RNA_float_get_array(op->ptr, "value", values); + t_values_set_is_array = true; + } + else { + values[0] = RNA_float_get(op->ptr, "value"); + } - if (op && - ((prop = RNA_struct_find_property(op->ptr, "orient_matrix")) && - RNA_property_is_set(op->ptr, prop)) && - ((t->flag & T_MODAL) || - /* When using redo, don't use the custom constraint matrix - * if the user selects a different orientation. */ - (RNA_enum_get(op->ptr, "orient_type") == RNA_enum_get(op->ptr, "orient_matrix_type")))) { - RNA_property_float_get_array(op->ptr, prop, &t->orient_matrix[0][0]); - copy_m3_m3(t->spacemtx, t->orient_matrix); - /* Some transform modes use this to operate on an axis. */ - t->orient_matrix_is_set = true; - t->orientation.user = V3D_ORIENT_CUSTOM_MATRIX; - t->orientation.custom = 0; + copy_v4_v4(t->values, values); if (t->flag & T_MODAL) { - RNA_enum_set(op->ptr, "orient_matrix_type", RNA_enum_get(op->ptr, "orient_type")); + /* Run before init functions so 'values_modal_offset' can be applied on mouse input. */ + copy_v4_v4(t->values_modal_offset, values); + } + else { + copy_v4_v4(t->values, values); + t->flag |= T_INPUT_IS_VALUES_FINAL; + } + } + + if (op && (prop = RNA_struct_find_property(op->ptr, "constraint_axis"))) { + bool constraint_axis[3] = {false, false, false}; + if (RNA_property_is_set(op->ptr, prop)) { + RNA_property_boolean_get_array(op->ptr, prop, constraint_axis); + } + + if (t_values_set_is_array && t->flag & T_INPUT_IS_VALUES_FINAL) { + /* For operators whose `t->values` is array, set contrain so that the + * orientation is more intuitive in the Redo Panel. */ + for (int i = 3; i--;) { + constraint_axis[i] |= t->values[i] != 0.0f; + } + } + + if (constraint_axis[0] || constraint_axis[1] || constraint_axis[2]) { + t->con.mode |= CON_APPLY; + + if (constraint_axis[0]) { + t->con.mode |= CON_AXIS0; + } + if (constraint_axis[1]) { + t->con.mode |= CON_AXIS1; + } + if (constraint_axis[2]) { + t->con.mode |= CON_AXIS2; + } } } - else if (op && ((prop = RNA_struct_find_property(op->ptr, "orient_type")) && - RNA_property_is_set(op->ptr, prop))) { - short orientation = RNA_property_enum_get(op->ptr, prop); - TransformOrientation *custom_orientation = NULL; - if (orientation >= V3D_ORIENT_CUSTOM) { - if (orientation >= V3D_ORIENT_CUSTOM + BIF_countTransformOrientation(C)) { - orientation = V3D_ORIENT_GLOBAL; + { + TransformOrientationSlot *orient_slot = &t->scene->orientation_slots[SCE_ORIENT_DEFAULT]; + short orient_type_set = -1; + short orient_type_matrix_set = -1; + short orient_type_scene = orient_slot->type; + if (orient_type_scene == V3D_ORIENT_CUSTOM) { + const int index_custom = orient_slot->index_custom; + orient_type_scene += index_custom; + } + + short orient_types[3]; + float custom_matrix[3][3]; + bool use_orient_axis = false; + + if (op && (prop = RNA_struct_find_property(op->ptr, "orient_axis"))) { + t->orient_axis = RNA_property_enum_get(op->ptr, prop); + use_orient_axis = true; + } + if (op && (prop = RNA_struct_find_property(op->ptr, "orient_axis_ortho"))) { + t->orient_axis_ortho = RNA_property_enum_get(op->ptr, prop); + } + + if (op && ((prop = RNA_struct_find_property(op->ptr, "orient_type")) && + RNA_property_is_set(op->ptr, prop))) { + orient_type_set = RNA_property_enum_get(op->ptr, prop); + if (orient_type_set >= V3D_ORIENT_CUSTOM) { + if (orient_type_set >= V3D_ORIENT_CUSTOM + BIF_countTransformOrientation(C)) { + orient_type_set = V3D_ORIENT_GLOBAL; + } + } + + /* Change the default orientation to be used when redoing. */ + orient_types[0] = orient_type_set; + orient_types[1] = orient_type_set; + orient_types[2] = orient_type_scene; + } + else { + if ((t->flag & T_MODAL) && (use_orient_axis || transform_mode_is_changeable(t->mode))) { + orient_types[0] = V3D_ORIENT_VIEW; } else { - custom_orientation = BKE_scene_transform_orientation_find(t->scene, - orientation - V3D_ORIENT_CUSTOM); - orientation = V3D_ORIENT_CUSTOM; + orient_types[0] = orient_type_scene; + } + orient_types[1] = orient_type_scene; + orient_types[2] = orient_type_scene != V3D_ORIENT_GLOBAL ? V3D_ORIENT_GLOBAL : + V3D_ORIENT_LOCAL; + } + + if (op && ((prop = RNA_struct_find_property(op->ptr, "orient_matrix")) && + RNA_property_is_set(op->ptr, prop))) { + RNA_property_float_get_array(op->ptr, prop, &custom_matrix[0][0]); + + if ((prop = RNA_struct_find_property(op->ptr, "orient_matrix_type")) && + RNA_property_is_set(op->ptr, prop)) { + orient_type_matrix_set = RNA_property_enum_get(op->ptr, prop); + } + else if (orient_type_set != -1) { + orient_type_matrix_set = orient_type_set; + } + else { + orient_type_matrix_set = orient_type_set = V3D_ORIENT_GLOBAL; + } + + if (orient_type_matrix_set == orient_type_set) { + /* Constraints are forced to use the custom matrix when redoing. */ + orient_types[0] = V3D_ORIENT_CUSTOM_MATRIX; } } - t->orientation.user = orientation; - t->orientation.custom = custom_orientation; + if (t->con.mode & CON_APPLY) { + t->orient_curr = 1; + } + + /* For efficiency, avoid calculating the same orientation twice. */ + for (int i = 1; i < 3; i++) { + t->orient[i].type = transform_orientation_matrix_get( + C, t, orient_types[i], custom_matrix, t->orient[i].matrix); + } + + if (orient_types[0] != orient_types[1]) { + t->orient[0].type = transform_orientation_matrix_get( + C, t, orient_types[0], custom_matrix, t->orient[0].matrix); + } + else { + memcpy(&t->orient[0], &t->orient[1], sizeof(t->orient[0])); + } + + const char *spacename = transform_orientations_spacename_get(t, orient_types[0]); + BLI_strncpy(t->spacename, spacename, sizeof(t->spacename)); } if (op && ((prop = RNA_struct_find_property(op->ptr, "release_confirm")) && @@ -1763,6 +1841,24 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve t->options |= CTX_NO_PET; } + if (t->obedit_type == OB_MESH) { + if (op && (prop = RNA_struct_find_property(op->ptr, "use_automerge_and_split")) && + RNA_property_is_set(op->ptr, prop)) { + if (RNA_property_boolean_get(op->ptr, prop)) { + t->flag |= T_AUTOMERGE | T_AUTOSPLIT; + } + } + else { + char automerge = t->scene->toolsettings->automerge; + if (automerge & AUTO_MERGE) { + t->flag |= T_AUTOMERGE; + if (automerge & AUTO_MERGE_AND_SPLIT) { + t->flag |= T_AUTOSPLIT; + } + } + } + } + // Mirror is not supported with PET, turn it off. #if 0 if (t->flag & T_PROP_EDIT) { diff --git a/source/blender/editors/transform/transform_gizmo_3d.c b/source/blender/editors/transform/transform_gizmo_3d.c index d7461e1de0c..ddeba206e4a 100644 --- a/source/blender/editors/transform/transform_gizmo_3d.c +++ b/source/blender/editors/transform/transform_gizmo_3d.c @@ -713,7 +713,9 @@ void ED_transform_calc_orientation_from_type_ex(const bContext *C, ok = true; break; } - case V3D_ORIENT_CUSTOM: { + case V3D_ORIENT_CUSTOM: + default: { + BLI_assert(orientation_type >= V3D_ORIENT_CUSTOM); TransformOrientation *custom_orientation = BKE_scene_transform_orientation_find( scene, orientation_index_custom); if (applyTransformOrientation(custom_orientation, r_mat, NULL)) { @@ -1033,7 +1035,7 @@ int ED_transform_calc_gizmo_stats(const bContext *C, /* mislead counting bones... bah. We don't know the gizmo mode, could be mixed */ const int mode = TFM_ROTATION; - const int totsel_iter = count_set_pose_transflags( + const int totsel_iter = transform_convert_pose_transflags_update( ob_iter, mode, V3D_AROUND_CENTER_BOUNDS, NULL); if (totsel_iter) { @@ -1388,21 +1390,21 @@ void drawDial3d(const TransInfo *t) if (tc->mode & CON_APPLY) { if (tc->mode & CON_AXIS0) { axis_idx = MAN_AXIS_ROT_X; - negate_v3_v3(mat_basis[2], tc->mtx[0]); + negate_v3_v3(mat_basis[2], t->spacemtx[0]); } else if (tc->mode & CON_AXIS1) { axis_idx = MAN_AXIS_ROT_Y; - negate_v3_v3(mat_basis[2], tc->mtx[1]); + negate_v3_v3(mat_basis[2], t->spacemtx[1]); } else { BLI_assert((tc->mode & CON_AXIS2) != 0); axis_idx = MAN_AXIS_ROT_Z; - negate_v3_v3(mat_basis[2], tc->mtx[2]); + negate_v3_v3(mat_basis[2], t->spacemtx[2]); } } else { axis_idx = MAN_AXIS_ROT_C; - negate_v3_v3(mat_basis[2], t->orient_matrix[t->orient_axis]); + copy_v3_v3(mat_basis[2], t->spacemtx[t->orient_axis]); scale *= 1.2f; line_with -= 1.0f; } diff --git a/source/blender/editors/transform/transform_mode.c b/source/blender/editors/transform/transform_mode.c index a2b3a891031..c2c880b03ff 100644 --- a/source/blender/editors/transform/transform_mode.c +++ b/source/blender/editors/transform/transform_mode.c @@ -61,6 +61,18 @@ bool transdata_check_local_center(TransInfo *t, short around) (t->options & (CTX_MOVIECLIP | CTX_MASK | CTX_PAINT_CURVE)))); } +/* Informs if the mode can be switched during modal. */ +bool transform_mode_is_changeable(const int mode) +{ + return ELEM(mode, + TFM_ROTATION, + TFM_RESIZE, + TFM_TRACKBALL, + TFM_TRANSLATION, + TFM_EDGE_SLIDE, + TFM_VERT_SLIDE); +} + /* -------------------------------------------------------------------- */ /** \name Transform Locks * \{ */ @@ -529,7 +541,7 @@ void headerRotation(TransInfo *t, char str[UI_MAX_DRAW_STR], float final) void postInputRotation(TransInfo *t, float values[3]) { float axis_final[3]; - copy_v3_v3(axis_final, t->orient_matrix[t->orient_axis]); + copy_v3_v3(axis_final, t->spacemtx[t->orient_axis]); if ((t->con.mode & CON_APPLY) && t->con.applyRot) { t->con.applyRot(t, NULL, NULL, axis_final, values); } diff --git a/source/blender/editors/transform/transform_mode.h b/source/blender/editors/transform/transform_mode.h index 6180f6d3477..074e89390c2 100644 --- a/source/blender/editors/transform/transform_mode.h +++ b/source/blender/editors/transform/transform_mode.h @@ -41,6 +41,7 @@ typedef struct TransDataGenericSlideVert { /* transform_mode.c */ bool transdata_check_local_center(TransInfo *t, short around); +bool transform_mode_is_changeable(const int mode); void protectedTransBits(short protectflag, float vec[3]); void constraintTransLim(TransInfo *t, TransData *td); void postInputRotation(TransInfo *t, float values[3]); diff --git a/source/blender/editors/transform/transform_mode_edge_rotate_normal.c b/source/blender/editors/transform/transform_mode_edge_rotate_normal.c index 18149a09f20..fde0d5b187e 100644 --- a/source/blender/editors/transform/transform_mode_edge_rotate_normal.c +++ b/source/blender/editors/transform/transform_mode_edge_rotate_normal.c @@ -81,7 +81,7 @@ static void applyNormalRotation(TransInfo *t, const int UNUSED(mval[2])) char str[UI_MAX_DRAW_STR]; float axis_final[3]; - copy_v3_v3(axis_final, t->orient_matrix[t->orient_axis]); + copy_v3_v3(axis_final, t->spacemtx[t->orient_axis]); if ((t->con.mode & CON_APPLY) && t->con.applyRot) { t->con.applyRot(t, NULL, NULL, axis_final, NULL); diff --git a/source/blender/editors/transform/transform_mode_edge_seq_slide.c b/source/blender/editors/transform/transform_mode_edge_seq_slide.c index ee91459dcdd..8690cd54a3b 100644 --- a/source/blender/editors/transform/transform_mode_edge_seq_slide.c +++ b/source/blender/editors/transform/transform_mode_edge_seq_slide.c @@ -101,9 +101,8 @@ static void applySeqSlide(TransInfo *t, const int mval[2]) snapSequenceBounds(t, mval); if (t->con.mode & CON_APPLY) { - float pvec[3] = {0.0f, 0.0f, 0.0f}; float tvec[3]; - t->con.applyVec(t, NULL, NULL, t->values, tvec, pvec); + t->con.applyVec(t, NULL, NULL, t->values, tvec); copy_v3_v3(t->values_final, tvec); } else { diff --git a/source/blender/editors/transform/transform_mode_rotate.c b/source/blender/editors/transform/transform_mode_rotate.c index 6c2b3dc77d2..55c97630487 100644 --- a/source/blender/editors/transform/transform_mode_rotate.c +++ b/source/blender/editors/transform/transform_mode_rotate.c @@ -146,7 +146,8 @@ static void applyRotation(TransInfo *t, const int UNUSED(mval[2])) snapGridIncrement(t, &final); float axis_final[3]; - copy_v3_v3(axis_final, t->orient_matrix[t->orient_axis]); + /* Use the negative axis to match the default Z axis of the view matrix. */ + negate_v3_v3(axis_final, t->spacemtx[t->orient_axis]); if ((t->con.mode & CON_APPLY) && t->con.applyRot) { t->con.applyRot(t, NULL, NULL, axis_final, NULL); diff --git a/source/blender/editors/transform/transform_mode_shear.c b/source/blender/editors/transform/transform_mode_shear.c index ba79f5f3c7b..3eeb8a1e758 100644 --- a/source/blender/editors/transform/transform_mode_shear.c +++ b/source/blender/editors/transform/transform_mode_shear.c @@ -53,10 +53,10 @@ static void initShear_mouseInputMode(TransInfo *t) { float dir[3]; bool dir_flip = false; - copy_v3_v3(dir, t->orient_matrix[t->orient_axis_ortho]); + copy_v3_v3(dir, t->spacemtx[t->orient_axis_ortho]); /* Needed for axis aligned view gizmo. */ - if (t->orientation.user == V3D_ORIENT_VIEW) { + if (t->orient[t->orient_curr].type == V3D_ORIENT_VIEW) { if (t->orient_axis_ortho == 0) { if (t->center2d[1] > t->mouse.imval[1]) { dir_flip = !dir_flip; @@ -154,8 +154,8 @@ static void applyShear(TransInfo *t, const int UNUSED(mval[2])) unit_m3(smat); smat[1][0] = value; - copy_v3_v3(axismat_inv[0], t->orient_matrix[t->orient_axis_ortho]); - copy_v3_v3(axismat_inv[2], t->orient_matrix[t->orient_axis]); + copy_v3_v3(axismat_inv[0], t->spacemtx[t->orient_axis_ortho]); + copy_v3_v3(axismat_inv[2], t->spacemtx[t->orient_axis]); cross_v3_v3v3(axismat_inv[1], axismat_inv[0], axismat_inv[2]); invert_m3_m3(axismat, axismat_inv); diff --git a/source/blender/editors/transform/transform_mode_translate.c b/source/blender/editors/transform/transform_mode_translate.c index 0a7d8bd90d3..69552eda5bf 100644 --- a/source/blender/editors/transform/transform_mode_translate.c +++ b/source/blender/editors/transform/transform_mode_translate.c @@ -277,8 +277,7 @@ static void applyTranslationValue(TransInfo *t, const float vec[3]) } if (t->con.applyVec) { - float pvec[3]; - t->con.applyVec(t, tc, td, vec, tvec, pvec); + t->con.applyVec(t, tc, td, vec, tvec); } else { copy_v3_v3(tvec, vec); @@ -319,45 +318,39 @@ static void applyTranslationValue(TransInfo *t, const float vec[3]) static void applyTranslation(TransInfo *t, const int UNUSED(mval[2])) { char str[UI_MAX_DRAW_STR]; - float values_final[3]; + float global_dir[3]; if (t->flag & T_INPUT_IS_VALUES_FINAL) { - copy_v3_v3(t->values_final, t->values); + mul_v3_m3v3(global_dir, t->spacemtx, t->values); } else { - copy_v3_v3(t->values_final, t->values); + copy_v3_v3(global_dir, t->values); if ((t->con.mode & CON_APPLY) == 0) { - snapGridIncrement(t, t->values_final); + snapGridIncrement(t, global_dir); } - if (applyNumInput(&t->num, t->values_final)) { - removeAspectRatio(t, t->values_final); + if (applyNumInput(&t->num, global_dir)) { + removeAspectRatio(t, global_dir); } - applySnapping(t, t->values_final); + applySnapping(t, global_dir); } - copy_v3_v3(values_final, t->values_final); if (t->con.mode & CON_APPLY) { - float pvec[3] = {0.0f, 0.0f, 0.0f}; - t->con.applyVec(t, NULL, NULL, t->values_final, values_final, pvec); - headerTranslation(t, pvec, str); - - /* only so we have re-usable value with redo, see T46741. */ - mul_v3_m3v3(t->values_final, t->con.imtx, values_final); + float in[3]; + copy_v3_v3(in, global_dir); + t->con.applyVec(t, NULL, NULL, in, global_dir); + headerTranslation(t, global_dir, str); } else { - headerTranslation(t, t->values_final, str); - copy_v3_v3(values_final, t->values_final); + headerTranslation(t, global_dir, str); } - /* don't use 't->values' now on */ - - applyTranslationValue(t, values_final); + applyTranslationValue(t, global_dir); /* evil hack - redo translation if clipping needed */ - if (t->flag & T_CLIP_UV && clipUVTransform(t, values_final, 0)) { - applyTranslationValue(t, values_final); + if (t->flag & T_CLIP_UV && clipUVTransform(t, global_dir, 0)) { + applyTranslationValue(t, global_dir); /* In proportional edit it can happen that */ /* vertices in the radius of the brush end */ @@ -368,8 +361,10 @@ static void applyTranslation(TransInfo *t, const int UNUSED(mval[2])) } } - recalcData(t); + /* Set the redo value. */ + mul_v3_m3v3(t->values_final, t->spacemtx_inv, global_dir); + recalcData(t); ED_area_status_text(t->area, str); } diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c index 36f42992573..d643244e6ca 100644 --- a/source/blender/editors/transform/transform_ops.c +++ b/source/blender/editors/transform/transform_ops.c @@ -716,6 +716,15 @@ void Transform_Properties(struct wmOperatorType *ot, int flags) prop = RNA_def_boolean(ot->srna, "use_accurate", 0, "Accurate", "Use accurate transformation"); RNA_def_property_flag(prop, PROP_HIDDEN); } + + if (flags & P_POST_TRANSFORM) { + prop = RNA_def_boolean(ot->srna, + "use_automerge_and_split", + 0, + "Auto Merge & Split", + "Forces the use of Auto Merge & Split"); + RNA_def_property_flag(prop, PROP_HIDDEN); + } } static void TRANSFORM_OT_translate(struct wmOperatorType *ot) @@ -741,7 +750,7 @@ static void TRANSFORM_OT_translate(struct wmOperatorType *ot) Transform_Properties(ot, P_ORIENT_MATRIX | P_CONSTRAINT | P_PROPORTIONAL | P_MIRROR | P_ALIGN_SNAP | - P_OPTIONS | P_GPENCIL_EDIT | P_CURSOR_EDIT); + P_OPTIONS | P_GPENCIL_EDIT | P_CURSOR_EDIT | P_POST_TRANSFORM); } static void TRANSFORM_OT_resize(struct wmOperatorType *ot) diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c index 76823adfd20..4cddb9d3b4a 100644 --- a/source/blender/editors/transform/transform_orientations.c +++ b/source/blender/editors/transform/transform_orientations.c @@ -407,14 +407,19 @@ bool applyTransformOrientation(const TransformOrientation *ts, float r_mat[3][3] return true; } -static int count_bone_select(bArmature *arm, ListBase *lb, const bool do_it) +/* Updates all `BONE_TRANSFORM` flags. + * Returns total number of bones with `BONE_TRANSFORM`. + * Note: `transform_convert_pose_transflags_update` has a similar logic. */ +static int armature_bone_transflags_update_recursive(bArmature *arm, + ListBase *lb, + const bool do_it) { Bone *bone; bool do_next; int total = 0; for (bone = lb->first; bone; bone = bone->next) { - bone->flag &= ~(BONE_TRANSFORM | BONE_TRANSFORM_MIRROR); + bone->flag &= ~BONE_TRANSFORM; do_next = do_it; if (do_it) { if (bone->layer & arm->layer) { @@ -427,100 +432,156 @@ static int count_bone_select(bArmature *arm, ListBase *lb, const bool do_it) } } } - total += count_bone_select(arm, &bone->childbase, do_next); + total += armature_bone_transflags_update_recursive(arm, &bone->childbase, do_next); } return total; } -void initTransformOrientation(bContext *C, TransInfo *t) +/* Sets the matrix of the specified space orientation. + * If the matrix cannot be obtained, an orientation different from the one + * informed is returned */ +short transform_orientation_matrix_get(bContext *C, + TransInfo *t, + const short orientation, + const float custom[3][3], + float r_spacemtx[3][3]) { Object *ob = CTX_data_active_object(C); Object *obedit = CTX_data_active_object(C); - switch (t->orientation.user) { + switch (orientation) { case V3D_ORIENT_GLOBAL: - unit_m3(t->spacemtx); - BLI_strncpy(t->spacename, TIP_("global"), sizeof(t->spacename)); - break; + unit_m3(r_spacemtx); + return V3D_ORIENT_GLOBAL; case V3D_ORIENT_GIMBAL: - unit_m3(t->spacemtx); - if (ob && gimbal_axis(ob, t->spacemtx)) { - BLI_strncpy(t->spacename, TIP_("gimbal"), sizeof(t->spacename)); - break; + unit_m3(r_spacemtx); + if (ob && gimbal_axis(ob, r_spacemtx)) { + return V3D_ORIENT_GIMBAL; } ATTR_FALLTHROUGH; /* no gimbal fallthrough to normal */ + case V3D_ORIENT_NORMAL: if (obedit || (ob && ob->mode & OB_MODE_POSE)) { - BLI_strncpy(t->spacename, TIP_("normal"), sizeof(t->spacename)); - ED_getTransformOrientationMatrix(C, t->spacemtx, t->around); - break; + ED_getTransformOrientationMatrix(C, r_spacemtx, t->around); + return V3D_ORIENT_NORMAL; } ATTR_FALLTHROUGH; /* we define 'normal' as 'local' in Object mode */ - case V3D_ORIENT_LOCAL: - BLI_strncpy(t->spacename, TIP_("local"), sizeof(t->spacename)); + case V3D_ORIENT_LOCAL: if (ob) { - copy_m3_m4(t->spacemtx, ob->obmat); - normalize_m3(t->spacemtx); - } - else { - unit_m3(t->spacemtx); + copy_m3_m4(r_spacemtx, ob->obmat); + normalize_m3(r_spacemtx); + return V3D_ORIENT_LOCAL; } + unit_m3(r_spacemtx); + return V3D_ORIENT_GLOBAL; - break; - - case V3D_ORIENT_VIEW: + case V3D_ORIENT_VIEW: { + float mat[3][3]; if ((t->spacetype == SPACE_VIEW3D) && (t->region->regiontype == RGN_TYPE_WINDOW)) { RegionView3D *rv3d = t->region->regiondata; - float mat[3][3]; - - BLI_strncpy(t->spacename, TIP_("view"), sizeof(t->spacename)); copy_m3_m4(mat, rv3d->viewinv); normalize_m3(mat); - copy_m3_m3(t->spacemtx, mat); } else { - unit_m3(t->spacemtx); + unit_m3(mat); } - break; - case V3D_ORIENT_CURSOR: { - BLI_strncpy(t->spacename, TIP_("cursor"), sizeof(t->spacename)); - BKE_scene_cursor_rot_to_mat3(&t->scene->cursor, t->spacemtx); - break; + copy_m3_m3(r_spacemtx, mat); + return V3D_ORIENT_VIEW; } + case V3D_ORIENT_CURSOR: + BKE_scene_cursor_rot_to_mat3(&t->scene->cursor, r_spacemtx); + return V3D_ORIENT_CURSOR; + case V3D_ORIENT_CUSTOM_MATRIX: - /* Already set. */ - BLI_strncpy(t->spacename, TIP_("custom"), sizeof(t->spacename)); - break; - case V3D_ORIENT_CUSTOM: - BLI_strncpy(t->spacename, t->orientation.custom->name, sizeof(t->spacename)); + copy_m3_m3(r_spacemtx, custom); + return V3D_ORIENT_CUSTOM_MATRIX; - if (applyTransformOrientation(t->orientation.custom, t->spacemtx, t->spacename)) { + case V3D_ORIENT_CUSTOM: + default: + BLI_assert(orientation >= V3D_ORIENT_CUSTOM); + TransformOrientation *ts = BKE_scene_transform_orientation_find( + t->scene, orientation - V3D_ORIENT_CUSTOM); + if (applyTransformOrientation(ts, r_spacemtx, t->spacename)) { /* pass */ } else { - unit_m3(t->spacemtx); + unit_m3(r_spacemtx); } break; } - if (t->orient_matrix_is_set == false) { - t->orient_matrix_is_set = true; - if (t->flag & T_MODAL) { - /* Rotate for example defaults to operating on the view plane. */ - t->orientation.unset = V3D_ORIENT_VIEW; - copy_m3_m4(t->orient_matrix, t->viewinv); - normalize_m3(t->orient_matrix); - negate_m3(t->orient_matrix); - } - else { - copy_m3_m3(t->orient_matrix, t->spacemtx); - } + return orientation; +} + +const char *transform_orientations_spacename_get(TransInfo *t, const short orient_type) +{ + switch (orient_type) { + case V3D_ORIENT_GLOBAL: + return TIP_("global"); + case V3D_ORIENT_GIMBAL: + return TIP_("gimbal"); + case V3D_ORIENT_NORMAL: + return TIP_("normal"); + case V3D_ORIENT_LOCAL: + return TIP_("local"); + case V3D_ORIENT_VIEW: + return TIP_("view"); + case V3D_ORIENT_CURSOR: + return TIP_("cursor"); + case V3D_ORIENT_CUSTOM_MATRIX: + return TIP_("custom"); + case V3D_ORIENT_CUSTOM: + default: + BLI_assert(orient_type >= V3D_ORIENT_CUSTOM); + TransformOrientation *ts = BKE_scene_transform_orientation_find( + t->scene, orient_type - V3D_ORIENT_CUSTOM); + return ts->name; } } +void transform_orientations_current_set(TransInfo *t, const short orient_index) +{ + const short orientation = t->orient[orient_index].type; + const char *spacename; + switch (orientation) { + case V3D_ORIENT_GLOBAL: + spacename = TIP_("global"); + break; + case V3D_ORIENT_GIMBAL: + spacename = TIP_("gimbal"); + break; + case V3D_ORIENT_NORMAL: + spacename = TIP_("normal"); + break; + case V3D_ORIENT_LOCAL: + spacename = TIP_("local"); + break; + case V3D_ORIENT_VIEW: + spacename = TIP_("view"); + break; + case V3D_ORIENT_CURSOR: + spacename = TIP_("cursor"); + break; + case V3D_ORIENT_CUSTOM_MATRIX: + spacename = TIP_("custom"); + break; + case V3D_ORIENT_CUSTOM: + default: + BLI_assert(orientation >= V3D_ORIENT_CUSTOM); + TransformOrientation *ts = BKE_scene_transform_orientation_find( + t->scene, orientation - V3D_ORIENT_CUSTOM); + spacename = ts->name; + break; + } + + BLI_strncpy(t->spacename, spacename, sizeof(t->spacename)); + copy_m3_m3(t->spacemtx, t->orient[orient_index].matrix); + invert_m3_m3(t->spacemtx_inv, t->spacemtx); +} + /** * utility function - get first n, selected vert/edge/faces */ @@ -1072,10 +1133,9 @@ int getTransformOrientation_ex(const bContext *C, ok = true; } else { - int totsel; - - totsel = count_bone_select(arm, &arm->bonebase, true); - if (totsel) { + int transformed_len; + transformed_len = armature_bone_transflags_update_recursive(arm, &arm->bonebase, true); + if (transformed_len) { /* use channels to get stats */ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { if (pchan->bone && pchan->bone->flag & BONE_TRANSFORM) { diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c index 154af6c8ae2..d3df68b21da 100644 --- a/source/blender/editors/transform/transform_snap.c +++ b/source/blender/editors/transform/transform_snap.c @@ -1749,8 +1749,8 @@ static void applyGridIncrement( float local_axis[3]; float pos_on_axis[3]; - copy_v3_v3(local_axis, t->con.mtx[i]); - copy_v3_v3(pos_on_axis, t->con.mtx[i]); + copy_v3_v3(local_axis, t->spacemtx[i]); + copy_v3_v3(pos_on_axis, t->spacemtx[i]); /* amount of movement on axis from initial pos */ mul_v3_fl(pos_on_axis, val[i]); diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c index 2cfeedbb346..acd76a2e3f5 100644 --- a/source/blender/editors/transform/transform_snap_object.c +++ b/source/blender/editors/transform/transform_snap_object.c @@ -1707,8 +1707,14 @@ static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx, &nearest.dist_sq, nearest.co)) { nearest.index = vindex[v_id]; - nearest2d.copy_vert_no(vindex[v_id], nearest.no, nearest2d.userdata); elem = SCE_SNAP_MODE_VERTEX; + if (r_no) { + float imat[4][4]; + invert_m4_m4(imat, obmat); + nearest2d.copy_vert_no(vindex[v_id], r_no, nearest2d.userdata); + mul_transposed_mat3_m4_v3(imat, r_no); + normalize_v3(r_no); + } } } } @@ -1726,10 +1732,6 @@ static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx, vmid, &nearest.dist_sq, nearest.co)) { - float v_nor[2][3]; - nearest2d.copy_vert_no(vindex[0], v_nor[0], nearest2d.userdata); - nearest2d.copy_vert_no(vindex[1], v_nor[1], nearest2d.userdata); - mid_v3_v3v3(nearest.no, v_nor[0], v_nor[1]); nearest.index = *r_index; elem = SCE_SNAP_MODE_EDGE_MIDPOINT; } @@ -1757,11 +1759,6 @@ static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx, v_near, &nearest.dist_sq, nearest.co)) { - float v_nor[2][3]; - nearest2d.copy_vert_no(vindex[0], v_nor[0], nearest2d.userdata); - nearest2d.copy_vert_no(vindex[1], v_nor[1], nearest2d.userdata); - mid_v3_v3v3(nearest.no, v_nor[0], v_nor[1]); - nearest.index = *r_index; elem = SCE_SNAP_MODE_EDGE_PERPENDICULAR; } @@ -1778,15 +1775,6 @@ static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx, mul_m4_v3(obmat, r_loc); } - if (r_no) { - float imat[4][4]; - invert_m4_m4(imat, obmat); - - copy_v3_v3(r_no, nearest.no); - mul_transposed_mat3_m4_v3(imat, r_no); - normalize_v3(r_no); - } - *r_index = nearest.index; } diff --git a/source/blender/editors/uvedit/CMakeLists.txt b/source/blender/editors/uvedit/CMakeLists.txt index d2ba9ab9591..b40b82c50fb 100644 --- a/source/blender/editors/uvedit/CMakeLists.txt +++ b/source/blender/editors/uvedit/CMakeLists.txt @@ -40,6 +40,7 @@ set(SRC uvedit_draw.c uvedit_ops.c uvedit_parametrizer.c + uvedit_select.c uvedit_smart_stitch.c uvedit_unwrap_ops.c diff --git a/source/blender/editors/uvedit/uvedit_draw.c b/source/blender/editors/uvedit/uvedit_draw.c index 28800c5b6cf..f8cef95c776 100644 --- a/source/blender/editors/uvedit/uvedit_draw.c +++ b/source/blender/editors/uvedit/uvedit_draw.c @@ -223,6 +223,7 @@ static void draw_uvs_shadow(SpaceImage *sima, { Object *ob_eval = DEG_get_evaluated_object(depsgraph, obedit); Mesh *me = ob_eval->data; + const float overlay_alpha = sima->uv_opacity; float col[4]; UI_GetThemeColor4fv(TH_UV_SHADOW, col); @@ -235,7 +236,11 @@ static void draw_uvs_shadow(SpaceImage *sima, GPU_line_smooth(true); GPU_blend(true); } + else if (overlay_alpha < 1.0f) { + GPU_blend(true); + } + col[3] = overlay_alpha; GPU_batch_program_set_builtin(edges, GPU_SHADER_2D_UV_UNIFORM_COLOR); GPU_batch_uniform_4fv(edges, "color", col); GPU_batch_draw(edges); @@ -244,6 +249,9 @@ static void draw_uvs_shadow(SpaceImage *sima, GPU_line_smooth(false); GPU_blend(false); } + else if (overlay_alpha < 1.0f) { + GPU_blend(false); + } } } @@ -316,6 +324,7 @@ static void draw_uvs(SpaceImage *sima, Object *ob_eval = batch->ob_eval; const ToolSettings *ts = scene->toolsettings; float col1[4], col2[4], col3[4], transparent[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + const float overlay_alpha = sima->uv_opacity; if (sima->flag & SI_DRAWSHADOW) { bool is_cage_like_final_meshes = false; @@ -356,7 +365,11 @@ static void draw_uvs(SpaceImage *sima, UI_GetThemeColor4fv(TH_FACE, col1); UI_GetThemeColor4fv(TH_FACE_SELECT, col2); UI_GetThemeColor4fv(TH_EDITMESH_ACTIVE, col3); - col3[3] *= 0.2; /* Simulate dithering */ + + col1[3] *= overlay_alpha; + col2[3] *= overlay_alpha; + col3[3] *= overlay_alpha; + GPU_batch_uniform_4fv(batch->faces, "faceColor", col1); GPU_batch_uniform_4fv(batch->faces, "selectColor", col2); GPU_batch_uniform_4fv(batch->faces, "activeColor", col3); @@ -382,9 +395,16 @@ static void draw_uvs(SpaceImage *sima, GPU_line_smooth(true); GPU_blend(true); } + else if (overlay_alpha < 1.0f) { + GPU_blend(true); + } + switch (sima->dt_uv) { case SI_UVDT_DASH: { - float dash_colors[2][4] = {{0.56f, 0.56f, 0.56f, 1.0f}, {0.07f, 0.07f, 0.07f, 1.0f}}; + float dash_colors[2][4] = { + {0.56f, 0.56f, 0.56f, overlay_alpha}, + {0.07f, 0.07f, 0.07f, overlay_alpha}, + }; float viewport_size[4]; GPU_viewport_size_get_f(viewport_size); @@ -408,7 +428,8 @@ static void draw_uvs(SpaceImage *sima, * instead of modifying the provoking vert. */ glProvokingVertex(GL_FIRST_VERTEX_CONVENTION); - UI_GetThemeColor4fv(TH_EDGE_SELECT, col2); + UI_GetThemeColor3fv(TH_EDGE_SELECT, col2); + col2[3] = overlay_alpha; GPU_batch_program_set_builtin( batch->edges, (interpedges) ? GPU_SHADER_2D_UV_EDGES_SMOOTH : GPU_SHADER_2D_UV_EDGES); @@ -416,18 +437,19 @@ static void draw_uvs(SpaceImage *sima, if (sima->dt_uv == SI_UVDT_OUTLINE) { /* Black Outline. */ GPU_line_width(3.0f); - GPU_batch_uniform_4f(batch->edges, "edgeColor", 0.0f, 0.0f, 0.0f, 1.0f); - GPU_batch_uniform_4f(batch->edges, "selectColor", 0.0f, 0.0f, 0.0f, 1.0f); + GPU_batch_uniform_4f(batch->edges, "edgeColor", 0.0f, 0.0f, 0.0f, overlay_alpha); + GPU_batch_uniform_4f(batch->edges, "selectColor", 0.0f, 0.0f, 0.0f, overlay_alpha); GPU_batch_draw(batch->edges); - UI_GetThemeColor4fv(TH_WIRE_EDIT, col1); + UI_GetThemeColor3fv(TH_WIRE_EDIT, col1); } else if (sima->dt_uv == SI_UVDT_WHITE) { - copy_v4_fl4(col1, 1.0f, 1.0f, 1.0f, 1.0f); + copy_v3_fl3(col1, 1.0f, 1.0f, 1.0f); } else { - copy_v4_fl4(col1, 0.0f, 0.0f, 0.0f, 1.0f); + copy_v3_fl3(col1, 0.0f, 0.0f, 0.0f); } + col1[3] = overlay_alpha; /* Inner Line. Use depth test to insure selection is drawn on top. */ GPU_depth_test(true); @@ -445,6 +467,9 @@ static void draw_uvs(SpaceImage *sima, GPU_line_smooth(false); GPU_blend(false); } + else if (overlay_alpha < 1.0f) { + GPU_blend(false); + } } if (batch->verts || batch->facedots) { UI_GetThemeColor4fv(TH_VERTEX_SELECT, col2); diff --git a/source/blender/editors/uvedit/uvedit_intern.h b/source/blender/editors/uvedit/uvedit_intern.h index 167e8df6fa7..31384d6df17 100644 --- a/source/blender/editors/uvedit/uvedit_intern.h +++ b/source/blender/editors/uvedit/uvedit_intern.h @@ -93,6 +93,7 @@ bool uv_find_nearest_face_multi(struct Scene *scene, void uvedit_live_unwrap_update(struct SpaceImage *sima, struct Scene *scene, struct Object *obedit); +void uvedit_pixel_to_float(struct SpaceImage *sima, float pixeldist, float r_dist[2]); /* operators */ @@ -107,4 +108,28 @@ void UV_OT_sphere_project(struct wmOperatorType *ot); void UV_OT_unwrap(struct wmOperatorType *ot); void UV_OT_stitch(struct wmOperatorType *ot); +/* uvedit_select.c */ + +bool uvedit_select_is_any_selected(struct Scene *scene, struct Object *obedit); +bool uvedit_select_is_any_selected_multi(struct Scene *scene, + struct Object **objects, + const uint objects_len); +const float *uvedit_first_selected_uv_from_vertex(struct Scene *scene, + struct BMVert *eve, + const int cd_loop_uv_offset); + +void UV_OT_select_all(struct wmOperatorType *ot); +void UV_OT_select(struct wmOperatorType *ot); +void UV_OT_select_loop(struct wmOperatorType *ot); +void UV_OT_select_linked(struct wmOperatorType *ot); +void UV_OT_select_linked_pick(struct wmOperatorType *ot); +void UV_OT_select_split(struct wmOperatorType *ot); +void UV_OT_select_pinned(struct wmOperatorType *ot); +void UV_OT_select_box(struct wmOperatorType *ot); +void UV_OT_select_lasso(struct wmOperatorType *ot); +void UV_OT_select_circle(struct wmOperatorType *ot); +void UV_OT_select_more(struct wmOperatorType *ot); +void UV_OT_select_less(struct wmOperatorType *ot); +void UV_OT_select_overlap(struct wmOperatorType *ot); + #endif /* __UVEDIT_INTERN_H__ */ diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c index 49c802131e6..78b6cfc44ac 100644 --- a/source/blender/editors/uvedit/uvedit_ops.c +++ b/source/blender/editors/uvedit/uvedit_ops.c @@ -36,15 +36,9 @@ #include "DNA_scene_types.h" #include "DNA_space_types.h" -#include "BLI_alloca.h" #include "BLI_array.h" -#include "BLI_blenlib.h" -#include "BLI_hash.h" -#include "BLI_kdopbvh.h" #include "BLI_kdtree.h" -#include "BLI_lasso_2d.h" #include "BLI_math.h" -#include "BLI_polyfill_2d.h" #include "BLI_utildefines.h" #include "BLT_translation.h" @@ -52,31 +46,22 @@ #include "BKE_context.h" #include "BKE_customdata.h" #include "BKE_editmesh.h" -#include "BKE_image.h" #include "BKE_layer.h" #include "BKE_main.h" #include "BKE_material.h" -#include "BKE_mesh.h" #include "BKE_mesh_mapping.h" #include "BKE_node.h" -#include "BKE_report.h" -#include "BKE_scene.h" #include "DEG_depsgraph.h" -#include "DEG_depsgraph_query.h" #include "ED_image.h" #include "ED_mesh.h" #include "ED_node.h" -#include "ED_object.h" #include "ED_screen.h" -#include "ED_select_utils.h" -#include "ED_transform.h" #include "ED_uvedit.h" #include "RNA_access.h" #include "RNA_define.h" -#include "RNA_enum_types.h" #include "WM_api.h" #include "WM_message.h" @@ -88,27 +73,6 @@ #include "uvedit_intern.h" -static bool uv_select_is_any_selected(Scene *scene, Object *obedit); -static bool uv_select_is_any_selected_multi(Scene *scene, - Object **objects, - const uint objects_len); -static void uv_select_all_perform(Scene *scene, Object *obedit, int action); -static void uv_select_all_perform_multi(Scene *scene, - Object **objects, - const uint objects_len, - int action); -static void uv_select_flush_from_tag_face(SpaceImage *sima, - Scene *scene, - Object *obedit, - const bool select); -static void uv_select_flush_from_tag_loop(SpaceImage *sima, - Scene *scene, - Object *obedit, - const bool select); -static void uv_select_tag_update_for_object(Depsgraph *depsgraph, - const ToolSettings *ts, - Object *obedit); - /* -------------------------------------------------------------------- */ /** \name State Testing * \{ */ @@ -226,7 +190,7 @@ void ED_object_assign_active_image(Main *bmain, Object *ob, int mat_nr, Image *i /** \name Space Conversion * \{ */ -static void uvedit_pixel_to_float(SpaceImage *sima, float *dist, float pixeldist) +void uvedit_pixel_to_float(SpaceImage *sima, float pixeldist, float r_dist[2]) { int width, height; @@ -238,333 +202,8 @@ static void uvedit_pixel_to_float(SpaceImage *sima, float *dist, float pixeldist height = IMG_SIZE_FALLBACK; } - dist[0] = pixeldist / width; - dist[1] = pixeldist / height; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Visibility and Selection Utilities - * \{ */ - -static void uvedit_vertex_select_tagged(BMEditMesh *em, - Scene *scene, - bool select, - int cd_loop_uv_offset) -{ - BMFace *efa; - BMLoop *l; - BMIter iter, liter; - - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) { - uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); - } - } - } -} - -bool uvedit_face_visible_test_ex(const ToolSettings *ts, BMFace *efa) -{ - if (ts->uv_flag & UV_SYNC_SELECTION) { - return (BM_elem_flag_test(efa, BM_ELEM_HIDDEN) == 0); - } - else { - return (BM_elem_flag_test(efa, BM_ELEM_HIDDEN) == 0 && BM_elem_flag_test(efa, BM_ELEM_SELECT)); - } -} - -bool uvedit_face_visible_test(const Scene *scene, BMFace *efa) -{ - return uvedit_face_visible_test_ex(scene->toolsettings, efa); -} - -bool uvedit_face_select_test_ex(const ToolSettings *ts, BMFace *efa, const int cd_loop_uv_offset) -{ - if (ts->uv_flag & UV_SYNC_SELECTION) { - return (BM_elem_flag_test(efa, BM_ELEM_SELECT)); - } - else { - BMLoop *l_iter, *l_first; - l_iter = l_first = BM_FACE_FIRST_LOOP(efa); - do { - MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset); - if (!(luv->flag & MLOOPUV_VERTSEL)) { - return false; - } - } while ((l_iter = l_iter->next) != l_first); - return true; - } -} -bool uvedit_face_select_test(const Scene *scene, BMFace *efa, const int cd_loop_uv_offset) -{ - return uvedit_face_select_test_ex(scene->toolsettings, efa, cd_loop_uv_offset); -} - -bool uvedit_face_select_set(const struct Scene *scene, - struct BMEditMesh *em, - struct BMFace *efa, - const bool select, - const bool do_history, - const int cd_loop_uv_offset) -{ - if (select) { - return uvedit_face_select_enable(scene, em, efa, do_history, cd_loop_uv_offset); - } - else { - return uvedit_face_select_disable(scene, em, efa, cd_loop_uv_offset); - } -} - -bool uvedit_face_select_enable(const Scene *scene, - BMEditMesh *em, - BMFace *efa, - const bool do_history, - const int cd_loop_uv_offset) -{ - const ToolSettings *ts = scene->toolsettings; - - if (ts->uv_flag & UV_SYNC_SELECTION) { - BM_face_select_set(em->bm, efa, true); - if (do_history) { - BM_select_history_store(em->bm, (BMElem *)efa); - } - } - else { - BMLoop *l; - MLoopUV *luv; - BMIter liter; - - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - luv->flag |= MLOOPUV_VERTSEL; - } - - return true; - } - - return false; -} - -bool uvedit_face_select_disable(const Scene *scene, - BMEditMesh *em, - BMFace *efa, - const int cd_loop_uv_offset) -{ - const ToolSettings *ts = scene->toolsettings; - - if (ts->uv_flag & UV_SYNC_SELECTION) { - BM_face_select_set(em->bm, efa, false); - } - else { - BMLoop *l; - MLoopUV *luv; - BMIter liter; - - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - luv->flag &= ~MLOOPUV_VERTSEL; - } - - return true; - } - - return false; -} - -bool uvedit_edge_select_test_ex(const ToolSettings *ts, BMLoop *l, const int cd_loop_uv_offset) -{ - if (ts->uv_flag & UV_SYNC_SELECTION) { - if (ts->selectmode & SCE_SELECT_FACE) { - return BM_elem_flag_test(l->f, BM_ELEM_SELECT); - } - else if (ts->selectmode == SCE_SELECT_EDGE) { - return BM_elem_flag_test(l->e, BM_ELEM_SELECT); - } - else { - return BM_elem_flag_test(l->v, BM_ELEM_SELECT) && - BM_elem_flag_test(l->next->v, BM_ELEM_SELECT); - } - } - else { - MLoopUV *luv1, *luv2; - - luv1 = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - luv2 = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset); - - return (luv1->flag & MLOOPUV_VERTSEL) && (luv2->flag & MLOOPUV_VERTSEL); - } -} -bool uvedit_edge_select_test(const Scene *scene, BMLoop *l, const int cd_loop_uv_offset) -{ - return uvedit_edge_select_test_ex(scene->toolsettings, l, cd_loop_uv_offset); -} - -void uvedit_edge_select_set(BMEditMesh *em, - const Scene *scene, - BMLoop *l, - const bool select, - const bool do_history, - const int cd_loop_uv_offset) - -{ - if (select) { - uvedit_edge_select_enable(em, scene, l, do_history, cd_loop_uv_offset); - } - else { - uvedit_edge_select_disable(em, scene, l, cd_loop_uv_offset); - } -} - -void uvedit_edge_select_enable(BMEditMesh *em, - const Scene *scene, - BMLoop *l, - const bool do_history, - const int cd_loop_uv_offset) - -{ - const ToolSettings *ts = scene->toolsettings; - - if (ts->uv_flag & UV_SYNC_SELECTION) { - if (ts->selectmode & SCE_SELECT_FACE) { - BM_face_select_set(em->bm, l->f, true); - } - else if (ts->selectmode & SCE_SELECT_EDGE) { - BM_edge_select_set(em->bm, l->e, true); - } - else { - BM_vert_select_set(em->bm, l->e->v1, true); - BM_vert_select_set(em->bm, l->e->v2, true); - } - - if (do_history) { - BM_select_history_store(em->bm, (BMElem *)l->e); - } - } - else { - MLoopUV *luv1, *luv2; - - luv1 = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - luv2 = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset); - - luv1->flag |= MLOOPUV_VERTSEL; - luv2->flag |= MLOOPUV_VERTSEL; - } -} - -void uvedit_edge_select_disable(BMEditMesh *em, - const Scene *scene, - BMLoop *l, - const int cd_loop_uv_offset) - -{ - const ToolSettings *ts = scene->toolsettings; - - if (ts->uv_flag & UV_SYNC_SELECTION) { - if (ts->selectmode & SCE_SELECT_FACE) { - BM_face_select_set(em->bm, l->f, false); - } - else if (ts->selectmode & SCE_SELECT_EDGE) { - BM_edge_select_set(em->bm, l->e, false); - } - else { - BM_vert_select_set(em->bm, l->e->v1, false); - BM_vert_select_set(em->bm, l->e->v2, false); - } - } - else { - MLoopUV *luv1, *luv2; - - luv1 = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - luv2 = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset); - - luv1->flag &= ~MLOOPUV_VERTSEL; - luv2->flag &= ~MLOOPUV_VERTSEL; - } -} - -bool uvedit_uv_select_test_ex(const ToolSettings *ts, BMLoop *l, const int cd_loop_uv_offset) -{ - if (ts->uv_flag & UV_SYNC_SELECTION) { - if (ts->selectmode & SCE_SELECT_FACE) { - return BM_elem_flag_test_bool(l->f, BM_ELEM_SELECT); - } - else { - return BM_elem_flag_test_bool(l->v, BM_ELEM_SELECT); - } - } - else { - MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - return (luv->flag & MLOOPUV_VERTSEL) != 0; - } -} -bool uvedit_uv_select_test(const Scene *scene, BMLoop *l, const int cd_loop_uv_offset) -{ - return uvedit_uv_select_test_ex(scene->toolsettings, l, cd_loop_uv_offset); -} - -void uvedit_uv_select_set(BMEditMesh *em, - const Scene *scene, - BMLoop *l, - const bool select, - const bool do_history, - const int cd_loop_uv_offset) -{ - if (select) { - uvedit_uv_select_enable(em, scene, l, do_history, cd_loop_uv_offset); - } - else { - uvedit_uv_select_disable(em, scene, l, cd_loop_uv_offset); - } -} - -void uvedit_uv_select_enable(BMEditMesh *em, - const Scene *scene, - BMLoop *l, - const bool do_history, - const int cd_loop_uv_offset) -{ - const ToolSettings *ts = scene->toolsettings; - - if (ts->uv_flag & UV_SYNC_SELECTION) { - if (ts->selectmode & SCE_SELECT_FACE) { - BM_face_select_set(em->bm, l->f, true); - } - else { - BM_vert_select_set(em->bm, l->v, true); - } - - if (do_history) { - BM_select_history_remove(em->bm, (BMElem *)l->v); - } - } - else { - MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - luv->flag |= MLOOPUV_VERTSEL; - } -} - -void uvedit_uv_select_disable(BMEditMesh *em, - const Scene *scene, - BMLoop *l, - const int cd_loop_uv_offset) -{ - const ToolSettings *ts = scene->toolsettings; - - if (ts->uv_flag & UV_SYNC_SELECTION) { - if (ts->selectmode & SCE_SELECT_FACE) { - BM_face_select_set(em->bm, l->f, false); - } - else { - BM_vert_select_set(em->bm, l->v, false); - } - } - else { - MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - luv->flag &= ~MLOOPUV_VERTSEL; - } + r_dist[0] = pixeldist / width; + r_dist[1] = pixeldist / height; } /** \} */ @@ -746,7 +385,7 @@ bool ED_uvedit_center_from_pivot_ex(SpaceImage *sima, uint objects_len = 0; Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( view_layer, ((View3D *)NULL), &objects_len); - *r_has_select = uv_select_is_any_selected_multi(scene, objects, objects_len); + *r_has_select = uvedit_select_is_any_selected_multi(scene, objects, objects_len); MEM_freeN(objects); } break; @@ -775,858 +414,6 @@ bool ED_uvedit_center_from_pivot( /** \} */ /* -------------------------------------------------------------------- */ -/** \name Find Nearest Elements - * \{ */ - -bool uv_find_nearest_edge(Scene *scene, Object *obedit, const float co[2], UvNearestHit *hit) -{ - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMFace *efa; - BMLoop *l; - BMIter iter, liter; - MLoopUV *luv, *luv_next; - int i; - bool found = false; - - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - - BM_mesh_elem_index_ensure(em->bm, BM_VERT); - - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, efa)) { - continue; - } - BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset); - - const float dist_test_sq = dist_squared_to_line_segment_v2(co, luv->uv, luv_next->uv); - - if (dist_test_sq < hit->dist_sq) { - hit->efa = efa; - - hit->l = l; - hit->luv = luv; - hit->luv_next = luv_next; - hit->lindex = i; - - hit->dist_sq = dist_test_sq; - found = true; - } - } - } - return found; -} - -bool uv_find_nearest_edge_multi(Scene *scene, - Object **objects, - const uint objects_len, - const float co[2], - UvNearestHit *hit_final) -{ - bool found = false; - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - if (uv_find_nearest_edge(scene, obedit, co, hit_final)) { - hit_final->ob = obedit; - found = true; - } - } - return found; -} - -bool uv_find_nearest_face(Scene *scene, Object *obedit, const float co[2], UvNearestHit *hit_final) -{ - BMEditMesh *em = BKE_editmesh_from_object(obedit); - bool found = false; - - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - - /* this will fill in hit.vert1 and hit.vert2 */ - float dist_sq_init = hit_final->dist_sq; - UvNearestHit hit = *hit_final; - if (uv_find_nearest_edge(scene, obedit, co, &hit)) { - hit.dist_sq = dist_sq_init; - hit.l = NULL; - hit.luv = hit.luv_next = NULL; - - BMIter iter; - BMFace *efa; - - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, efa)) { - continue; - } - - float cent[2]; - uv_poly_center(efa, cent, cd_loop_uv_offset); - - const float dist_test_sq = len_squared_v2v2(co, cent); - - if (dist_test_sq < hit.dist_sq) { - hit.efa = efa; - hit.dist_sq = dist_test_sq; - found = true; - } - } - } - if (found) { - *hit_final = hit; - } - return found; -} - -bool uv_find_nearest_face_multi(Scene *scene, - Object **objects, - const uint objects_len, - const float co[2], - UvNearestHit *hit_final) -{ - bool found = false; - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - if (uv_find_nearest_face(scene, obedit, co, hit_final)) { - hit_final->ob = obedit; - found = true; - } - } - return found; -} - -static bool uv_nearest_between(const BMLoop *l, const float co[2], const int cd_loop_uv_offset) -{ - const float *uv_prev = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l->prev, cd_loop_uv_offset))->uv; - const float *uv_curr = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset))->uv; - const float *uv_next = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset))->uv; - - return ((line_point_side_v2(uv_prev, uv_curr, co) > 0.0f) && - (line_point_side_v2(uv_next, uv_curr, co) <= 0.0f)); -} - -bool uv_find_nearest_vert(Scene *scene, - Object *obedit, - float const co[2], - const float penalty_dist, - UvNearestHit *hit_final) -{ - bool found = false; - - /* this will fill in hit.vert1 and hit.vert2 */ - float dist_sq_init = hit_final->dist_sq; - UvNearestHit hit = *hit_final; - if (uv_find_nearest_edge(scene, obedit, co, &hit)) { - hit.dist_sq = dist_sq_init; - - hit.l = NULL; - hit.luv = hit.luv_next = NULL; - - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMFace *efa; - BMIter iter; - - BM_mesh_elem_index_ensure(em->bm, BM_VERT); - - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, efa)) { - continue; - } - - BMIter liter; - BMLoop *l; - int i; - BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) { - float dist_test_sq; - MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - if (penalty_dist != 0.0f && uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { - dist_test_sq = len_v2v2(co, luv->uv) + penalty_dist; - dist_test_sq = square_f(dist_test_sq); - } - else { - dist_test_sq = len_squared_v2v2(co, luv->uv); - } - - if (dist_test_sq <= hit.dist_sq) { - if (dist_test_sq == hit.dist_sq) { - if (!uv_nearest_between(l, co, cd_loop_uv_offset)) { - continue; - } - } - - hit.dist_sq = dist_test_sq; - - hit.l = l; - hit.luv = luv; - hit.luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset); - hit.efa = efa; - hit.lindex = i; - found = true; - } - } - } - } - - if (found) { - *hit_final = hit; - } - - return found; -} - -bool uv_find_nearest_vert_multi(Scene *scene, - Object **objects, - const uint objects_len, - float const co[2], - const float penalty_dist, - UvNearestHit *hit_final) -{ - bool found = false; - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - if (uv_find_nearest_vert(scene, obedit, co, penalty_dist, hit_final)) { - hit_final->ob = obedit; - found = true; - } - } - return found; -} - -bool ED_uvedit_nearest_uv( - const Scene *scene, Object *obedit, const float co[2], float *dist_sq, float r_uv[2]) -{ - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMIter iter; - BMFace *efa; - const float *uv_best = NULL; - float dist_best = *dist_sq; - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, efa)) { - continue; - } - BMLoop *l_iter, *l_first; - l_iter = l_first = BM_FACE_FIRST_LOOP(efa); - do { - const float *uv = ((const MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset))->uv; - const float dist_test = len_squared_v2v2(co, uv); - if (dist_best > dist_test) { - dist_best = dist_test; - uv_best = uv; - } - } while ((l_iter = l_iter->next) != l_first); - } - - if (uv_best != NULL) { - copy_v2_v2(r_uv, uv_best); - *dist_sq = dist_best; - return true; - } - else { - return false; - } -} - -bool ED_uvedit_nearest_uv_multi(const Scene *scene, - Object **objects, - const uint objects_len, - const float co[2], - float *dist_sq, - float r_uv[2]) -{ - bool found = false; - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - if (ED_uvedit_nearest_uv(scene, obedit, co, dist_sq, r_uv)) { - found = true; - } - } - return found; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Loop Select - * \{ */ - -static void uv_select_edgeloop_vertex_loop_flag(UvMapVert *first) -{ - UvMapVert *iterv; - int count = 0; - - for (iterv = first; iterv; iterv = iterv->next) { - if (iterv->separate && iterv != first) { - break; - } - - count++; - } - - if (count < 5) { - first->flag = 1; - } -} - -static UvMapVert *uv_select_edgeloop_vertex_map_get(UvVertMap *vmap, BMFace *efa, BMLoop *l) -{ - UvMapVert *iterv, *first; - first = BM_uv_vert_map_at_index(vmap, BM_elem_index_get(l->v)); - - for (iterv = first; iterv; iterv = iterv->next) { - if (iterv->separate) { - first = iterv; - } - if (iterv->poly_index == BM_elem_index_get(efa)) { - return first; - } - } - - return NULL; -} - -static bool uv_select_edgeloop_edge_tag_faces(BMEditMesh *em, - UvMapVert *first1, - UvMapVert *first2, - int *totface) -{ - UvMapVert *iterv1, *iterv2; - BMFace *efa; - int tot = 0; - - /* count number of faces this edge has */ - for (iterv1 = first1; iterv1; iterv1 = iterv1->next) { - if (iterv1->separate && iterv1 != first1) { - break; - } - - for (iterv2 = first2; iterv2; iterv2 = iterv2->next) { - if (iterv2->separate && iterv2 != first2) { - break; - } - - if (iterv1->poly_index == iterv2->poly_index) { - /* if face already tagged, don't do this edge */ - efa = BM_face_at_index(em->bm, iterv1->poly_index); - if (BM_elem_flag_test(efa, BM_ELEM_TAG)) { - return false; - } - - tot++; - break; - } - } - } - - if (*totface == 0) { /* start edge */ - *totface = tot; - } - else if (tot != *totface) { /* check for same number of faces as start edge */ - return false; - } - - /* tag the faces */ - for (iterv1 = first1; iterv1; iterv1 = iterv1->next) { - if (iterv1->separate && iterv1 != first1) { - break; - } - - for (iterv2 = first2; iterv2; iterv2 = iterv2->next) { - if (iterv2->separate && iterv2 != first2) { - break; - } - - if (iterv1->poly_index == iterv2->poly_index) { - efa = BM_face_at_index(em->bm, iterv1->poly_index); - BM_elem_flag_enable(efa, BM_ELEM_TAG); - break; - } - } - } - - return true; -} - -static int uv_select_edgeloop( - Scene *scene, Object *obedit, UvNearestHit *hit, const float limit[2], const bool extend) -{ - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMFace *efa; - BMIter iter, liter; - BMLoop *l; - UvVertMap *vmap; - UvMapVert *iterv_curr; - UvMapVert *iterv_next; - int starttotf; - bool looking, select; - - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - - /* setup */ - BM_mesh_elem_table_ensure(em->bm, BM_FACE); - vmap = BM_uv_vert_map_create(em->bm, limit, false, false); - - BM_mesh_elem_index_ensure(em->bm, BM_VERT | BM_FACE); - - if (!extend) { - uv_select_all_perform(scene, obedit, SEL_DESELECT); - } - - BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false); - - /* set flags for first face and verts */ - iterv_curr = uv_select_edgeloop_vertex_map_get(vmap, hit->efa, hit->l); - iterv_next = uv_select_edgeloop_vertex_map_get(vmap, hit->efa, hit->l->next); - uv_select_edgeloop_vertex_loop_flag(iterv_curr); - uv_select_edgeloop_vertex_loop_flag(iterv_next); - - starttotf = 0; - uv_select_edgeloop_edge_tag_faces(em, iterv_curr, iterv_next, &starttotf); - - /* sorry, first edge isn't even ok */ - looking = !(iterv_curr->flag == 0 && iterv_next->flag == 0); - - /* iterate */ - while (looking) { - looking = false; - - /* find correct valence edges which are not tagged yet, but connect to tagged one */ - - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!BM_elem_flag_test(efa, BM_ELEM_TAG) && uvedit_face_visible_test(scene, efa)) { - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - /* check face not hidden and not tagged */ - if (!(iterv_curr = uv_select_edgeloop_vertex_map_get(vmap, efa, l))) { - continue; - } - if (!(iterv_next = uv_select_edgeloop_vertex_map_get(vmap, efa, l->next))) { - continue; - } - - /* check if vertex is tagged and has right valence */ - if (iterv_curr->flag || iterv_next->flag) { - if (uv_select_edgeloop_edge_tag_faces(em, iterv_curr, iterv_next, &starttotf)) { - looking = true; - BM_elem_flag_enable(efa, BM_ELEM_TAG); - - uv_select_edgeloop_vertex_loop_flag(iterv_curr); - uv_select_edgeloop_vertex_loop_flag(iterv_next); - break; - } - } - } - } - } - } - - /* do the actual select/deselect */ - iterv_curr = uv_select_edgeloop_vertex_map_get(vmap, hit->efa, hit->l); - iterv_next = uv_select_edgeloop_vertex_map_get(vmap, hit->efa, hit->l->next); - iterv_curr->flag = 1; - iterv_next->flag = 1; - - if (extend) { - select = !(uvedit_uv_select_test(scene, hit->l, cd_loop_uv_offset)); - } - else { - select = true; - } - - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - iterv_curr = uv_select_edgeloop_vertex_map_get(vmap, efa, l); - - if (iterv_curr->flag) { - uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); - } - } - } - - /* cleanup */ - BM_uv_vert_map_free(vmap); - - return (select) ? 1 : -1; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Select Linked - * \{ */ - -static void uv_select_linked_multi(Scene *scene, - Object **objects, - const uint objects_len, - const float limit[2], - UvNearestHit *hit_final, - bool extend, - bool deselect, - bool toggle, - bool select_faces) -{ - /* loop over objects, or just use hit_final->ob */ - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - if (hit_final && ob_index != 0) { - break; - } - Object *obedit = hit_final ? hit_final->ob : objects[ob_index]; - - BMFace *efa; - BMLoop *l; - BMIter iter, liter; - MLoopUV *luv; - UvVertMap *vmap; - UvMapVert *vlist, *iterv, *startv; - int i, stacksize = 0, *stack; - uint a; - char *flag; - - BMEditMesh *em = BKE_editmesh_from_object(obedit); - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - - BM_mesh_elem_table_ensure(em->bm, BM_FACE); /* we can use this too */ - - /* Note, we had 'use winding' so we don't consider overlapping islands as connected, see T44320 - * this made *every* projection split the island into front/back islands. - * Keep 'use_winding' to false, see: T50970. - * - * Better solve this by having a delimit option for select-linked operator, - * keeping island-select working as is. */ - vmap = BM_uv_vert_map_create(em->bm, limit, !select_faces, false); - - if (vmap == NULL) { - continue; - } - - stack = MEM_mallocN(sizeof(*stack) * (em->bm->totface + 1), "UvLinkStack"); - flag = MEM_callocN(sizeof(*flag) * em->bm->totface, "UvLinkFlag"); - - if (hit_final == NULL) { - /* Use existing selection */ - BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) { - if (uvedit_face_visible_test(scene, efa)) { - if (select_faces) { - if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) { - stack[stacksize] = a; - stacksize++; - flag[a] = 1; - } - } - else { - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - - if (luv->flag & MLOOPUV_VERTSEL) { - stack[stacksize] = a; - stacksize++; - flag[a] = 1; - - break; - } - } - } - } - } - } - else { - BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) { - if (efa == hit_final->efa) { - stack[stacksize] = a; - stacksize++; - flag[a] = 1; - break; - } - } - } - - while (stacksize > 0) { - - stacksize--; - a = stack[stacksize]; - - efa = BM_face_at_index(em->bm, a); - - BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) { - - /* make_uv_vert_map_EM sets verts tmp.l to the indices */ - vlist = BM_uv_vert_map_at_index(vmap, BM_elem_index_get(l->v)); - - startv = vlist; - - for (iterv = vlist; iterv; iterv = iterv->next) { - if (iterv->separate) { - startv = iterv; - } - if (iterv->poly_index == a) { - break; - } - } - - for (iterv = startv; iterv; iterv = iterv->next) { - if ((startv != iterv) && (iterv->separate)) { - break; - } - else if (!flag[iterv->poly_index]) { - flag[iterv->poly_index] = 1; - stack[stacksize] = iterv->poly_index; - stacksize++; - } - } - } - } - - /* Toggling - if any of the linked vertices is selected (and visible), we deselect. */ - if ((toggle == true) && (extend == false) && (deselect == false)) { - BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) { - bool found_selected = false; - if (!flag[a]) { - continue; - } - - if (select_faces) { - if (BM_elem_flag_test(efa, BM_ELEM_SELECT) && !BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { - found_selected = true; - } - } - else { - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - - if (luv->flag & MLOOPUV_VERTSEL) { - found_selected = true; - } - } - - if (found_selected) { - deselect = true; - break; - } - } - } - } - -#define SET_SELECTION(value) \ - if (select_faces) { \ - BM_face_select_set(em->bm, efa, value); \ - } \ - else { \ - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { \ - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); \ - luv->flag = (value) ? (luv->flag | MLOOPUV_VERTSEL) : (luv->flag & ~MLOOPUV_VERTSEL); \ - } \ - } \ - (void)0 - - BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) { - if (!flag[a]) { - if (!extend && !deselect && !toggle) { - SET_SELECTION(false); - } - continue; - } - - if (!deselect) { - SET_SELECTION(true); - } - else { - SET_SELECTION(false); - } - } - -#undef SET_SELECTION - - MEM_freeN(stack); - MEM_freeN(flag); - BM_uv_vert_map_free(vmap); - } -} - -/* WATCH IT: this returns first selected UV, - * not ideal in many cases since there could be multiple */ -static float *uv_sel_co_from_eve(Scene *scene, BMEditMesh *em, BMVert *eve) -{ - BMIter liter; - BMLoop *l; - - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - - BM_ITER_ELEM (l, &liter, eve, BM_LOOPS_OF_VERT) { - if (!uvedit_face_visible_test(scene, l->f)) { - continue; - } - - if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { - MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - return luv->uv; - } - } - - return NULL; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Select More/Less Operator - * \{ */ - -static int uv_select_more_less(bContext *C, const bool select) -{ - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - SpaceImage *sima = CTX_wm_space_image(C); - - BMFace *efa; - BMLoop *l; - BMIter iter, liter; - const ToolSettings *ts = scene->toolsettings; - - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( - view_layer, ((View3D *)NULL), &objects_len); - - const bool is_uv_face_selectmode = (ts->uv_selectmode == UV_SELECT_FACE); - - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - - bool changed = false; - - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - - if (ts->uv_flag & UV_SYNC_SELECTION) { - if (select) { - EDBM_select_more(em, true); - } - else { - EDBM_select_less(em, true); - } - - DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); - continue; - } - - if (is_uv_face_selectmode) { - - /* clear tags */ - BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false); - - /* mark loops to be selected */ - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (uvedit_face_visible_test(scene, efa)) { - -#define IS_SEL 1 -#define IS_UNSEL 2 - - int sel_state = 0; - - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - if (luv->flag & MLOOPUV_VERTSEL) { - sel_state |= IS_SEL; - } - else { - sel_state |= IS_UNSEL; - } - - /* if we have a mixed selection, tag to grow it */ - if (sel_state == (IS_SEL | IS_UNSEL)) { - BM_elem_flag_enable(efa, BM_ELEM_TAG); - changed = true; - break; - } - } - -#undef IS_SEL -#undef IS_UNSEL - } - } - } - else { - - /* clear tags */ - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - BM_elem_flag_disable(l, BM_ELEM_TAG); - } - } - - /* mark loops to be selected */ - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (uvedit_face_visible_test(scene, efa)) { - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - - MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - - if (((luv->flag & MLOOPUV_VERTSEL) != 0) == select) { - BM_elem_flag_enable(l->next, BM_ELEM_TAG); - BM_elem_flag_enable(l->prev, BM_ELEM_TAG); - changed = true; - } - } - } - } - } - - if (changed) { - if (is_uv_face_selectmode) { - /* Select tagged faces. */ - uv_select_flush_from_tag_face(sima, scene, obedit, select); - } - else { - /* Select tagged loops. */ - uv_select_flush_from_tag_loop(sima, scene, obedit, select); - } - DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); - } - } - MEM_freeN(objects); - - return OPERATOR_FINISHED; -} - -static int uv_select_more_exec(bContext *C, wmOperator *UNUSED(op)) -{ - return uv_select_more_less(C, true); -} - -static void UV_OT_select_more(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Select More"; - ot->description = "Select more UV vertices connected to initial selection"; - ot->idname = "UV_OT_select_more"; - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* api callbacks */ - ot->exec = uv_select_more_exec; - ot->poll = ED_operator_uvedit_space_image; -} - -static int uv_select_less_exec(bContext *C, wmOperator *UNUSED(op)) -{ - return uv_select_more_less(C, false); -} - -static void UV_OT_select_less(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Select Less"; - ot->description = "Deselect UV vertices at the boundary of each selection region"; - ot->idname = "UV_OT_select_less"; - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* api callbacks */ - ot->exec = uv_select_less_exec; - ot->poll = ED_operator_uvedit_space_image; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ /** \name Weld Align Operator * \{ */ @@ -1822,9 +609,10 @@ static void uv_weld_align(bContext *C, eUVWeldAlign tool) if (BLI_array_len(eve_line) > 2) { /* we know the returns from these must be valid */ - const float *uv_start = uv_sel_co_from_eve(scene, em, eve_line[0]); - const float *uv_end = uv_sel_co_from_eve( - scene, em, eve_line[BLI_array_len(eve_line) - 1]); + const float *uv_start = uvedit_first_selected_uv_from_vertex( + scene, eve_line[0], cd_loop_uv_offset); + const float *uv_end = uvedit_first_selected_uv_from_vertex( + scene, eve_line[BLI_array_len(eve_line) - 1], cd_loop_uv_offset); /* For UV_STRAIGHTEN_X & UV_STRAIGHTEN_Y modes */ float a = 0.0f; eUVWeldAlign tool_local = tool; @@ -2270,1654 +1058,6 @@ static void UV_OT_weld(wmOperatorType *ot) /** \} */ /* -------------------------------------------------------------------- */ -/** \name (De)Select All Operator - * \{ */ - -static bool uv_select_is_any_selected(Scene *scene, Object *obedit) -{ - const ToolSettings *ts = scene->toolsettings; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMFace *efa; - BMLoop *l; - BMIter iter, liter; - MLoopUV *luv; - - if (ts->uv_flag & UV_SYNC_SELECTION) { - return (em->bm->totvertsel || em->bm->totedgesel || em->bm->totfacesel); - } - else { - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, efa)) { - continue; - } - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - if (luv->flag & MLOOPUV_VERTSEL) { - return true; - } - } - } - } - return false; -} - -static bool uv_select_is_any_selected_multi(Scene *scene, Object **objects, const uint objects_len) -{ - bool found = false; - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - if (uv_select_is_any_selected(scene, obedit)) { - found = true; - break; - } - } - return found; -} - -static void uv_select_all_perform(Scene *scene, Object *obedit, int action) -{ - const ToolSettings *ts = scene->toolsettings; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMFace *efa; - BMLoop *l; - BMIter iter, liter; - MLoopUV *luv; - - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - - if (action == SEL_TOGGLE) { - action = uv_select_is_any_selected(scene, obedit) ? SEL_DESELECT : SEL_SELECT; - } - - if (ts->uv_flag & UV_SYNC_SELECTION) { - switch (action) { - case SEL_TOGGLE: - EDBM_select_toggle_all(em); - break; - case SEL_SELECT: - EDBM_flag_enable_all(em, BM_ELEM_SELECT); - break; - case SEL_DESELECT: - EDBM_flag_disable_all(em, BM_ELEM_SELECT); - break; - case SEL_INVERT: - EDBM_select_swap(em); - EDBM_selectmode_flush(em); - break; - } - } - else { - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, efa)) { - continue; - } - - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - - switch (action) { - case SEL_SELECT: - luv->flag |= MLOOPUV_VERTSEL; - break; - case SEL_DESELECT: - luv->flag &= ~MLOOPUV_VERTSEL; - break; - case SEL_INVERT: - luv->flag ^= MLOOPUV_VERTSEL; - break; - } - } - } - } -} - -static void uv_select_all_perform_multi(Scene *scene, - Object **objects, - const uint objects_len, - int action) -{ - if (action == SEL_TOGGLE) { - action = uv_select_is_any_selected_multi(scene, objects, objects_len) ? SEL_DESELECT : - SEL_SELECT; - } - - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - uv_select_all_perform(scene, obedit, action); - } -} - -static int uv_select_all_exec(bContext *C, wmOperator *op) -{ - Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); - Scene *scene = CTX_data_scene(C); - const ToolSettings *ts = scene->toolsettings; - ViewLayer *view_layer = CTX_data_view_layer(C); - - int action = RNA_enum_get(op->ptr, "action"); - - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( - view_layer, ((View3D *)NULL), &objects_len); - - uv_select_all_perform_multi(scene, objects, objects_len, action); - - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - uv_select_tag_update_for_object(depsgraph, ts, obedit); - } - - MEM_freeN(objects); - - return OPERATOR_FINISHED; -} - -static void UV_OT_select_all(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "(De)select All"; - ot->description = "Change selection of all UV vertices"; - ot->idname = "UV_OT_select_all"; - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* api callbacks */ - ot->exec = uv_select_all_exec; - ot->poll = ED_operator_uvedit; - - WM_operator_properties_select_all(ot); -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Mouse Select Operator - * \{ */ - -static bool uv_sticky_select( - float *limit, int hitv[], int v, float *hituv[], float *uv, int sticky, int hitlen) -{ - int i; - - /* this function test if some vertex needs to selected - * in addition to the existing ones due to sticky select */ - if (sticky == SI_STICKY_DISABLE) { - return false; - } - - for (i = 0; i < hitlen; i++) { - if (hitv[i] == v) { - if (sticky == SI_STICKY_LOC) { - if (fabsf(hituv[i][0] - uv[0]) < limit[0] && fabsf(hituv[i][1] - uv[1]) < limit[1]) { - return true; - } - } - else if (sticky == SI_STICKY_VERTEX) { - return true; - } - } - } - - return false; -} - -static int uv_mouse_select_multi(bContext *C, - Object **objects, - uint objects_len, - const float co[2], - const bool extend, - const bool deselect_all, - const bool loop) -{ - Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); - SpaceImage *sima = CTX_wm_space_image(C); - Scene *scene = CTX_data_scene(C); - const ToolSettings *ts = scene->toolsettings; - BMFace *efa; - BMLoop *l; - BMIter iter, liter; - MLoopUV *luv; - UvNearestHit hit = UV_NEAREST_HIT_INIT; - int i, selectmode, sticky, sync, *hitv = NULL; - bool select = true; - bool found_item = false; - /* 0 == don't flush, 1 == sel, -1 == desel; only use when selection sync is enabled */ - int flush = 0; - int hitlen = 0; - float limit[2], **hituv = NULL; - - /* notice 'limit' is the same no matter the zoom level, since this is like - * remove doubles and could annoying if it joined points when zoomed out. - * 'penalty' is in screen pixel space otherwise zooming in on a uv-vert and - * shift-selecting can consider an adjacent point close enough to add to - * the selection rather than de-selecting the closest. */ - - float penalty_dist; - { - float penalty[2]; - uvedit_pixel_to_float(sima, limit, 0.05f); - uvedit_pixel_to_float(sima, penalty, 5.0f / (sima ? sima->zoom : 1.0f)); - penalty_dist = len_v2(penalty); - } - - /* retrieve operation mode */ - if (ts->uv_flag & UV_SYNC_SELECTION) { - sync = 1; - - if (ts->selectmode & SCE_SELECT_FACE) { - selectmode = UV_SELECT_FACE; - } - else if (ts->selectmode & SCE_SELECT_EDGE) { - selectmode = UV_SELECT_EDGE; - } - else { - selectmode = UV_SELECT_VERTEX; - } - - sticky = SI_STICKY_DISABLE; - } - else { - sync = 0; - selectmode = ts->uv_selectmode; - sticky = (sima) ? sima->sticky : 1; - } - - /* find nearest element */ - if (loop) { - /* find edge */ - found_item = uv_find_nearest_edge_multi(scene, objects, objects_len, co, &hit); - } - else if (selectmode == UV_SELECT_VERTEX) { - /* find vertex */ - found_item = uv_find_nearest_vert_multi(scene, objects, objects_len, co, penalty_dist, &hit); - found_item = found_item && (!deselect_all || hit.dist_sq < penalty_dist); - - if (found_item) { - /* mark 1 vertex as being hit */ - hitv = BLI_array_alloca(hitv, hit.efa->len); - hituv = BLI_array_alloca(hituv, hit.efa->len); - copy_vn_i(hitv, hit.efa->len, 0xFFFFFFFF); - - hitv[hit.lindex] = BM_elem_index_get(hit.l->v); - hituv[hit.lindex] = hit.luv->uv; - - hitlen = hit.efa->len; - } - } - else if (selectmode == UV_SELECT_EDGE) { - /* find edge */ - found_item = uv_find_nearest_edge_multi(scene, objects, objects_len, co, &hit); - found_item = found_item && (!deselect_all || hit.dist_sq < penalty_dist); - - if (found_item) { - /* mark 2 edge vertices as being hit */ - hitv = BLI_array_alloca(hitv, hit.efa->len); - hituv = BLI_array_alloca(hituv, hit.efa->len); - copy_vn_i(hitv, hit.efa->len, 0xFFFFFFFF); - - hitv[hit.lindex] = BM_elem_index_get(hit.l->v); - hitv[(hit.lindex + 1) % hit.efa->len] = BM_elem_index_get(hit.l->next->v); - hituv[hit.lindex] = hit.luv->uv; - hituv[(hit.lindex + 1) % hit.efa->len] = hit.luv_next->uv; - - hitlen = hit.efa->len; - } - } - else if (selectmode == UV_SELECT_FACE) { - /* find face */ - found_item = uv_find_nearest_face_multi(scene, objects, objects_len, co, &hit); - found_item = found_item && (!deselect_all || hit.dist_sq < penalty_dist); - - if (found_item) { - BMEditMesh *em = BKE_editmesh_from_object(hit.ob); - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - - /* make active */ - BM_mesh_active_face_set(em->bm, hit.efa); - - /* mark all face vertices as being hit */ - - hitv = BLI_array_alloca(hitv, hit.efa->len); - hituv = BLI_array_alloca(hituv, hit.efa->len); - BM_ITER_ELEM_INDEX (l, &liter, hit.efa, BM_LOOPS_OF_FACE, i) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - hituv[i] = luv->uv; - hitv[i] = BM_elem_index_get(l->v); - } - - hitlen = hit.efa->len; - } - } - else if (selectmode == UV_SELECT_ISLAND) { - found_item = uv_find_nearest_edge_multi(scene, objects, objects_len, co, &hit); - found_item = found_item && (!deselect_all || hit.dist_sq < penalty_dist); - } - - if (!found_item) { - if (deselect_all) { - uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT); - - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - uv_select_tag_update_for_object(depsgraph, ts, obedit); - } - - return OPERATOR_PASS_THROUGH | OPERATOR_FINISHED; - } - return OPERATOR_CANCELLED; - } - - Object *obedit = hit.ob; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - - /* do selection */ - if (loop) { - if (!extend) { - /* TODO(MULTI_EDIT): We only need to de-select non-active */ - uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT); - } - flush = uv_select_edgeloop(scene, obedit, &hit, limit, extend); - } - else if (selectmode == UV_SELECT_ISLAND) { - if (!extend) { - /* TODO(MULTI_EDIT): We only need to de-select non-active */ - uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT); - } - /* Current behavior of 'extend' - * is actually toggling, so pass extend flag as 'toggle' here */ - uv_select_linked_multi(scene, objects, objects_len, limit, &hit, false, false, extend, false); - } - else if (extend) { - if (selectmode == UV_SELECT_VERTEX) { - /* (de)select uv vertex */ - select = !uvedit_uv_select_test(scene, hit.l, cd_loop_uv_offset); - uvedit_uv_select_set(em, scene, hit.l, select, true, cd_loop_uv_offset); - flush = 1; - } - else if (selectmode == UV_SELECT_EDGE) { - /* (de)select edge */ - select = !(uvedit_edge_select_test(scene, hit.l, cd_loop_uv_offset)); - uvedit_edge_select_set(em, scene, hit.l, select, true, cd_loop_uv_offset); - flush = 1; - } - else if (selectmode == UV_SELECT_FACE) { - /* (de)select face */ - select = !(uvedit_face_select_test(scene, hit.efa, cd_loop_uv_offset)); - uvedit_face_select_set(scene, em, hit.efa, select, true, cd_loop_uv_offset); - flush = -1; - } - - /* de-selecting an edge may deselect a face too - validate */ - if (sync) { - if (select == false) { - BM_select_history_validate(em->bm); - } - } - - /* (de)select sticky uv nodes */ - if (sticky != SI_STICKY_DISABLE) { - - BM_mesh_elem_index_ensure(em->bm, BM_VERT); - - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, efa)) { - continue; - } - - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - if (uv_sticky_select( - limit, hitv, BM_elem_index_get(l->v), hituv, luv->uv, sticky, hitlen)) { - uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); - } - } - } - - flush = select ? 1 : -1; - } - } - else { - /* deselect all */ - uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT); - - if (selectmode == UV_SELECT_VERTEX) { - /* select vertex */ - uvedit_uv_select_enable(em, scene, hit.l, true, cd_loop_uv_offset); - flush = 1; - } - else if (selectmode == UV_SELECT_EDGE) { - /* select edge */ - uvedit_edge_select_enable(em, scene, hit.l, true, cd_loop_uv_offset); - flush = 1; - } - else if (selectmode == UV_SELECT_FACE) { - /* select face */ - uvedit_face_select_enable(scene, em, hit.efa, true, cd_loop_uv_offset); - } - - /* select sticky uvs */ - if (sticky != SI_STICKY_DISABLE) { - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, efa)) { - continue; - } - - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - if (sticky == SI_STICKY_DISABLE) { - continue; - } - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - - if (uv_sticky_select( - limit, hitv, BM_elem_index_get(l->v), hituv, luv->uv, sticky, hitlen)) { - uvedit_uv_select_enable(em, scene, l, false, cd_loop_uv_offset); - } - - flush = 1; - } - } - } - } - - if (sync) { - /* flush for mesh selection */ - - /* before bmesh */ -#if 0 - if (ts->selectmode != SCE_SELECT_FACE) { - if (flush == 1) { - EDBM_select_flush(em); - } - else if (flush == -1) { - EDBM_deselect_flush(em); - } - } -#else - if (flush != 0) { - if (loop) { - /* push vertex -> edge selection */ - if (select) { - EDBM_select_flush(em); - } - else { - EDBM_deselect_flush(em); - } - } - else { - EDBM_selectmode_flush(em); - } - } -#endif - } - - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obiter = objects[ob_index]; - uv_select_tag_update_for_object(depsgraph, ts, obiter); - } - - return OPERATOR_PASS_THROUGH | OPERATOR_FINISHED; -} -static int uv_mouse_select( - bContext *C, const float co[2], const bool extend, const bool deselect_all, const bool loop) -{ - 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_with_uvs( - view_layer, ((View3D *)NULL), &objects_len); - int ret = uv_mouse_select_multi(C, objects, objects_len, co, extend, deselect_all, loop); - MEM_freeN(objects); - return ret; -} - -static int uv_select_exec(bContext *C, wmOperator *op) -{ - float co[2]; - - RNA_float_get_array(op->ptr, "location", co); - const bool extend = RNA_boolean_get(op->ptr, "extend"); - const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all"); - const bool loop = false; - - return uv_mouse_select(C, co, extend, deselect_all, loop); -} - -static int uv_select_invoke(bContext *C, wmOperator *op, const wmEvent *event) -{ - ARegion *region = CTX_wm_region(C); - float co[2]; - - UI_view2d_region_to_view(®ion->v2d, event->mval[0], event->mval[1], &co[0], &co[1]); - RNA_float_set_array(op->ptr, "location", co); - - return uv_select_exec(C, op); -} - -static void UV_OT_select(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Select"; - ot->description = "Select UV vertices"; - ot->idname = "UV_OT_select"; - ot->flag = OPTYPE_UNDO; - - /* api callbacks */ - ot->exec = uv_select_exec; - ot->invoke = uv_select_invoke; - ot->poll = ED_operator_uvedit; /* requires space image */ - - /* properties */ - PropertyRNA *prop; - RNA_def_boolean(ot->srna, - "extend", - 0, - "Extend", - "Extend selection rather than clearing the existing selection"); - prop = RNA_def_boolean(ot->srna, - "deselect_all", - false, - "Deselect On Nothing", - "Deselect all when nothing under the cursor"); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); - - RNA_def_float_vector( - ot->srna, - "location", - 2, - NULL, - -FLT_MAX, - FLT_MAX, - "Location", - "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds", - -100.0f, - 100.0f); -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Loop Select Operator - * \{ */ - -static int uv_select_loop_exec(bContext *C, wmOperator *op) -{ - float co[2]; - - RNA_float_get_array(op->ptr, "location", co); - const bool extend = RNA_boolean_get(op->ptr, "extend"); - const bool deselect_all = false; - const bool loop = true; - - return uv_mouse_select(C, co, extend, deselect_all, loop); -} - -static int uv_select_loop_invoke(bContext *C, wmOperator *op, const wmEvent *event) -{ - ARegion *region = CTX_wm_region(C); - float co[2]; - - UI_view2d_region_to_view(®ion->v2d, event->mval[0], event->mval[1], &co[0], &co[1]); - RNA_float_set_array(op->ptr, "location", co); - - return uv_select_loop_exec(C, op); -} - -static void UV_OT_select_loop(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Loop Select"; - ot->description = "Select a loop of connected UV vertices"; - ot->idname = "UV_OT_select_loop"; - ot->flag = OPTYPE_UNDO; - - /* api callbacks */ - ot->exec = uv_select_loop_exec; - ot->invoke = uv_select_loop_invoke; - ot->poll = ED_operator_uvedit; /* requires space image */ - - /* properties */ - RNA_def_boolean(ot->srna, - "extend", - 0, - "Extend", - "Extend selection rather than clearing the existing selection"); - RNA_def_float_vector( - ot->srna, - "location", - 2, - NULL, - -FLT_MAX, - FLT_MAX, - "Location", - "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds", - -100.0f, - 100.0f); -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Select Linked Operator - * \{ */ - -static int uv_select_linked_internal(bContext *C, wmOperator *op, const wmEvent *event, bool pick) -{ - SpaceImage *sima = CTX_wm_space_image(C); - Scene *scene = CTX_data_scene(C); - const ToolSettings *ts = scene->toolsettings; - ViewLayer *view_layer = CTX_data_view_layer(C); - float limit[2]; - bool extend = true; - bool deselect = false; - bool select_faces = (ts->uv_flag & UV_SYNC_SELECTION) && (ts->selectmode & SCE_SELECT_FACE); - - UvNearestHit hit = UV_NEAREST_HIT_INIT; - - if ((ts->uv_flag & UV_SYNC_SELECTION) && !(ts->selectmode & SCE_SELECT_FACE)) { - BKE_report(op->reports, - RPT_ERROR, - "Select linked only works in face select mode when sync selection is enabled"); - return OPERATOR_CANCELLED; - } - - if (pick) { - extend = RNA_boolean_get(op->ptr, "extend"); - deselect = RNA_boolean_get(op->ptr, "deselect"); - } - uvedit_pixel_to_float(sima, limit, 0.05f); - - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( - view_layer, ((View3D *)NULL), &objects_len); - - if (pick) { - float co[2]; - - if (event) { - /* invoke */ - ARegion *region = CTX_wm_region(C); - - UI_view2d_region_to_view(®ion->v2d, event->mval[0], event->mval[1], &co[0], &co[1]); - RNA_float_set_array(op->ptr, "location", co); - } - else { - /* exec */ - RNA_float_get_array(op->ptr, "location", co); - } - - if (!uv_find_nearest_edge_multi(scene, objects, objects_len, co, &hit)) { - MEM_freeN(objects); - return OPERATOR_CANCELLED; - } - } - - if (!extend) { - uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT); - } - - uv_select_linked_multi(scene, - objects, - objects_len, - limit, - pick ? &hit : NULL, - extend, - deselect, - false, - select_faces); - - /* weak!, but works */ - Object **objects_free = objects; - if (pick) { - objects = &hit.ob; - objects_len = 1; - } - - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - DEG_id_tag_update(obedit->data, ID_RECALC_COPY_ON_WRITE | ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); - } - - MEM_SAFE_FREE(objects_free); - - return OPERATOR_FINISHED; -} - -static int uv_select_linked_exec(bContext *C, wmOperator *op) -{ - return uv_select_linked_internal(C, op, NULL, false); -} - -static void UV_OT_select_linked(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Select Linked"; - ot->description = "Select all UV vertices linked to the active UV map"; - ot->idname = "UV_OT_select_linked"; - - /* api callbacks */ - ot->exec = uv_select_linked_exec; - ot->poll = ED_operator_uvedit; /* requires space image */ - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Select Linked (Cursor Pick) Operator - * \{ */ - -static int uv_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event) -{ - return uv_select_linked_internal(C, op, event, true); -} - -static int uv_select_linked_pick_exec(bContext *C, wmOperator *op) -{ - return uv_select_linked_internal(C, op, NULL, true); -} - -static void UV_OT_select_linked_pick(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Select Linked Pick"; - ot->description = "Select all UV vertices linked under the mouse"; - ot->idname = "UV_OT_select_linked_pick"; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* api callbacks */ - ot->invoke = uv_select_linked_pick_invoke; - ot->exec = uv_select_linked_pick_exec; - ot->poll = ED_operator_uvedit; /* requires space image */ - - /* properties */ - RNA_def_boolean(ot->srna, - "extend", - 0, - "Extend", - "Extend selection rather than clearing the existing selection"); - RNA_def_boolean(ot->srna, - "deselect", - 0, - "Deselect", - "Deselect linked UV vertices rather than selecting them"); - RNA_def_float_vector( - ot->srna, - "location", - 2, - NULL, - -FLT_MAX, - FLT_MAX, - "Location", - "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds", - -100.0f, - 100.0f); -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Select Split Operator - * \{ */ - -/** - * \note This is based on similar use case to #MESH_OT_split(), which has a similar effect - * but in this case they are not joined to begin with (only having the behavior of being joined) - * so its best to call this #uv_select_split() instead of just split(), but assigned to the same - * key as #MESH_OT_split - Campbell. - */ -static int uv_select_split_exec(bContext *C, wmOperator *op) -{ - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - const ToolSettings *ts = scene->toolsettings; - - BMFace *efa; - BMLoop *l; - BMIter iter, liter; - MLoopUV *luv; - - if (ts->uv_flag & UV_SYNC_SELECTION) { - BKE_report(op->reports, RPT_ERROR, "Cannot split selection when sync selection is enabled"); - return OPERATOR_CANCELLED; - } - - bool changed_multi = false; - - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( - view_layer, ((View3D *)NULL), &objects_len); - - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMesh *bm = BKE_editmesh_from_object(obedit)->bm; - - bool changed = false; - - const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); - - BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { - bool is_sel = false; - bool is_unsel = false; - - if (!uvedit_face_visible_test(scene, efa)) { - continue; - } - - /* are we all selected? */ - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - - if (luv->flag & MLOOPUV_VERTSEL) { - is_sel = true; - } - else { - is_unsel = true; - } - - /* we have mixed selection, bail out */ - if (is_sel && is_unsel) { - break; - } - } - - if (is_sel && is_unsel) { - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - luv->flag &= ~MLOOPUV_VERTSEL; - } - - changed = true; - } - } - - if (changed) { - changed_multi = true; - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_IMAGE, NULL); - } - } - MEM_freeN(objects); - - return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED; -} - -static void UV_OT_select_split(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Select Split"; - ot->description = "Select only entirely selected faces"; - ot->idname = "UV_OT_select_split"; - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* api callbacks */ - ot->exec = uv_select_split_exec; - ot->poll = ED_operator_uvedit; /* requires space image */ -} - -static void uv_select_sync_flush(const ToolSettings *ts, BMEditMesh *em, const short select) -{ - /* bmesh API handles flushing but not on de-select */ - if (ts->uv_flag & UV_SYNC_SELECTION) { - if (ts->selectmode != SCE_SELECT_FACE) { - if (select == false) { - EDBM_deselect_flush(em); - } - else { - EDBM_select_flush(em); - } - } - - if (select == false) { - BM_select_history_validate(em->bm); - } - } -} - -static void uv_select_tag_update_for_object(Depsgraph *depsgraph, - const ToolSettings *ts, - Object *obedit) -{ - if (ts->uv_flag & UV_SYNC_SELECTION) { - DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); - WM_main_add_notifier(NC_GEOM | ND_SELECT, obedit->data); - } - else { - Object *obedit_eval = DEG_get_evaluated_object(depsgraph, obedit); - BKE_mesh_batch_cache_dirty_tag(obedit_eval->data, BKE_MESH_BATCH_DIRTY_UVEDIT_SELECT); - /* Only for region redraw. */ - WM_main_add_notifier(NC_GEOM | ND_SELECT, obedit->data); - } -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Select/Tag Flushing Utils - * - * Utility functions to flush the uv-selection from tags. - * \{ */ - -/** - * helper function for #uv_select_flush_from_tag_loop and uv_select_flush_from_tag_face - */ -static void uv_select_flush_from_tag_sticky_loc_internal(Scene *scene, - BMEditMesh *em, - UvVertMap *vmap, - const uint efa_index, - BMLoop *l, - const bool select, - const int cd_loop_uv_offset) -{ - UvMapVert *start_vlist = NULL, *vlist_iter; - BMFace *efa_vlist; - - uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); - - vlist_iter = BM_uv_vert_map_at_index(vmap, BM_elem_index_get(l->v)); - - while (vlist_iter) { - if (vlist_iter->separate) { - start_vlist = vlist_iter; - } - - if (efa_index == vlist_iter->poly_index) { - break; - } - - vlist_iter = vlist_iter->next; - } - - vlist_iter = start_vlist; - while (vlist_iter) { - - if (vlist_iter != start_vlist && vlist_iter->separate) { - break; - } - - if (efa_index != vlist_iter->poly_index) { - BMLoop *l_other; - efa_vlist = BM_face_at_index(em->bm, vlist_iter->poly_index); - /* tf_vlist = BM_ELEM_CD_GET_VOID_P(efa_vlist, cd_poly_tex_offset); */ /* UNUSED */ - - l_other = BM_iter_at_index( - em->bm, BM_LOOPS_OF_FACE, efa_vlist, vlist_iter->loop_of_poly_index); - - uvedit_uv_select_set(em, scene, l_other, select, false, cd_loop_uv_offset); - } - vlist_iter = vlist_iter->next; - } -} - -/** - * Flush the selection from face tags based on sticky and selection modes. - * - * needed because settings the selection a face is done in a number of places but it also - * needs to respect the sticky modes for the UV verts, so dealing with the sticky modes - * is best done in a separate function. - * - * \note This function is very similar to #uv_select_flush_from_tag_loop, - * be sure to update both upon changing. - */ -static void uv_select_flush_from_tag_face(SpaceImage *sima, - Scene *scene, - Object *obedit, - const bool select) -{ - /* Selecting UV Faces with some modes requires us to change - * the selection in other faces (depending on the sticky mode). - * - * This only needs to be done when the Mesh is not used for - * selection (so for sticky modes, vertex or location based). */ - - const ToolSettings *ts = scene->toolsettings; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMFace *efa; - BMLoop *l; - BMIter iter, liter; - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - - if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && sima->sticky == SI_STICKY_VERTEX) { - /* Tag all verts as untouched, then touch the ones that have a face center - * in the loop and select all MLoopUV's that use a touched vert. */ - BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false); - - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (BM_elem_flag_test(efa, BM_ELEM_TAG)) { - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - BM_elem_flag_enable(l->v, BM_ELEM_TAG); - } - } - } - - /* now select tagged verts */ - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */ - - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) { - uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); - } - } - } - } - else if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && sima->sticky == SI_STICKY_LOC) { - struct UvVertMap *vmap; - float limit[2]; - uint efa_index; - - uvedit_pixel_to_float(sima, limit, 0.05); - - BM_mesh_elem_table_ensure(em->bm, BM_FACE); - vmap = BM_uv_vert_map_create(em->bm, limit, false, false); - if (vmap == NULL) { - return; - } - - BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, efa_index) { - if (BM_elem_flag_test(efa, BM_ELEM_TAG)) { - /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */ - - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - uv_select_flush_from_tag_sticky_loc_internal( - scene, em, vmap, efa_index, l, select, cd_loop_uv_offset); - } - } - } - BM_uv_vert_map_free(vmap); - } - else { /* SI_STICKY_DISABLE or ts->uv_flag & UV_SYNC_SELECTION */ - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (BM_elem_flag_test(efa, BM_ELEM_TAG)) { - uvedit_face_select_set(scene, em, efa, select, false, cd_loop_uv_offset); - } - } - } -} - -/** - * Flush the selection from loop tags based on sticky and selection modes. - * - * needed because settings the selection a face is done in a number of places but it also needs - * to respect the sticky modes for the UV verts, so dealing with the sticky modes is best done - * in a separate function. - * - * \note This function is very similar to #uv_select_flush_from_tag_loop, - * be sure to update both upon changing. - */ -static void uv_select_flush_from_tag_loop(SpaceImage *sima, - Scene *scene, - Object *obedit, - const bool select) -{ - /* Selecting UV Loops with some modes requires us to change - * the selection in other faces (depending on the sticky mode). - * - * This only needs to be done when the Mesh is not used for - * selection (so for sticky modes, vertex or location based). */ - - const ToolSettings *ts = scene->toolsettings; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMFace *efa; - BMLoop *l; - BMIter iter, liter; - - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - - if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && sima->sticky == SI_STICKY_VERTEX) { - /* Tag all verts as untouched, then touch the ones that have a face center - * in the loop and select all MLoopUV's that use a touched vert. */ - BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false); - - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - if (BM_elem_flag_test(l, BM_ELEM_TAG)) { - BM_elem_flag_enable(l->v, BM_ELEM_TAG); - } - } - } - - /* now select tagged verts */ - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */ - - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) { - uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); - } - } - } - } - else if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && sima->sticky == SI_STICKY_LOC) { - struct UvVertMap *vmap; - float limit[2]; - uint efa_index; - - uvedit_pixel_to_float(sima, limit, 0.05); - - BM_mesh_elem_table_ensure(em->bm, BM_FACE); - vmap = BM_uv_vert_map_create(em->bm, limit, false, false); - if (vmap == NULL) { - return; - } - - BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, efa_index) { - /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */ - - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - if (BM_elem_flag_test(l, BM_ELEM_TAG)) { - uv_select_flush_from_tag_sticky_loc_internal( - scene, em, vmap, efa_index, l, select, cd_loop_uv_offset); - } - } - } - BM_uv_vert_map_free(vmap); - } - else { /* SI_STICKY_DISABLE or ts->uv_flag & UV_SYNC_SELECTION */ - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - if (BM_elem_flag_test(l, BM_ELEM_TAG)) { - uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); - } - } - } - } -} - -/** \} */ - -#define UV_SELECT_ISLAND_LIMIT \ - float limit[2]; \ - uvedit_pixel_to_float(sima, limit, 0.05f) - -/* -------------------------------------------------------------------- */ -/** \name Box Select Operator - * \{ */ - -static int uv_box_select_exec(bContext *C, wmOperator *op) -{ - Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); - SpaceImage *sima = CTX_wm_space_image(C); - Scene *scene = CTX_data_scene(C); - const ToolSettings *ts = scene->toolsettings; - ViewLayer *view_layer = CTX_data_view_layer(C); - ARegion *region = CTX_wm_region(C); - BMFace *efa; - BMLoop *l; - BMIter iter, liter; - MLoopUV *luv; - rctf rectf; - bool pinned; - const bool use_face_center = ((ts->uv_flag & UV_SYNC_SELECTION) ? - (ts->selectmode == SCE_SELECT_FACE) : - (ts->uv_selectmode == UV_SELECT_FACE)); - - /* get rectangle from operator */ - WM_operator_properties_border_to_rctf(op, &rectf); - UI_view2d_region_to_view_rctf(®ion->v2d, &rectf, &rectf); - - const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode"); - const bool select = (sel_op != SEL_OP_SUB); - const bool use_pre_deselect = SEL_OP_USE_PRE_DESELECT(sel_op); - - pinned = RNA_boolean_get(op->ptr, "pinned"); - - UV_SELECT_ISLAND_LIMIT; - - bool changed_multi = false; - - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( - view_layer, ((View3D *)NULL), &objects_len); - - if (use_pre_deselect) { - uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT); - } - - /* don't indent to avoid diff noise! */ - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - - bool changed = false; - - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - - /* do actual selection */ - if (use_face_center && !pinned) { - /* handle face selection mode */ - float cent[2]; - - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - /* assume not touched */ - BM_elem_flag_disable(efa, BM_ELEM_TAG); - - if (uvedit_face_visible_test(scene, efa)) { - uv_poly_center(efa, cent, cd_loop_uv_offset); - if (BLI_rctf_isect_pt_v(&rectf, cent)) { - BM_elem_flag_enable(efa, BM_ELEM_TAG); - changed = true; - } - } - } - - /* (de)selects all tagged faces and deals with sticky modes */ - if (changed) { - uv_select_flush_from_tag_face(sima, scene, obedit, select); - } - } - else { - /* other selection modes */ - changed = true; - BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false); - - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, efa)) { - continue; - } - bool has_selected = false; - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - if ((select) != (uvedit_uv_select_test(scene, l, cd_loop_uv_offset))) { - if (!pinned || (ts->uv_flag & UV_SYNC_SELECTION)) { - /* UV_SYNC_SELECTION - can't do pinned selection */ - if (BLI_rctf_isect_pt_v(&rectf, luv->uv)) { - uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); - BM_elem_flag_enable(l->v, BM_ELEM_TAG); - has_selected = true; - } - } - else if (pinned) { - if ((luv->flag & MLOOPUV_PINNED) && BLI_rctf_isect_pt_v(&rectf, luv->uv)) { - uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); - BM_elem_flag_enable(l->v, BM_ELEM_TAG); - } - } - } - } - if (has_selected && ts->uv_selectmode == UV_SELECT_ISLAND) { - UvNearestHit hit = { - .ob = obedit, - .efa = efa, - }; - uv_select_linked_multi( - scene, objects, objects_len, limit, &hit, true, !select, false, false); - } - } - - if (sima->sticky == SI_STICKY_VERTEX) { - uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset); - } - } - - if (changed || use_pre_deselect) { - changed_multi = true; - - uv_select_sync_flush(ts, em, select); - uv_select_tag_update_for_object(depsgraph, ts, obedit); - } - } - - MEM_freeN(objects); - - return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED; -} - -static void UV_OT_select_box(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Box Select"; - ot->description = "Select UV vertices using box selection"; - ot->idname = "UV_OT_select_box"; - - /* api callbacks */ - ot->invoke = WM_gesture_box_invoke; - ot->exec = uv_box_select_exec; - ot->modal = WM_gesture_box_modal; - ot->poll = ED_operator_uvedit_space_image; /* requires space image */ - ot->cancel = WM_gesture_box_cancel; - - /* flags */ - ot->flag = OPTYPE_UNDO; - - /* properties */ - RNA_def_boolean(ot->srna, "pinned", 0, "Pinned", "Border select pinned UVs only"); - - WM_operator_properties_gesture_box(ot); - WM_operator_properties_select_operation_simple(ot); -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Circle Select Operator - * \{ */ - -static int uv_inside_circle(const float uv[2], const float offset[2], const float ellipse[2]) -{ - /* normalized ellipse: ell[0] = scaleX, ell[1] = scaleY */ - float x, y; - x = (uv[0] - offset[0]) * ellipse[0]; - y = (uv[1] - offset[1]) * ellipse[1]; - return ((x * x + y * y) < 1.0f); -} - -static int uv_circle_select_exec(bContext *C, wmOperator *op) -{ - Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); - SpaceImage *sima = CTX_wm_space_image(C); - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - const ToolSettings *ts = scene->toolsettings; - ARegion *region = CTX_wm_region(C); - BMFace *efa; - BMLoop *l; - BMIter iter, liter; - MLoopUV *luv; - int x, y, radius, width, height; - float zoomx, zoomy, offset[2], ellipse[2]; - - const bool use_face_center = ((ts->uv_flag & UV_SYNC_SELECTION) ? - (ts->selectmode == SCE_SELECT_FACE) : - (ts->uv_selectmode == UV_SELECT_FACE)); - - /* get operator properties */ - x = RNA_int_get(op->ptr, "x"); - y = RNA_int_get(op->ptr, "y"); - radius = RNA_int_get(op->ptr, "radius"); - - /* compute ellipse size and location, not a circle since we deal - * with non square image. ellipse is normalized, r = 1.0. */ - ED_space_image_get_size(sima, &width, &height); - ED_space_image_get_zoom(sima, region, &zoomx, &zoomy); - - ellipse[0] = width * zoomx / radius; - ellipse[1] = height * zoomy / radius; - - UI_view2d_region_to_view(®ion->v2d, x, y, &offset[0], &offset[1]); - - UV_SELECT_ISLAND_LIMIT; - - bool changed_multi = false; - - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( - view_layer, ((View3D *)NULL), &objects_len); - - const eSelectOp sel_op = ED_select_op_modal(RNA_enum_get(op->ptr, "mode"), - WM_gesture_is_modal_first(op->customdata)); - const bool select = (sel_op != SEL_OP_SUB); - const bool use_pre_deselect = SEL_OP_USE_PRE_DESELECT(sel_op); - - if (use_pre_deselect) { - uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT); - } - - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - - bool changed = false; - - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - - /* do selection */ - if (use_face_center) { - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - BM_elem_flag_disable(efa, BM_ELEM_TAG); - /* assume not touched */ - if (select != uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) { - float cent[2]; - uv_poly_center(efa, cent, cd_loop_uv_offset); - if (uv_inside_circle(cent, offset, ellipse)) { - BM_elem_flag_enable(efa, BM_ELEM_TAG); - changed = true; - } - } - } - - /* (de)selects all tagged faces and deals with sticky modes */ - if (changed) { - uv_select_flush_from_tag_face(sima, scene, obedit, select); - } - } - else { - BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false); - - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, efa)) { - continue; - } - bool has_selected = false; - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - if ((select) != (uvedit_uv_select_test(scene, l, cd_loop_uv_offset))) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - if (uv_inside_circle(luv->uv, offset, ellipse)) { - changed = true; - uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); - BM_elem_flag_enable(l->v, BM_ELEM_TAG); - has_selected = true; - } - } - } - if (has_selected && ts->uv_selectmode == UV_SELECT_ISLAND) { - UvNearestHit hit = { - .ob = obedit, - .efa = efa, - }; - uv_select_linked_multi( - scene, objects, objects_len, limit, &hit, true, !select, false, false); - } - } - - if (sima->sticky == SI_STICKY_VERTEX) { - uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset); - } - } - - if (changed || use_pre_deselect) { - changed_multi = true; - - uv_select_sync_flush(ts, em, select); - uv_select_tag_update_for_object(depsgraph, ts, obedit); - } - } - MEM_freeN(objects); - - return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED; -} - -static void UV_OT_select_circle(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Circle Select"; - ot->description = "Select UV vertices using circle selection"; - ot->idname = "UV_OT_select_circle"; - - /* api callbacks */ - ot->invoke = WM_gesture_circle_invoke; - ot->modal = WM_gesture_circle_modal; - ot->exec = uv_circle_select_exec; - ot->poll = ED_operator_uvedit_space_image; /* requires space image */ - ot->cancel = WM_gesture_circle_cancel; - - /* flags */ - ot->flag = OPTYPE_UNDO; - - /* properties */ - WM_operator_properties_gesture_circle(ot); - WM_operator_properties_select_operation_simple(ot); -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Lasso Select Operator - * \{ */ - -static bool do_lasso_select_mesh_uv(bContext *C, - const int mcords[][2], - short moves, - const eSelectOp sel_op) -{ - Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); - SpaceImage *sima = CTX_wm_space_image(C); - ARegion *region = CTX_wm_region(C); - Scene *scene = CTX_data_scene(C); - const ToolSettings *ts = scene->toolsettings; - ViewLayer *view_layer = CTX_data_view_layer(C); - const bool use_face_center = ((ts->uv_flag & UV_SYNC_SELECTION) ? - (ts->selectmode == SCE_SELECT_FACE) : - (ts->uv_selectmode == UV_SELECT_FACE)); - const bool select = (sel_op != SEL_OP_SUB); - const bool use_pre_deselect = SEL_OP_USE_PRE_DESELECT(sel_op); - - BMIter iter, liter; - - BMFace *efa; - BMLoop *l; - int screen_uv[2]; - bool changed_multi = false; - rcti rect; - - UV_SELECT_ISLAND_LIMIT; - - BLI_lasso_boundbox(&rect, mcords, moves); - - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( - view_layer, ((View3D *)NULL), &objects_len); - - if (use_pre_deselect) { - uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT); - } - - /* don't indent to avoid diff noise! */ - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - - bool changed = false; - - BMEditMesh *em = BKE_editmesh_from_object(obedit); - - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - - if (use_face_center) { /* Face Center Sel */ - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - BM_elem_flag_disable(efa, BM_ELEM_TAG); - /* assume not touched */ - if (select != uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) { - float cent[2]; - uv_poly_center(efa, cent, cd_loop_uv_offset); - - if (UI_view2d_view_to_region_clip( - ®ion->v2d, cent[0], cent[1], &screen_uv[0], &screen_uv[1]) && - BLI_rcti_isect_pt_v(&rect, screen_uv) && - BLI_lasso_is_point_inside( - mcords, moves, screen_uv[0], screen_uv[1], V2D_IS_CLIPPED)) { - BM_elem_flag_enable(efa, BM_ELEM_TAG); - changed = true; - } - } - } - - /* (de)selects all tagged faces and deals with sticky modes */ - if (changed) { - uv_select_flush_from_tag_face(sima, scene, obedit, select); - } - } - else { /* Vert Sel */ - BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false); - - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, efa)) { - continue; - } - bool has_selected = false; - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - if ((select) != (uvedit_uv_select_test(scene, l, cd_loop_uv_offset))) { - MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - if (UI_view2d_view_to_region_clip( - ®ion->v2d, luv->uv[0], luv->uv[1], &screen_uv[0], &screen_uv[1]) && - BLI_rcti_isect_pt_v(&rect, screen_uv) && - BLI_lasso_is_point_inside( - mcords, moves, screen_uv[0], screen_uv[1], V2D_IS_CLIPPED)) { - uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); - changed = true; - BM_elem_flag_enable(l->v, BM_ELEM_TAG); - has_selected = true; - } - } - } - if (has_selected && ts->uv_selectmode == UV_SELECT_ISLAND) { - UvNearestHit hit = { - .ob = obedit, - .efa = efa, - }; - uv_select_linked_multi( - scene, objects, objects_len, limit, &hit, true, !select, false, false); - } - } - - if (sima->sticky == SI_STICKY_VERTEX) { - uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset); - } - } - - if (changed || use_pre_deselect) { - changed_multi = true; - - uv_select_sync_flush(ts, em, select); - uv_select_tag_update_for_object(depsgraph, ts, obedit); - } - } - MEM_freeN(objects); - - return changed_multi; -} - -static int uv_lasso_select_exec(bContext *C, wmOperator *op) -{ - int mcords_tot; - const int(*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot); - - if (mcords) { - const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode"); - bool changed = do_lasso_select_mesh_uv(C, mcords, mcords_tot, sel_op); - MEM_freeN((void *)mcords); - - return changed ? OPERATOR_FINISHED : OPERATOR_CANCELLED; - } - - return OPERATOR_PASS_THROUGH; -} - -static void UV_OT_select_lasso(wmOperatorType *ot) -{ - ot->name = "Lasso Select UV"; - ot->description = "Select UVs using lasso selection"; - ot->idname = "UV_OT_select_lasso"; - - ot->invoke = WM_gesture_lasso_invoke; - ot->modal = WM_gesture_lasso_modal; - ot->exec = uv_lasso_select_exec; - ot->poll = ED_operator_uvedit_space_image; - ot->cancel = WM_gesture_lasso_cancel; - - /* flags */ - ot->flag = OPTYPE_UNDO; - - /* properties */ - WM_operator_properties_gesture_lasso(ot); - WM_operator_properties_select_operation_simple(ot); -} - -/** \} */ - -/* -------------------------------------------------------------------- */ /** \name Snap Cursor Operator * \{ */ @@ -4320,312 +1460,6 @@ static void UV_OT_pin(wmOperatorType *ot) /** \} */ /* -------------------------------------------------------------------- */ -/** \name Select Pinned UV's Operator - * \{ */ - -static int uv_select_pinned_exec(bContext *C, wmOperator *UNUSED(op)) -{ - Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); - Scene *scene = CTX_data_scene(C); - const ToolSettings *ts = scene->toolsettings; - ViewLayer *view_layer = CTX_data_view_layer(C); - BMFace *efa; - BMLoop *l; - BMIter iter, liter; - MLoopUV *luv; - - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( - view_layer, ((View3D *)NULL), &objects_len); - - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - bool changed = false; - - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test(scene, efa)) { - continue; - } - - BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { - luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - - if (luv->flag & MLOOPUV_PINNED) { - uvedit_uv_select_enable(em, scene, l, false, cd_loop_uv_offset); - changed = true; - } - } - } - - if (changed) { - uv_select_tag_update_for_object(depsgraph, ts, obedit); - } - } - MEM_freeN(objects); - - return OPERATOR_FINISHED; -} - -static void UV_OT_select_pinned(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Selected Pinned"; - ot->description = "Select all pinned UV vertices"; - ot->idname = "UV_OT_select_pinned"; - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* api callbacks */ - ot->exec = uv_select_pinned_exec; - ot->poll = ED_operator_uvedit; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Select Overlap Operator - * \{ */ - -BLI_INLINE uint overlap_hash(const void *overlap_v) -{ - const BVHTreeOverlap *overlap = overlap_v; - - /* Designed to treat (A,B) and (B,A) as the same. */ - int x = overlap->indexA; - int y = overlap->indexB; - if (x > y) { - SWAP(int, x, y); - } - return BLI_hash_int_2d(x, y); -} - -BLI_INLINE bool overlap_cmp(const void *a_v, const void *b_v) -{ - const BVHTreeOverlap *a = a_v; - const BVHTreeOverlap *b = b_v; - return !((a->indexA == b->indexA && a->indexB == b->indexB) || - (a->indexA == b->indexB && a->indexB == b->indexA)); -} - -struct UVOverlapData { - int ob_index; - int face_index; - float tri[3][2]; -}; - -static int uv_select_overlap(bContext *C, const bool extend) -{ - Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); - Scene *scene = CTX_data_scene(C); - 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_with_uvs( - view_layer, ((View3D *)NULL), &objects_len); - - /* Calculate maximum number of tree nodes and prepare initial selection. */ - uint uv_tri_len = 0; - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - - BM_mesh_elem_table_ensure(em->bm, BM_FACE); - BM_mesh_elem_index_ensure(em->bm, BM_VERT | BM_FACE); - BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false); - if (!extend) { - uv_select_all_perform(scene, obedit, SEL_DESELECT); - } - - BMIter iter; - BMFace *efa; - BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { - if (!uvedit_face_visible_test_ex(scene->toolsettings, efa)) { - continue; - } - uv_tri_len += efa->len - 2; - } - } - - struct UVOverlapData *overlap_data = MEM_mallocN(sizeof(struct UVOverlapData) * uv_tri_len, - "UvOverlapData"); - BVHTree *uv_tree = BLI_bvhtree_new(uv_tri_len, 0.0f, 4, 6); - - /* Use a global data index when inserting into the BVH. */ - int data_index = 0; - - int face_len_alloc = 3; - float(*uv_verts)[2] = MEM_mallocN(sizeof(*uv_verts) * face_len_alloc, "UvOverlapCoords"); - uint(*indices)[3] = MEM_mallocN(sizeof(*indices) * (face_len_alloc - 2), "UvOverlapTris"); - - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *obedit = objects[ob_index]; - BMEditMesh *em = BKE_editmesh_from_object(obedit); - BMIter iter, liter; - BMFace *efa; - BMLoop *l; - - const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); - - /* Triangulate each UV face and store it inside the BVH. */ - int face_index; - BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, face_index) { - - if (!uvedit_face_visible_test_ex(scene->toolsettings, efa)) { - continue; - } - - const uint face_len = efa->len; - const uint tri_len = face_len - 2; - - if (face_len_alloc < face_len) { - MEM_freeN(uv_verts); - MEM_freeN(indices); - uv_verts = MEM_mallocN(sizeof(*uv_verts) * face_len, "UvOverlapCoords"); - indices = MEM_mallocN(sizeof(*indices) * tri_len, "UvOverlapTris"); - face_len_alloc = face_len; - } - - int vert_index; - BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, vert_index) { - MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); - copy_v2_v2(uv_verts[vert_index], luv->uv); - } - - BLI_polyfill_calc(uv_verts, face_len, 0, indices); - - for (int t = 0; t < tri_len; t++) { - overlap_data[data_index].ob_index = ob_index; - overlap_data[data_index].face_index = face_index; - - /* BVH needs 3D, overlap data uses 2D. */ - const float tri[3][3] = { - {UNPACK2(uv_verts[indices[t][0]]), 0.0f}, - {UNPACK2(uv_verts[indices[t][1]]), 0.0f}, - {UNPACK2(uv_verts[indices[t][2]]), 0.0f}, - }; - - copy_v2_v2(overlap_data[data_index].tri[0], tri[0]); - copy_v2_v2(overlap_data[data_index].tri[1], tri[1]); - copy_v2_v2(overlap_data[data_index].tri[2], tri[2]); - - BLI_bvhtree_insert(uv_tree, data_index, &tri[0][0], 3); - data_index++; - } - } - } - BLI_assert(data_index == uv_tri_len); - - MEM_freeN(uv_verts); - MEM_freeN(indices); - - BLI_bvhtree_balance(uv_tree); - - uint tree_overlap_len; - BVHTreeOverlap *overlap = BLI_bvhtree_overlap(uv_tree, uv_tree, &tree_overlap_len, NULL, NULL); - - if (overlap != NULL) { - GSet *overlap_set = BLI_gset_new_ex(overlap_hash, overlap_cmp, __func__, tree_overlap_len); - - for (int i = 0; i < tree_overlap_len; i++) { - /* Skip overlaps against yourself. */ - if (overlap[i].indexA == overlap[i].indexB) { - continue; - } - - /* Skip overlaps that have already been tested. */ - if (!BLI_gset_add(overlap_set, &overlap[i])) { - continue; - } - - const struct UVOverlapData *o_a = &overlap_data[overlap[i].indexA]; - const struct UVOverlapData *o_b = &overlap_data[overlap[i].indexB]; - Object *obedit_a = objects[o_a->ob_index]; - Object *obedit_b = objects[o_b->ob_index]; - BMEditMesh *em_a = BKE_editmesh_from_object(obedit_a); - BMEditMesh *em_b = BKE_editmesh_from_object(obedit_b); - BMFace *face_a = em_a->bm->ftable[o_a->face_index]; - BMFace *face_b = em_b->bm->ftable[o_b->face_index]; - const int cd_loop_uv_offset_a = CustomData_get_offset(&em_a->bm->ldata, CD_MLOOPUV); - const int cd_loop_uv_offset_b = CustomData_get_offset(&em_b->bm->ldata, CD_MLOOPUV); - - /* Skip if both faces are already selected. */ - if (uvedit_face_select_test(scene, face_a, cd_loop_uv_offset_a) && - uvedit_face_select_test(scene, face_b, cd_loop_uv_offset_b)) { - continue; - } - - /* Main tri-tri overlap test. */ - const float endpoint_bias = -1e-4f; - const float(*t1)[2] = o_a->tri; - const float(*t2)[2] = o_b->tri; - float vi[2]; - bool result = ( - /* Don't use 'isect_tri_tri_v2' here - * because it's important to ignore overlap at end-points. */ - isect_seg_seg_v2_point_ex(t1[0], t1[1], t2[0], t2[1], endpoint_bias, vi) == 1 || - isect_seg_seg_v2_point_ex(t1[0], t1[1], t2[1], t2[2], endpoint_bias, vi) == 1 || - isect_seg_seg_v2_point_ex(t1[0], t1[1], t2[2], t2[0], endpoint_bias, vi) == 1 || - isect_seg_seg_v2_point_ex(t1[1], t1[2], t2[0], t2[1], endpoint_bias, vi) == 1 || - isect_seg_seg_v2_point_ex(t1[1], t1[2], t2[1], t2[2], endpoint_bias, vi) == 1 || - isect_seg_seg_v2_point_ex(t1[1], t1[2], t2[2], t2[0], endpoint_bias, vi) == 1 || - isect_seg_seg_v2_point_ex(t1[2], t1[0], t2[0], t2[1], endpoint_bias, vi) == 1 || - isect_seg_seg_v2_point_ex(t1[2], t1[0], t2[1], t2[2], endpoint_bias, vi) == 1 || - isect_point_tri_v2(t1[0], t2[0], t2[1], t2[2]) != 0 || - isect_point_tri_v2(t2[0], t1[0], t1[1], t1[2]) != 0); - - if (result) { - uvedit_face_select_enable(scene, em_a, face_a, false, cd_loop_uv_offset_a); - uvedit_face_select_enable(scene, em_b, face_b, false, cd_loop_uv_offset_b); - } - } - - BLI_gset_free(overlap_set, NULL); - MEM_freeN(overlap); - } - - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - uv_select_tag_update_for_object(depsgraph, scene->toolsettings, objects[ob_index]); - } - - BLI_bvhtree_free(uv_tree); - - MEM_freeN(overlap_data); - MEM_freeN(objects); - - return OPERATOR_FINISHED; -} - -static int uv_select_overlap_exec(bContext *C, wmOperator *op) -{ - bool extend = RNA_boolean_get(op->ptr, "extend"); - return uv_select_overlap(C, extend); -} - -static void UV_OT_select_overlap(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Select Overlap"; - ot->description = "Select all UV faces which overlap each other"; - ot->idname = "UV_OT_select_overlap"; - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* api callbacks */ - ot->exec = uv_select_overlap_exec; - ot->poll = ED_operator_uvedit; - - /* properties */ - RNA_def_boolean(ot->srna, - "extend", - 0, - "Extend", - "Extend selection rather than clearing the existing selection"); -} - -/** \} */ - -/* -------------------------------------------------------------------- */ /** \name Hide Operator * \{ */ @@ -5269,6 +2103,7 @@ static void UV_OT_mark_seam(wmOperatorType *ot) void ED_operatortypes_uvedit(void) { + /* uvedit_select.c */ WM_operatortype_append(UV_OT_select_all); WM_operatortype_append(UV_OT_select); WM_operatortype_append(UV_OT_select_loop); diff --git a/source/blender/editors/uvedit/uvedit_parametrizer.h b/source/blender/editors/uvedit/uvedit_parametrizer.h index 2b80241e6e3..53188ea42bb 100644 --- a/source/blender/editors/uvedit/uvedit_parametrizer.h +++ b/source/blender/editors/uvedit/uvedit_parametrizer.h @@ -21,12 +21,12 @@ * \ingroup eduv */ +#include "BLI_sys_types.h" // for intptr_t support + #ifdef __cplusplus extern "C" { #endif -#include "BLI_sys_types.h" // for intptr_t support - typedef void ParamHandle; /* handle to a set of charts */ typedef intptr_t ParamKey; /* (hash) key for identifying verts and faces */ typedef enum ParamBool { diff --git a/source/blender/editors/uvedit/uvedit_select.c b/source/blender/editors/uvedit/uvedit_select.c new file mode 100644 index 00000000000..cc9be9d48c1 --- /dev/null +++ b/source/blender/editors/uvedit/uvedit_select.c @@ -0,0 +1,3371 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + */ + +/** \file + * \ingroup eduv + */ + +#include <math.h> +#include <stdlib.h> +#include <string.h> + +#include "MEM_guardedalloc.h" + +#include "DNA_image_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_node_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" +#include "DNA_space_types.h" + +#include "BLI_alloca.h" +#include "BLI_blenlib.h" +#include "BLI_hash.h" +#include "BLI_kdopbvh.h" +#include "BLI_lasso_2d.h" +#include "BLI_math.h" +#include "BLI_polyfill_2d.h" +#include "BLI_utildefines.h" + +#include "BKE_context.h" +#include "BKE_customdata.h" +#include "BKE_editmesh.h" +#include "BKE_layer.h" +#include "BKE_mesh.h" +#include "BKE_mesh_mapping.h" +#include "BKE_report.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" + +#include "ED_image.h" +#include "ED_mesh.h" +#include "ED_screen.h" +#include "ED_select_utils.h" +#include "ED_uvedit.h" + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "UI_view2d.h" + +#include "uvedit_intern.h" + +static void uv_select_all_perform(Scene *scene, Object *obedit, int action); +static void uv_select_all_perform_multi(Scene *scene, + Object **objects, + const uint objects_len, + int action); +static void uv_select_flush_from_tag_face(SpaceImage *sima, + Scene *scene, + Object *obedit, + const bool select); +static void uv_select_flush_from_tag_loop(SpaceImage *sima, + Scene *scene, + Object *obedit, + const bool select); +static void uv_select_tag_update_for_object(Depsgraph *depsgraph, + const ToolSettings *ts, + Object *obedit); + +/* -------------------------------------------------------------------- */ +/** \name Visibility and Selection Utilities + * \{ */ + +static void uv_select_island_limit_default(SpaceImage *sima, float r_limit[2]) +{ + uvedit_pixel_to_float(sima, 0.05f, r_limit); +} + +static void uvedit_vertex_select_tagged(BMEditMesh *em, + Scene *scene, + bool select, + int cd_loop_uv_offset) +{ + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) { + uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); + } + } + } +} + +bool uvedit_face_visible_test_ex(const ToolSettings *ts, BMFace *efa) +{ + if (ts->uv_flag & UV_SYNC_SELECTION) { + return (BM_elem_flag_test(efa, BM_ELEM_HIDDEN) == 0); + } + else { + return (BM_elem_flag_test(efa, BM_ELEM_HIDDEN) == 0 && BM_elem_flag_test(efa, BM_ELEM_SELECT)); + } +} +bool uvedit_face_visible_test(const Scene *scene, BMFace *efa) +{ + return uvedit_face_visible_test_ex(scene->toolsettings, efa); +} + +bool uvedit_face_select_test_ex(const ToolSettings *ts, BMFace *efa, const int cd_loop_uv_offset) +{ + if (ts->uv_flag & UV_SYNC_SELECTION) { + return (BM_elem_flag_test(efa, BM_ELEM_SELECT)); + } + else { + BMLoop *l; + MLoopUV *luv; + BMIter liter; + + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + if (!(luv->flag & MLOOPUV_VERTSEL)) { + return false; + } + } + + return true; + } +} +bool uvedit_face_select_test(const Scene *scene, BMFace *efa, const int cd_loop_uv_offset) +{ + return uvedit_face_select_test_ex(scene->toolsettings, efa, cd_loop_uv_offset); +} + +bool uvedit_face_select_set(const struct Scene *scene, + struct BMEditMesh *em, + struct BMFace *efa, + const bool select, + const bool do_history, + const int cd_loop_uv_offset) +{ + if (select) { + return uvedit_face_select_enable(scene, em, efa, do_history, cd_loop_uv_offset); + } + else { + return uvedit_face_select_disable(scene, em, efa, cd_loop_uv_offset); + } +} + +bool uvedit_face_select_enable(const Scene *scene, + BMEditMesh *em, + BMFace *efa, + const bool do_history, + const int cd_loop_uv_offset) +{ + const ToolSettings *ts = scene->toolsettings; + + if (ts->uv_flag & UV_SYNC_SELECTION) { + BM_face_select_set(em->bm, efa, true); + if (do_history) { + BM_select_history_store(em->bm, (BMElem *)efa); + } + } + else { + BMLoop *l; + MLoopUV *luv; + BMIter liter; + + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + luv->flag |= MLOOPUV_VERTSEL; + } + + return true; + } + + return false; +} + +bool uvedit_face_select_disable(const Scene *scene, + BMEditMesh *em, + BMFace *efa, + const int cd_loop_uv_offset) +{ + const ToolSettings *ts = scene->toolsettings; + + if (ts->uv_flag & UV_SYNC_SELECTION) { + BM_face_select_set(em->bm, efa, false); + } + else { + BMLoop *l; + MLoopUV *luv; + BMIter liter; + + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + luv->flag &= ~MLOOPUV_VERTSEL; + } + + return true; + } + + return false; +} + +bool uvedit_edge_select_test_ex(const ToolSettings *ts, BMLoop *l, const int cd_loop_uv_offset) +{ + if (ts->uv_flag & UV_SYNC_SELECTION) { + if (ts->selectmode & SCE_SELECT_FACE) { + return BM_elem_flag_test(l->f, BM_ELEM_SELECT); + } + else if (ts->selectmode == SCE_SELECT_EDGE) { + return BM_elem_flag_test(l->e, BM_ELEM_SELECT); + } + else { + return BM_elem_flag_test(l->v, BM_ELEM_SELECT) && + BM_elem_flag_test(l->next->v, BM_ELEM_SELECT); + } + } + else { + MLoopUV *luv1, *luv2; + + luv1 = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + luv2 = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset); + + return (luv1->flag & MLOOPUV_VERTSEL) && (luv2->flag & MLOOPUV_VERTSEL); + } +} +bool uvedit_edge_select_test(const Scene *scene, BMLoop *l, const int cd_loop_uv_offset) +{ + return uvedit_edge_select_test_ex(scene->toolsettings, l, cd_loop_uv_offset); +} + +void uvedit_edge_select_set(BMEditMesh *em, + const Scene *scene, + BMLoop *l, + const bool select, + const bool do_history, + const int cd_loop_uv_offset) + +{ + if (select) { + uvedit_edge_select_enable(em, scene, l, do_history, cd_loop_uv_offset); + } + else { + uvedit_edge_select_disable(em, scene, l, cd_loop_uv_offset); + } +} + +void uvedit_edge_select_enable(BMEditMesh *em, + const Scene *scene, + BMLoop *l, + const bool do_history, + const int cd_loop_uv_offset) + +{ + const ToolSettings *ts = scene->toolsettings; + + if (ts->uv_flag & UV_SYNC_SELECTION) { + if (ts->selectmode & SCE_SELECT_FACE) { + BM_face_select_set(em->bm, l->f, true); + } + else if (ts->selectmode & SCE_SELECT_EDGE) { + BM_edge_select_set(em->bm, l->e, true); + } + else { + BM_vert_select_set(em->bm, l->e->v1, true); + BM_vert_select_set(em->bm, l->e->v2, true); + } + + if (do_history) { + BM_select_history_store(em->bm, (BMElem *)l->e); + } + } + else { + MLoopUV *luv1, *luv2; + + luv1 = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + luv2 = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset); + + luv1->flag |= MLOOPUV_VERTSEL; + luv2->flag |= MLOOPUV_VERTSEL; + } +} + +void uvedit_edge_select_disable(BMEditMesh *em, + const Scene *scene, + BMLoop *l, + const int cd_loop_uv_offset) + +{ + const ToolSettings *ts = scene->toolsettings; + + if (ts->uv_flag & UV_SYNC_SELECTION) { + if (ts->selectmode & SCE_SELECT_FACE) { + BM_face_select_set(em->bm, l->f, false); + } + else if (ts->selectmode & SCE_SELECT_EDGE) { + BM_edge_select_set(em->bm, l->e, false); + } + else { + BM_vert_select_set(em->bm, l->e->v1, false); + BM_vert_select_set(em->bm, l->e->v2, false); + } + } + else { + MLoopUV *luv1, *luv2; + + luv1 = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + luv2 = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset); + + luv1->flag &= ~MLOOPUV_VERTSEL; + luv2->flag &= ~MLOOPUV_VERTSEL; + } +} + +bool uvedit_uv_select_test_ex(const ToolSettings *ts, BMLoop *l, const int cd_loop_uv_offset) +{ + if (ts->uv_flag & UV_SYNC_SELECTION) { + if (ts->selectmode & SCE_SELECT_FACE) { + return BM_elem_flag_test_bool(l->f, BM_ELEM_SELECT); + } + else { + return BM_elem_flag_test_bool(l->v, BM_ELEM_SELECT); + } + } + else { + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + return (luv->flag & MLOOPUV_VERTSEL) != 0; + } +} +bool uvedit_uv_select_test(const Scene *scene, BMLoop *l, const int cd_loop_uv_offset) +{ + return uvedit_uv_select_test_ex(scene->toolsettings, l, cd_loop_uv_offset); +} + +void uvedit_uv_select_set(BMEditMesh *em, + const Scene *scene, + BMLoop *l, + const bool select, + const bool do_history, + const int cd_loop_uv_offset) +{ + if (select) { + uvedit_uv_select_enable(em, scene, l, do_history, cd_loop_uv_offset); + } + else { + uvedit_uv_select_disable(em, scene, l, cd_loop_uv_offset); + } +} + +void uvedit_uv_select_enable(BMEditMesh *em, + const Scene *scene, + BMLoop *l, + const bool do_history, + const int cd_loop_uv_offset) +{ + const ToolSettings *ts = scene->toolsettings; + + if (ts->uv_flag & UV_SYNC_SELECTION) { + if (ts->selectmode & SCE_SELECT_FACE) { + BM_face_select_set(em->bm, l->f, true); + } + else { + BM_vert_select_set(em->bm, l->v, true); + } + + if (do_history) { + BM_select_history_remove(em->bm, (BMElem *)l->v); + } + } + else { + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + luv->flag |= MLOOPUV_VERTSEL; + } +} + +void uvedit_uv_select_disable(BMEditMesh *em, + const Scene *scene, + BMLoop *l, + const int cd_loop_uv_offset) +{ + const ToolSettings *ts = scene->toolsettings; + + if (ts->uv_flag & UV_SYNC_SELECTION) { + if (ts->selectmode & SCE_SELECT_FACE) { + BM_face_select_set(em->bm, l->f, false); + } + else { + BM_vert_select_set(em->bm, l->v, false); + } + } + else { + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + luv->flag &= ~MLOOPUV_VERTSEL; + } +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Find Nearest Elements + * \{ */ + +bool uv_find_nearest_edge(Scene *scene, Object *obedit, const float co[2], UvNearestHit *hit) +{ + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + MLoopUV *luv, *luv_next; + int i; + bool found = false; + + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + + BM_mesh_elem_index_ensure(em->bm, BM_VERT); + + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (!uvedit_face_visible_test(scene, efa)) { + continue; + } + BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset); + + const float dist_test_sq = dist_squared_to_line_segment_v2(co, luv->uv, luv_next->uv); + + if (dist_test_sq < hit->dist_sq) { + hit->efa = efa; + + hit->l = l; + hit->luv = luv; + hit->luv_next = luv_next; + hit->lindex = i; + + hit->dist_sq = dist_test_sq; + found = true; + } + } + } + return found; +} + +bool uv_find_nearest_edge_multi(Scene *scene, + Object **objects, + const uint objects_len, + const float co[2], + UvNearestHit *hit_final) +{ + bool found = false; + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + if (uv_find_nearest_edge(scene, obedit, co, hit_final)) { + hit_final->ob = obedit; + found = true; + } + } + return found; +} + +bool uv_find_nearest_face(Scene *scene, Object *obedit, const float co[2], UvNearestHit *hit_final) +{ + BMEditMesh *em = BKE_editmesh_from_object(obedit); + bool found = false; + + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + + /* this will fill in hit.vert1 and hit.vert2 */ + float dist_sq_init = hit_final->dist_sq; + UvNearestHit hit = *hit_final; + if (uv_find_nearest_edge(scene, obedit, co, &hit)) { + hit.dist_sq = dist_sq_init; + hit.l = NULL; + hit.luv = hit.luv_next = NULL; + + BMIter iter; + BMFace *efa; + + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (!uvedit_face_visible_test(scene, efa)) { + continue; + } + + float cent[2]; + uv_poly_center(efa, cent, cd_loop_uv_offset); + + const float dist_test_sq = len_squared_v2v2(co, cent); + + if (dist_test_sq < hit.dist_sq) { + hit.efa = efa; + hit.dist_sq = dist_test_sq; + found = true; + } + } + } + if (found) { + *hit_final = hit; + } + return found; +} + +bool uv_find_nearest_face_multi(Scene *scene, + Object **objects, + const uint objects_len, + const float co[2], + UvNearestHit *hit_final) +{ + bool found = false; + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + if (uv_find_nearest_face(scene, obedit, co, hit_final)) { + hit_final->ob = obedit; + found = true; + } + } + return found; +} + +static bool uv_nearest_between(const BMLoop *l, const float co[2], const int cd_loop_uv_offset) +{ + const float *uv_prev = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l->prev, cd_loop_uv_offset))->uv; + const float *uv_curr = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset))->uv; + const float *uv_next = ((MLoopUV *)BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset))->uv; + + return ((line_point_side_v2(uv_prev, uv_curr, co) > 0.0f) && + (line_point_side_v2(uv_next, uv_curr, co) <= 0.0f)); +} + +bool uv_find_nearest_vert(Scene *scene, + Object *obedit, + float const co[2], + const float penalty_dist, + UvNearestHit *hit_final) +{ + bool found = false; + + /* this will fill in hit.vert1 and hit.vert2 */ + float dist_sq_init = hit_final->dist_sq; + UvNearestHit hit = *hit_final; + if (uv_find_nearest_edge(scene, obedit, co, &hit)) { + hit.dist_sq = dist_sq_init; + + hit.l = NULL; + hit.luv = hit.luv_next = NULL; + + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMFace *efa; + BMIter iter; + + BM_mesh_elem_index_ensure(em->bm, BM_VERT); + + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (!uvedit_face_visible_test(scene, efa)) { + continue; + } + + BMIter liter; + BMLoop *l; + int i; + BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) { + float dist_test_sq; + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + if (penalty_dist != 0.0f && uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { + dist_test_sq = len_v2v2(co, luv->uv) + penalty_dist; + dist_test_sq = square_f(dist_test_sq); + } + else { + dist_test_sq = len_squared_v2v2(co, luv->uv); + } + + if (dist_test_sq <= hit.dist_sq) { + if (dist_test_sq == hit.dist_sq) { + if (!uv_nearest_between(l, co, cd_loop_uv_offset)) { + continue; + } + } + + hit.dist_sq = dist_test_sq; + + hit.l = l; + hit.luv = luv; + hit.luv_next = BM_ELEM_CD_GET_VOID_P(l->next, cd_loop_uv_offset); + hit.efa = efa; + hit.lindex = i; + found = true; + } + } + } + } + + if (found) { + *hit_final = hit; + } + + return found; +} + +bool uv_find_nearest_vert_multi(Scene *scene, + Object **objects, + const uint objects_len, + float const co[2], + const float penalty_dist, + UvNearestHit *hit_final) +{ + bool found = false; + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + if (uv_find_nearest_vert(scene, obedit, co, penalty_dist, hit_final)) { + hit_final->ob = obedit; + found = true; + } + } + return found; +} + +bool ED_uvedit_nearest_uv( + const Scene *scene, Object *obedit, const float co[2], float *dist_sq, float r_uv[2]) +{ + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMIter iter; + BMFace *efa; + const float *uv_best = NULL; + float dist_best = *dist_sq; + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (!uvedit_face_visible_test(scene, efa)) { + continue; + } + BMLoop *l_iter, *l_first; + l_iter = l_first = BM_FACE_FIRST_LOOP(efa); + do { + const float *uv = ((const MLoopUV *)BM_ELEM_CD_GET_VOID_P(l_iter, cd_loop_uv_offset))->uv; + const float dist_test = len_squared_v2v2(co, uv); + if (dist_best > dist_test) { + dist_best = dist_test; + uv_best = uv; + } + } while ((l_iter = l_iter->next) != l_first); + } + + if (uv_best != NULL) { + copy_v2_v2(r_uv, uv_best); + *dist_sq = dist_best; + return true; + } + else { + return false; + } +} + +bool ED_uvedit_nearest_uv_multi(const Scene *scene, + Object **objects, + const uint objects_len, + const float co[2], + float *dist_sq, + float r_uv[2]) +{ + bool found = false; + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + if (ED_uvedit_nearest_uv(scene, obedit, co, dist_sq, r_uv)) { + found = true; + } + } + return found; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Loop Select + * \{ */ + +static void uv_select_edgeloop_vertex_loop_flag(UvMapVert *first) +{ + UvMapVert *iterv; + int count = 0; + + for (iterv = first; iterv; iterv = iterv->next) { + if (iterv->separate && iterv != first) { + break; + } + + count++; + } + + if (count < 5) { + first->flag = 1; + } +} + +static UvMapVert *uv_select_edgeloop_vertex_map_get(UvVertMap *vmap, BMFace *efa, BMLoop *l) +{ + UvMapVert *iterv, *first; + first = BM_uv_vert_map_at_index(vmap, BM_elem_index_get(l->v)); + + for (iterv = first; iterv; iterv = iterv->next) { + if (iterv->separate) { + first = iterv; + } + if (iterv->poly_index == BM_elem_index_get(efa)) { + return first; + } + } + + return NULL; +} + +static bool uv_select_edgeloop_edge_tag_faces(BMEditMesh *em, + UvMapVert *first1, + UvMapVert *first2, + int *totface) +{ + UvMapVert *iterv1, *iterv2; + BMFace *efa; + int tot = 0; + + /* count number of faces this edge has */ + for (iterv1 = first1; iterv1; iterv1 = iterv1->next) { + if (iterv1->separate && iterv1 != first1) { + break; + } + + for (iterv2 = first2; iterv2; iterv2 = iterv2->next) { + if (iterv2->separate && iterv2 != first2) { + break; + } + + if (iterv1->poly_index == iterv2->poly_index) { + /* if face already tagged, don't do this edge */ + efa = BM_face_at_index(em->bm, iterv1->poly_index); + if (BM_elem_flag_test(efa, BM_ELEM_TAG)) { + return false; + } + + tot++; + break; + } + } + } + + if (*totface == 0) { /* start edge */ + *totface = tot; + } + else if (tot != *totface) { /* check for same number of faces as start edge */ + return false; + } + + /* tag the faces */ + for (iterv1 = first1; iterv1; iterv1 = iterv1->next) { + if (iterv1->separate && iterv1 != first1) { + break; + } + + for (iterv2 = first2; iterv2; iterv2 = iterv2->next) { + if (iterv2->separate && iterv2 != first2) { + break; + } + + if (iterv1->poly_index == iterv2->poly_index) { + efa = BM_face_at_index(em->bm, iterv1->poly_index); + BM_elem_flag_enable(efa, BM_ELEM_TAG); + break; + } + } + } + + return true; +} + +static int uv_select_edgeloop( + Scene *scene, Object *obedit, UvNearestHit *hit, const float limit[2], const bool extend) +{ + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMFace *efa; + BMIter iter, liter; + BMLoop *l; + UvVertMap *vmap; + UvMapVert *iterv_curr; + UvMapVert *iterv_next; + int starttotf; + bool looking, select; + + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + + /* setup */ + BM_mesh_elem_table_ensure(em->bm, BM_FACE); + vmap = BM_uv_vert_map_create(em->bm, limit, false, false); + + BM_mesh_elem_index_ensure(em->bm, BM_VERT | BM_FACE); + + if (!extend) { + uv_select_all_perform(scene, obedit, SEL_DESELECT); + } + + BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false); + + /* set flags for first face and verts */ + iterv_curr = uv_select_edgeloop_vertex_map_get(vmap, hit->efa, hit->l); + iterv_next = uv_select_edgeloop_vertex_map_get(vmap, hit->efa, hit->l->next); + uv_select_edgeloop_vertex_loop_flag(iterv_curr); + uv_select_edgeloop_vertex_loop_flag(iterv_next); + + starttotf = 0; + uv_select_edgeloop_edge_tag_faces(em, iterv_curr, iterv_next, &starttotf); + + /* sorry, first edge isn't even ok */ + looking = !(iterv_curr->flag == 0 && iterv_next->flag == 0); + + /* iterate */ + while (looking) { + looking = false; + + /* find correct valence edges which are not tagged yet, but connect to tagged one */ + + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (!BM_elem_flag_test(efa, BM_ELEM_TAG) && uvedit_face_visible_test(scene, efa)) { + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + /* check face not hidden and not tagged */ + if (!(iterv_curr = uv_select_edgeloop_vertex_map_get(vmap, efa, l))) { + continue; + } + if (!(iterv_next = uv_select_edgeloop_vertex_map_get(vmap, efa, l->next))) { + continue; + } + + /* check if vertex is tagged and has right valence */ + if (iterv_curr->flag || iterv_next->flag) { + if (uv_select_edgeloop_edge_tag_faces(em, iterv_curr, iterv_next, &starttotf)) { + looking = true; + BM_elem_flag_enable(efa, BM_ELEM_TAG); + + uv_select_edgeloop_vertex_loop_flag(iterv_curr); + uv_select_edgeloop_vertex_loop_flag(iterv_next); + break; + } + } + } + } + } + } + + /* do the actual select/deselect */ + iterv_curr = uv_select_edgeloop_vertex_map_get(vmap, hit->efa, hit->l); + iterv_next = uv_select_edgeloop_vertex_map_get(vmap, hit->efa, hit->l->next); + iterv_curr->flag = 1; + iterv_next->flag = 1; + + if (extend) { + select = !(uvedit_uv_select_test(scene, hit->l, cd_loop_uv_offset)); + } + else { + select = true; + } + + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + iterv_curr = uv_select_edgeloop_vertex_map_get(vmap, efa, l); + + if (iterv_curr->flag) { + uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); + } + } + } + + /* cleanup */ + BM_uv_vert_map_free(vmap); + + return (select) ? 1 : -1; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select Linked + * \{ */ + +static void uv_select_linked_multi(Scene *scene, + Object **objects, + const uint objects_len, + const float limit[2], + UvNearestHit *hit_final, + bool extend, + bool deselect, + bool toggle, + bool select_faces) +{ + /* loop over objects, or just use hit_final->ob */ + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + if (hit_final && ob_index != 0) { + break; + } + Object *obedit = hit_final ? hit_final->ob : objects[ob_index]; + + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + MLoopUV *luv; + UvVertMap *vmap; + UvMapVert *vlist, *iterv, *startv; + int i, stacksize = 0, *stack; + uint a; + char *flag; + + BMEditMesh *em = BKE_editmesh_from_object(obedit); + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + + BM_mesh_elem_table_ensure(em->bm, BM_FACE); /* we can use this too */ + + /* Note, we had 'use winding' so we don't consider overlapping islands as connected, see T44320 + * this made *every* projection split the island into front/back islands. + * Keep 'use_winding' to false, see: T50970. + * + * Better solve this by having a delimit option for select-linked operator, + * keeping island-select working as is. */ + vmap = BM_uv_vert_map_create(em->bm, limit, !select_faces, false); + + if (vmap == NULL) { + continue; + } + + stack = MEM_mallocN(sizeof(*stack) * (em->bm->totface + 1), "UvLinkStack"); + flag = MEM_callocN(sizeof(*flag) * em->bm->totface, "UvLinkFlag"); + + if (hit_final == NULL) { + /* Use existing selection */ + BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) { + if (uvedit_face_visible_test(scene, efa)) { + if (select_faces) { + if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) { + stack[stacksize] = a; + stacksize++; + flag[a] = 1; + } + } + else { + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + + if (luv->flag & MLOOPUV_VERTSEL) { + stack[stacksize] = a; + stacksize++; + flag[a] = 1; + + break; + } + } + } + } + } + } + else { + BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) { + if (efa == hit_final->efa) { + stack[stacksize] = a; + stacksize++; + flag[a] = 1; + break; + } + } + } + + while (stacksize > 0) { + + stacksize--; + a = stack[stacksize]; + + efa = BM_face_at_index(em->bm, a); + + BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) { + + /* make_uv_vert_map_EM sets verts tmp.l to the indices */ + vlist = BM_uv_vert_map_at_index(vmap, BM_elem_index_get(l->v)); + + startv = vlist; + + for (iterv = vlist; iterv; iterv = iterv->next) { + if (iterv->separate) { + startv = iterv; + } + if (iterv->poly_index == a) { + break; + } + } + + for (iterv = startv; iterv; iterv = iterv->next) { + if ((startv != iterv) && (iterv->separate)) { + break; + } + else if (!flag[iterv->poly_index]) { + flag[iterv->poly_index] = 1; + stack[stacksize] = iterv->poly_index; + stacksize++; + } + } + } + } + + /* Toggling - if any of the linked vertices is selected (and visible), we deselect. */ + if ((toggle == true) && (extend == false) && (deselect == false)) { + BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) { + bool found_selected = false; + if (!flag[a]) { + continue; + } + + if (select_faces) { + if (BM_elem_flag_test(efa, BM_ELEM_SELECT) && !BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { + found_selected = true; + } + } + else { + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + + if (luv->flag & MLOOPUV_VERTSEL) { + found_selected = true; + } + } + + if (found_selected) { + deselect = true; + break; + } + } + } + } + +#define SET_SELECTION(value) \ + if (select_faces) { \ + BM_face_select_set(em->bm, efa, value); \ + } \ + else { \ + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { \ + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); \ + luv->flag = (value) ? (luv->flag | MLOOPUV_VERTSEL) : (luv->flag & ~MLOOPUV_VERTSEL); \ + } \ + } \ + (void)0 + + BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, a) { + if (!flag[a]) { + if (!extend && !deselect && !toggle) { + SET_SELECTION(false); + } + continue; + } + + if (!deselect) { + SET_SELECTION(true); + } + else { + SET_SELECTION(false); + } + } + +#undef SET_SELECTION + + MEM_freeN(stack); + MEM_freeN(flag); + BM_uv_vert_map_free(vmap); + } +} + +/** + * \warning This returns first selected UV, + * not ideal in many cases since there could be multiple. + */ +const float *uvedit_first_selected_uv_from_vertex(Scene *scene, + BMVert *eve, + const int cd_loop_uv_offset) +{ + BMIter liter; + BMLoop *l; + + BM_ITER_ELEM (l, &liter, eve, BM_LOOPS_OF_VERT) { + if (!uvedit_face_visible_test(scene, l->f)) { + continue; + } + + if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) { + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + return luv->uv; + } + } + + return NULL; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select More/Less Operator + * \{ */ + +static int uv_select_more_less(bContext *C, const bool select) +{ + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + SpaceImage *sima = CTX_wm_space_image(C); + + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + const ToolSettings *ts = scene->toolsettings; + + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( + view_layer, ((View3D *)NULL), &objects_len); + + const bool is_uv_face_selectmode = (ts->uv_selectmode == UV_SELECT_FACE); + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + + bool changed = false; + + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + + if (ts->uv_flag & UV_SYNC_SELECTION) { + if (select) { + EDBM_select_more(em, true); + } + else { + EDBM_select_less(em, true); + } + + DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + continue; + } + + if (is_uv_face_selectmode) { + + /* clear tags */ + BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false); + + /* mark loops to be selected */ + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (uvedit_face_visible_test(scene, efa)) { + +#define IS_SEL 1 +#define IS_UNSEL 2 + + int sel_state = 0; + + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + if (luv->flag & MLOOPUV_VERTSEL) { + sel_state |= IS_SEL; + } + else { + sel_state |= IS_UNSEL; + } + + /* if we have a mixed selection, tag to grow it */ + if (sel_state == (IS_SEL | IS_UNSEL)) { + BM_elem_flag_enable(efa, BM_ELEM_TAG); + changed = true; + break; + } + } + +#undef IS_SEL +#undef IS_UNSEL + } + } + } + else { + + /* clear tags */ + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + BM_elem_flag_disable(l, BM_ELEM_TAG); + } + } + + /* mark loops to be selected */ + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (uvedit_face_visible_test(scene, efa)) { + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + + if (((luv->flag & MLOOPUV_VERTSEL) != 0) == select) { + BM_elem_flag_enable(l->next, BM_ELEM_TAG); + BM_elem_flag_enable(l->prev, BM_ELEM_TAG); + changed = true; + } + } + } + } + } + + if (changed) { + if (is_uv_face_selectmode) { + /* Select tagged faces. */ + uv_select_flush_from_tag_face(sima, scene, obedit, select); + } + else { + /* Select tagged loops. */ + uv_select_flush_from_tag_loop(sima, scene, obedit, select); + } + DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + } + } + MEM_freeN(objects); + + return OPERATOR_FINISHED; +} + +static int uv_select_more_exec(bContext *C, wmOperator *UNUSED(op)) +{ + return uv_select_more_less(C, true); +} + +void UV_OT_select_more(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Select More"; + ot->description = "Select more UV vertices connected to initial selection"; + ot->idname = "UV_OT_select_more"; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* api callbacks */ + ot->exec = uv_select_more_exec; + ot->poll = ED_operator_uvedit_space_image; +} + +static int uv_select_less_exec(bContext *C, wmOperator *UNUSED(op)) +{ + return uv_select_more_less(C, false); +} + +void UV_OT_select_less(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Select Less"; + ot->description = "Deselect UV vertices at the boundary of each selection region"; + ot->idname = "UV_OT_select_less"; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* api callbacks */ + ot->exec = uv_select_less_exec; + ot->poll = ED_operator_uvedit_space_image; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name (De)Select All Operator + * \{ */ + +bool uvedit_select_is_any_selected(Scene *scene, Object *obedit) +{ + const ToolSettings *ts = scene->toolsettings; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + MLoopUV *luv; + + if (ts->uv_flag & UV_SYNC_SELECTION) { + return (em->bm->totvertsel || em->bm->totedgesel || em->bm->totfacesel); + } + else { + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (!uvedit_face_visible_test(scene, efa)) { + continue; + } + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + if (luv->flag & MLOOPUV_VERTSEL) { + return true; + } + } + } + } + return false; +} + +bool uvedit_select_is_any_selected_multi(Scene *scene, Object **objects, const uint objects_len) +{ + bool found = false; + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + if (uvedit_select_is_any_selected(scene, obedit)) { + found = true; + break; + } + } + return found; +} + +static void uv_select_all_perform(Scene *scene, Object *obedit, int action) +{ + const ToolSettings *ts = scene->toolsettings; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + MLoopUV *luv; + + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + + if (action == SEL_TOGGLE) { + action = uvedit_select_is_any_selected(scene, obedit) ? SEL_DESELECT : SEL_SELECT; + } + + if (ts->uv_flag & UV_SYNC_SELECTION) { + switch (action) { + case SEL_TOGGLE: + EDBM_select_toggle_all(em); + break; + case SEL_SELECT: + EDBM_flag_enable_all(em, BM_ELEM_SELECT); + break; + case SEL_DESELECT: + EDBM_flag_disable_all(em, BM_ELEM_SELECT); + break; + case SEL_INVERT: + EDBM_select_swap(em); + EDBM_selectmode_flush(em); + break; + } + } + else { + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (!uvedit_face_visible_test(scene, efa)) { + continue; + } + + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + + switch (action) { + case SEL_SELECT: + luv->flag |= MLOOPUV_VERTSEL; + break; + case SEL_DESELECT: + luv->flag &= ~MLOOPUV_VERTSEL; + break; + case SEL_INVERT: + luv->flag ^= MLOOPUV_VERTSEL; + break; + } + } + } + } +} + +static void uv_select_all_perform_multi(Scene *scene, + Object **objects, + const uint objects_len, + int action) +{ + if (action == SEL_TOGGLE) { + action = uvedit_select_is_any_selected_multi(scene, objects, objects_len) ? SEL_DESELECT : + SEL_SELECT; + } + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + uv_select_all_perform(scene, obedit, action); + } +} + +static int uv_select_all_exec(bContext *C, wmOperator *op) +{ + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + Scene *scene = CTX_data_scene(C); + const ToolSettings *ts = scene->toolsettings; + ViewLayer *view_layer = CTX_data_view_layer(C); + + int action = RNA_enum_get(op->ptr, "action"); + + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( + view_layer, ((View3D *)NULL), &objects_len); + + uv_select_all_perform_multi(scene, objects, objects_len, action); + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + uv_select_tag_update_for_object(depsgraph, ts, obedit); + } + + MEM_freeN(objects); + + return OPERATOR_FINISHED; +} + +void UV_OT_select_all(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "(De)select All"; + ot->description = "Change selection of all UV vertices"; + ot->idname = "UV_OT_select_all"; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* api callbacks */ + ot->exec = uv_select_all_exec; + ot->poll = ED_operator_uvedit; + + WM_operator_properties_select_all(ot); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Mouse Select Operator + * \{ */ + +static bool uv_sticky_select( + float *limit, int hitv[], int v, float *hituv[], float *uv, int sticky, int hitlen) +{ + int i; + + /* this function test if some vertex needs to selected + * in addition to the existing ones due to sticky select */ + if (sticky == SI_STICKY_DISABLE) { + return false; + } + + for (i = 0; i < hitlen; i++) { + if (hitv[i] == v) { + if (sticky == SI_STICKY_LOC) { + if (fabsf(hituv[i][0] - uv[0]) < limit[0] && fabsf(hituv[i][1] - uv[1]) < limit[1]) { + return true; + } + } + else if (sticky == SI_STICKY_VERTEX) { + return true; + } + } + } + + return false; +} + +static int uv_mouse_select_multi(bContext *C, + Object **objects, + uint objects_len, + const float co[2], + const bool extend, + const bool deselect_all, + const bool loop) +{ + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + SpaceImage *sima = CTX_wm_space_image(C); + Scene *scene = CTX_data_scene(C); + const ToolSettings *ts = scene->toolsettings; + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + MLoopUV *luv; + UvNearestHit hit = UV_NEAREST_HIT_INIT; + int i, selectmode, sticky, sync, *hitv = NULL; + bool select = true; + bool found_item = false; + /* 0 == don't flush, 1 == sel, -1 == desel; only use when selection sync is enabled */ + int flush = 0; + int hitlen = 0; + float limit[2], **hituv = NULL; + + /* notice 'limit' is the same no matter the zoom level, since this is like + * remove doubles and could annoying if it joined points when zoomed out. + * 'penalty' is in screen pixel space otherwise zooming in on a uv-vert and + * shift-selecting can consider an adjacent point close enough to add to + * the selection rather than de-selecting the closest. */ + + float penalty_dist; + { + float penalty[2]; + uvedit_pixel_to_float(sima, 0.05f, limit); + uvedit_pixel_to_float(sima, 5.0f / (sima ? sima->zoom : 1.0f), penalty); + penalty_dist = len_v2(penalty); + } + + /* retrieve operation mode */ + if (ts->uv_flag & UV_SYNC_SELECTION) { + sync = 1; + + if (ts->selectmode & SCE_SELECT_FACE) { + selectmode = UV_SELECT_FACE; + } + else if (ts->selectmode & SCE_SELECT_EDGE) { + selectmode = UV_SELECT_EDGE; + } + else { + selectmode = UV_SELECT_VERTEX; + } + + sticky = SI_STICKY_DISABLE; + } + else { + sync = 0; + selectmode = ts->uv_selectmode; + sticky = (sima) ? sima->sticky : 1; + } + + /* find nearest element */ + if (loop) { + /* find edge */ + found_item = uv_find_nearest_edge_multi(scene, objects, objects_len, co, &hit); + } + else if (selectmode == UV_SELECT_VERTEX) { + /* find vertex */ + found_item = uv_find_nearest_vert_multi(scene, objects, objects_len, co, penalty_dist, &hit); + found_item = found_item && (!deselect_all || hit.dist_sq < penalty_dist); + + if (found_item) { + /* mark 1 vertex as being hit */ + hitv = BLI_array_alloca(hitv, hit.efa->len); + hituv = BLI_array_alloca(hituv, hit.efa->len); + copy_vn_i(hitv, hit.efa->len, 0xFFFFFFFF); + + hitv[hit.lindex] = BM_elem_index_get(hit.l->v); + hituv[hit.lindex] = hit.luv->uv; + + hitlen = hit.efa->len; + } + } + else if (selectmode == UV_SELECT_EDGE) { + /* find edge */ + found_item = uv_find_nearest_edge_multi(scene, objects, objects_len, co, &hit); + found_item = found_item && (!deselect_all || hit.dist_sq < penalty_dist); + + if (found_item) { + /* mark 2 edge vertices as being hit */ + hitv = BLI_array_alloca(hitv, hit.efa->len); + hituv = BLI_array_alloca(hituv, hit.efa->len); + copy_vn_i(hitv, hit.efa->len, 0xFFFFFFFF); + + hitv[hit.lindex] = BM_elem_index_get(hit.l->v); + hitv[(hit.lindex + 1) % hit.efa->len] = BM_elem_index_get(hit.l->next->v); + hituv[hit.lindex] = hit.luv->uv; + hituv[(hit.lindex + 1) % hit.efa->len] = hit.luv_next->uv; + + hitlen = hit.efa->len; + } + } + else if (selectmode == UV_SELECT_FACE) { + /* find face */ + found_item = uv_find_nearest_face_multi(scene, objects, objects_len, co, &hit); + found_item = found_item && (!deselect_all || hit.dist_sq < penalty_dist); + + if (found_item) { + BMEditMesh *em = BKE_editmesh_from_object(hit.ob); + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + + /* make active */ + BM_mesh_active_face_set(em->bm, hit.efa); + + /* mark all face vertices as being hit */ + + hitv = BLI_array_alloca(hitv, hit.efa->len); + hituv = BLI_array_alloca(hituv, hit.efa->len); + BM_ITER_ELEM_INDEX (l, &liter, hit.efa, BM_LOOPS_OF_FACE, i) { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + hituv[i] = luv->uv; + hitv[i] = BM_elem_index_get(l->v); + } + + hitlen = hit.efa->len; + } + } + else if (selectmode == UV_SELECT_ISLAND) { + found_item = uv_find_nearest_edge_multi(scene, objects, objects_len, co, &hit); + found_item = found_item && (!deselect_all || hit.dist_sq < penalty_dist); + } + + if (!found_item) { + if (deselect_all) { + uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT); + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + uv_select_tag_update_for_object(depsgraph, ts, obedit); + } + + return OPERATOR_PASS_THROUGH | OPERATOR_FINISHED; + } + return OPERATOR_CANCELLED; + } + + Object *obedit = hit.ob; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + + /* do selection */ + if (loop) { + if (!extend) { + /* TODO(MULTI_EDIT): We only need to de-select non-active */ + uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT); + } + flush = uv_select_edgeloop(scene, obedit, &hit, limit, extend); + } + else if (selectmode == UV_SELECT_ISLAND) { + if (!extend) { + /* TODO(MULTI_EDIT): We only need to de-select non-active */ + uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT); + } + /* Current behavior of 'extend' + * is actually toggling, so pass extend flag as 'toggle' here */ + uv_select_linked_multi(scene, objects, objects_len, limit, &hit, false, false, extend, false); + } + else if (extend) { + if (selectmode == UV_SELECT_VERTEX) { + /* (de)select uv vertex */ + select = !uvedit_uv_select_test(scene, hit.l, cd_loop_uv_offset); + uvedit_uv_select_set(em, scene, hit.l, select, true, cd_loop_uv_offset); + flush = 1; + } + else if (selectmode == UV_SELECT_EDGE) { + /* (de)select edge */ + select = !(uvedit_edge_select_test(scene, hit.l, cd_loop_uv_offset)); + uvedit_edge_select_set(em, scene, hit.l, select, true, cd_loop_uv_offset); + flush = 1; + } + else if (selectmode == UV_SELECT_FACE) { + /* (de)select face */ + select = !(uvedit_face_select_test(scene, hit.efa, cd_loop_uv_offset)); + uvedit_face_select_set(scene, em, hit.efa, select, true, cd_loop_uv_offset); + flush = -1; + } + + /* de-selecting an edge may deselect a face too - validate */ + if (sync) { + if (select == false) { + BM_select_history_validate(em->bm); + } + } + + /* (de)select sticky uv nodes */ + if (sticky != SI_STICKY_DISABLE) { + + BM_mesh_elem_index_ensure(em->bm, BM_VERT); + + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (!uvedit_face_visible_test(scene, efa)) { + continue; + } + + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + if (uv_sticky_select( + limit, hitv, BM_elem_index_get(l->v), hituv, luv->uv, sticky, hitlen)) { + uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); + } + } + } + + flush = select ? 1 : -1; + } + } + else { + /* deselect all */ + uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT); + + if (selectmode == UV_SELECT_VERTEX) { + /* select vertex */ + uvedit_uv_select_enable(em, scene, hit.l, true, cd_loop_uv_offset); + flush = 1; + } + else if (selectmode == UV_SELECT_EDGE) { + /* select edge */ + uvedit_edge_select_enable(em, scene, hit.l, true, cd_loop_uv_offset); + flush = 1; + } + else if (selectmode == UV_SELECT_FACE) { + /* select face */ + uvedit_face_select_enable(scene, em, hit.efa, true, cd_loop_uv_offset); + } + + /* select sticky uvs */ + if (sticky != SI_STICKY_DISABLE) { + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (!uvedit_face_visible_test(scene, efa)) { + continue; + } + + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + if (sticky == SI_STICKY_DISABLE) { + continue; + } + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + + if (uv_sticky_select( + limit, hitv, BM_elem_index_get(l->v), hituv, luv->uv, sticky, hitlen)) { + uvedit_uv_select_enable(em, scene, l, false, cd_loop_uv_offset); + } + + flush = 1; + } + } + } + } + + if (sync) { + /* flush for mesh selection */ + + /* before bmesh */ +#if 0 + if (ts->selectmode != SCE_SELECT_FACE) { + if (flush == 1) { + EDBM_select_flush(em); + } + else if (flush == -1) { + EDBM_deselect_flush(em); + } + } +#else + if (flush != 0) { + if (loop) { + /* push vertex -> edge selection */ + if (select) { + EDBM_select_flush(em); + } + else { + EDBM_deselect_flush(em); + } + } + else { + EDBM_selectmode_flush(em); + } + } +#endif + } + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obiter = objects[ob_index]; + uv_select_tag_update_for_object(depsgraph, ts, obiter); + } + + return OPERATOR_PASS_THROUGH | OPERATOR_FINISHED; +} +static int uv_mouse_select( + bContext *C, const float co[2], const bool extend, const bool deselect_all, const bool loop) +{ + 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_with_uvs( + view_layer, ((View3D *)NULL), &objects_len); + int ret = uv_mouse_select_multi(C, objects, objects_len, co, extend, deselect_all, loop); + MEM_freeN(objects); + return ret; +} + +static int uv_select_exec(bContext *C, wmOperator *op) +{ + float co[2]; + + RNA_float_get_array(op->ptr, "location", co); + const bool extend = RNA_boolean_get(op->ptr, "extend"); + const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all"); + const bool loop = false; + + return uv_mouse_select(C, co, extend, deselect_all, loop); +} + +static int uv_select_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + const ARegion *region = CTX_wm_region(C); + float co[2]; + + UI_view2d_region_to_view(®ion->v2d, event->mval[0], event->mval[1], &co[0], &co[1]); + RNA_float_set_array(op->ptr, "location", co); + + return uv_select_exec(C, op); +} + +void UV_OT_select(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Select"; + ot->description = "Select UV vertices"; + ot->idname = "UV_OT_select"; + ot->flag = OPTYPE_UNDO; + + /* api callbacks */ + ot->exec = uv_select_exec; + ot->invoke = uv_select_invoke; + ot->poll = ED_operator_uvedit; /* requires space image */ + + /* properties */ + PropertyRNA *prop; + RNA_def_boolean(ot->srna, + "extend", + 0, + "Extend", + "Extend selection rather than clearing the existing selection"); + prop = RNA_def_boolean(ot->srna, + "deselect_all", + false, + "Deselect On Nothing", + "Deselect all when nothing under the cursor"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + + RNA_def_float_vector( + ot->srna, + "location", + 2, + NULL, + -FLT_MAX, + FLT_MAX, + "Location", + "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds", + -100.0f, + 100.0f); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Loop Select Operator + * \{ */ + +static int uv_select_loop_exec(bContext *C, wmOperator *op) +{ + float co[2]; + + RNA_float_get_array(op->ptr, "location", co); + const bool extend = RNA_boolean_get(op->ptr, "extend"); + const bool deselect_all = false; + const bool loop = true; + + return uv_mouse_select(C, co, extend, deselect_all, loop); +} + +static int uv_select_loop_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + const ARegion *region = CTX_wm_region(C); + float co[2]; + + UI_view2d_region_to_view(®ion->v2d, event->mval[0], event->mval[1], &co[0], &co[1]); + RNA_float_set_array(op->ptr, "location", co); + + return uv_select_loop_exec(C, op); +} + +void UV_OT_select_loop(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Loop Select"; + ot->description = "Select a loop of connected UV vertices"; + ot->idname = "UV_OT_select_loop"; + ot->flag = OPTYPE_UNDO; + + /* api callbacks */ + ot->exec = uv_select_loop_exec; + ot->invoke = uv_select_loop_invoke; + ot->poll = ED_operator_uvedit; /* requires space image */ + + /* properties */ + RNA_def_boolean(ot->srna, + "extend", + 0, + "Extend", + "Extend selection rather than clearing the existing selection"); + RNA_def_float_vector( + ot->srna, + "location", + 2, + NULL, + -FLT_MAX, + FLT_MAX, + "Location", + "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds", + -100.0f, + 100.0f); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select Linked Operator + * \{ */ + +static int uv_select_linked_internal(bContext *C, wmOperator *op, const wmEvent *event, bool pick) +{ + SpaceImage *sima = CTX_wm_space_image(C); + Scene *scene = CTX_data_scene(C); + const ToolSettings *ts = scene->toolsettings; + ViewLayer *view_layer = CTX_data_view_layer(C); + float limit[2]; + bool extend = true; + bool deselect = false; + bool select_faces = (ts->uv_flag & UV_SYNC_SELECTION) && (ts->selectmode & SCE_SELECT_FACE); + + UvNearestHit hit = UV_NEAREST_HIT_INIT; + + if ((ts->uv_flag & UV_SYNC_SELECTION) && !(ts->selectmode & SCE_SELECT_FACE)) { + BKE_report(op->reports, + RPT_ERROR, + "Select linked only works in face select mode when sync selection is enabled"); + return OPERATOR_CANCELLED; + } + + if (pick) { + extend = RNA_boolean_get(op->ptr, "extend"); + deselect = RNA_boolean_get(op->ptr, "deselect"); + } + uv_select_island_limit_default(sima, limit); + + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( + view_layer, ((View3D *)NULL), &objects_len); + + if (pick) { + float co[2]; + + if (event) { + /* invoke */ + const ARegion *region = CTX_wm_region(C); + + UI_view2d_region_to_view(®ion->v2d, event->mval[0], event->mval[1], &co[0], &co[1]); + RNA_float_set_array(op->ptr, "location", co); + } + else { + /* exec */ + RNA_float_get_array(op->ptr, "location", co); + } + + if (!uv_find_nearest_edge_multi(scene, objects, objects_len, co, &hit)) { + MEM_freeN(objects); + return OPERATOR_CANCELLED; + } + } + + if (!extend) { + uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT); + } + + uv_select_linked_multi(scene, + objects, + objects_len, + limit, + pick ? &hit : NULL, + extend, + deselect, + false, + select_faces); + + /* weak!, but works */ + Object **objects_free = objects; + if (pick) { + objects = &hit.ob; + objects_len = 1; + } + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + DEG_id_tag_update(obedit->data, ID_RECALC_COPY_ON_WRITE | ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + } + + MEM_SAFE_FREE(objects_free); + + return OPERATOR_FINISHED; +} + +static int uv_select_linked_exec(bContext *C, wmOperator *op) +{ + return uv_select_linked_internal(C, op, NULL, false); +} + +void UV_OT_select_linked(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Select Linked"; + ot->description = "Select all UV vertices linked to the active UV map"; + ot->idname = "UV_OT_select_linked"; + + /* api callbacks */ + ot->exec = uv_select_linked_exec; + ot->poll = ED_operator_uvedit; /* requires space image */ + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select Linked (Cursor Pick) Operator + * \{ */ + +static int uv_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + return uv_select_linked_internal(C, op, event, true); +} + +static int uv_select_linked_pick_exec(bContext *C, wmOperator *op) +{ + return uv_select_linked_internal(C, op, NULL, true); +} + +void UV_OT_select_linked_pick(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Select Linked Pick"; + ot->description = "Select all UV vertices linked under the mouse"; + ot->idname = "UV_OT_select_linked_pick"; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* api callbacks */ + ot->invoke = uv_select_linked_pick_invoke; + ot->exec = uv_select_linked_pick_exec; + ot->poll = ED_operator_uvedit; /* requires space image */ + + /* properties */ + RNA_def_boolean(ot->srna, + "extend", + 0, + "Extend", + "Extend selection rather than clearing the existing selection"); + RNA_def_boolean(ot->srna, + "deselect", + 0, + "Deselect", + "Deselect linked UV vertices rather than selecting them"); + RNA_def_float_vector( + ot->srna, + "location", + 2, + NULL, + -FLT_MAX, + FLT_MAX, + "Location", + "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds", + -100.0f, + 100.0f); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select Split Operator + * \{ */ + +/** + * \note This is based on similar use case to #MESH_OT_split(), which has a similar effect + * but in this case they are not joined to begin with (only having the behavior of being joined) + * so its best to call this #uv_select_split() instead of just split(), but assigned to the same + * key as #MESH_OT_split - Campbell. + */ +static int uv_select_split_exec(bContext *C, wmOperator *op) +{ + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + const ToolSettings *ts = scene->toolsettings; + + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + MLoopUV *luv; + + if (ts->uv_flag & UV_SYNC_SELECTION) { + BKE_report(op->reports, RPT_ERROR, "Cannot split selection when sync selection is enabled"); + return OPERATOR_CANCELLED; + } + + bool changed_multi = false; + + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( + view_layer, ((View3D *)NULL), &objects_len); + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMesh *bm = BKE_editmesh_from_object(obedit)->bm; + + bool changed = false; + + const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV); + + BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) { + bool is_sel = false; + bool is_unsel = false; + + if (!uvedit_face_visible_test(scene, efa)) { + continue; + } + + /* are we all selected? */ + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + + if (luv->flag & MLOOPUV_VERTSEL) { + is_sel = true; + } + else { + is_unsel = true; + } + + /* we have mixed selection, bail out */ + if (is_sel && is_unsel) { + break; + } + } + + if (is_sel && is_unsel) { + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + luv->flag &= ~MLOOPUV_VERTSEL; + } + + changed = true; + } + } + + if (changed) { + changed_multi = true; + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_IMAGE, NULL); + } + } + MEM_freeN(objects); + + return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED; +} + +void UV_OT_select_split(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Select Split"; + ot->description = "Select only entirely selected faces"; + ot->idname = "UV_OT_select_split"; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* api callbacks */ + ot->exec = uv_select_split_exec; + ot->poll = ED_operator_uvedit; /* requires space image */ +} + +static void uv_select_sync_flush(const ToolSettings *ts, BMEditMesh *em, const short select) +{ + /* bmesh API handles flushing but not on de-select */ + if (ts->uv_flag & UV_SYNC_SELECTION) { + if (ts->selectmode != SCE_SELECT_FACE) { + if (select == false) { + EDBM_deselect_flush(em); + } + else { + EDBM_select_flush(em); + } + } + + if (select == false) { + BM_select_history_validate(em->bm); + } + } +} + +static void uv_select_tag_update_for_object(Depsgraph *depsgraph, + const ToolSettings *ts, + Object *obedit) +{ + if (ts->uv_flag & UV_SYNC_SELECTION) { + DEG_id_tag_update(obedit->data, ID_RECALC_SELECT); + WM_main_add_notifier(NC_GEOM | ND_SELECT, obedit->data); + } + else { + Object *obedit_eval = DEG_get_evaluated_object(depsgraph, obedit); + BKE_mesh_batch_cache_dirty_tag(obedit_eval->data, BKE_MESH_BATCH_DIRTY_UVEDIT_SELECT); + /* Only for region redraw. */ + WM_main_add_notifier(NC_GEOM | ND_SELECT, obedit->data); + } +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select/Tag Flushing Utils + * + * Utility functions to flush the uv-selection from tags. + * \{ */ + +/** + * helper function for #uv_select_flush_from_tag_loop and uv_select_flush_from_tag_face + */ +static void uv_select_flush_from_tag_sticky_loc_internal(Scene *scene, + BMEditMesh *em, + UvVertMap *vmap, + const uint efa_index, + BMLoop *l, + const bool select, + const int cd_loop_uv_offset) +{ + UvMapVert *start_vlist = NULL, *vlist_iter; + BMFace *efa_vlist; + + uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); + + vlist_iter = BM_uv_vert_map_at_index(vmap, BM_elem_index_get(l->v)); + + while (vlist_iter) { + if (vlist_iter->separate) { + start_vlist = vlist_iter; + } + + if (efa_index == vlist_iter->poly_index) { + break; + } + + vlist_iter = vlist_iter->next; + } + + vlist_iter = start_vlist; + while (vlist_iter) { + + if (vlist_iter != start_vlist && vlist_iter->separate) { + break; + } + + if (efa_index != vlist_iter->poly_index) { + BMLoop *l_other; + efa_vlist = BM_face_at_index(em->bm, vlist_iter->poly_index); + /* tf_vlist = BM_ELEM_CD_GET_VOID_P(efa_vlist, cd_poly_tex_offset); */ /* UNUSED */ + + l_other = BM_iter_at_index( + em->bm, BM_LOOPS_OF_FACE, efa_vlist, vlist_iter->loop_of_poly_index); + + uvedit_uv_select_set(em, scene, l_other, select, false, cd_loop_uv_offset); + } + vlist_iter = vlist_iter->next; + } +} + +/** + * Flush the selection from face tags based on sticky and selection modes. + * + * needed because settings the selection a face is done in a number of places but it also + * needs to respect the sticky modes for the UV verts, so dealing with the sticky modes + * is best done in a separate function. + * + * \note This function is very similar to #uv_select_flush_from_tag_loop, + * be sure to update both upon changing. + */ +static void uv_select_flush_from_tag_face(SpaceImage *sima, + Scene *scene, + Object *obedit, + const bool select) +{ + /* Selecting UV Faces with some modes requires us to change + * the selection in other faces (depending on the sticky mode). + * + * This only needs to be done when the Mesh is not used for + * selection (so for sticky modes, vertex or location based). */ + + const ToolSettings *ts = scene->toolsettings; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + + if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && sima->sticky == SI_STICKY_VERTEX) { + /* Tag all verts as untouched, then touch the ones that have a face center + * in the loop and select all MLoopUV's that use a touched vert. */ + BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false); + + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (BM_elem_flag_test(efa, BM_ELEM_TAG)) { + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + BM_elem_flag_enable(l->v, BM_ELEM_TAG); + } + } + } + + /* now select tagged verts */ + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */ + + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) { + uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); + } + } + } + } + else if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && sima->sticky == SI_STICKY_LOC) { + struct UvVertMap *vmap; + float limit[2]; + uint efa_index; + + uv_select_island_limit_default(sima, limit); + + BM_mesh_elem_table_ensure(em->bm, BM_FACE); + vmap = BM_uv_vert_map_create(em->bm, limit, false, false); + if (vmap == NULL) { + return; + } + + BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, efa_index) { + if (BM_elem_flag_test(efa, BM_ELEM_TAG)) { + /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */ + + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + uv_select_flush_from_tag_sticky_loc_internal( + scene, em, vmap, efa_index, l, select, cd_loop_uv_offset); + } + } + } + BM_uv_vert_map_free(vmap); + } + else { /* SI_STICKY_DISABLE or ts->uv_flag & UV_SYNC_SELECTION */ + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (BM_elem_flag_test(efa, BM_ELEM_TAG)) { + uvedit_face_select_set(scene, em, efa, select, false, cd_loop_uv_offset); + } + } + } +} + +/** + * Flush the selection from loop tags based on sticky and selection modes. + * + * needed because settings the selection a face is done in a number of places but it also needs + * to respect the sticky modes for the UV verts, so dealing with the sticky modes is best done + * in a separate function. + * + * \note This function is very similar to #uv_select_flush_from_tag_loop, + * be sure to update both upon changing. + */ +static void uv_select_flush_from_tag_loop(SpaceImage *sima, + Scene *scene, + Object *obedit, + const bool select) +{ + /* Selecting UV Loops with some modes requires us to change + * the selection in other faces (depending on the sticky mode). + * + * This only needs to be done when the Mesh is not used for + * selection (so for sticky modes, vertex or location based). */ + + const ToolSettings *ts = scene->toolsettings; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + + if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && sima->sticky == SI_STICKY_VERTEX) { + /* Tag all verts as untouched, then touch the ones that have a face center + * in the loop and select all MLoopUV's that use a touched vert. */ + BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false); + + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + if (BM_elem_flag_test(l, BM_ELEM_TAG)) { + BM_elem_flag_enable(l->v, BM_ELEM_TAG); + } + } + } + + /* now select tagged verts */ + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */ + + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + if (BM_elem_flag_test(l->v, BM_ELEM_TAG)) { + uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); + } + } + } + } + else if ((ts->uv_flag & UV_SYNC_SELECTION) == 0 && sima->sticky == SI_STICKY_LOC) { + struct UvVertMap *vmap; + float limit[2]; + uint efa_index; + + uv_select_island_limit_default(sima, limit); + + BM_mesh_elem_table_ensure(em->bm, BM_FACE); + vmap = BM_uv_vert_map_create(em->bm, limit, false, false); + if (vmap == NULL) { + return; + } + + BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, efa_index) { + /* tf = BM_ELEM_CD_GET_VOID_P(efa, cd_poly_tex_offset); */ /* UNUSED */ + + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + if (BM_elem_flag_test(l, BM_ELEM_TAG)) { + uv_select_flush_from_tag_sticky_loc_internal( + scene, em, vmap, efa_index, l, select, cd_loop_uv_offset); + } + } + } + BM_uv_vert_map_free(vmap); + } + else { /* SI_STICKY_DISABLE or ts->uv_flag & UV_SYNC_SELECTION */ + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + if (BM_elem_flag_test(l, BM_ELEM_TAG)) { + uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); + } + } + } + } +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Box Select Operator + * \{ */ + +static int uv_box_select_exec(bContext *C, wmOperator *op) +{ + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + SpaceImage *sima = CTX_wm_space_image(C); + Scene *scene = CTX_data_scene(C); + const ToolSettings *ts = scene->toolsettings; + ViewLayer *view_layer = CTX_data_view_layer(C); + const ARegion *region = CTX_wm_region(C); + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + MLoopUV *luv; + rctf rectf; + bool pinned; + float limit[2]; + const bool use_face_center = ((ts->uv_flag & UV_SYNC_SELECTION) ? + (ts->selectmode == SCE_SELECT_FACE) : + (ts->uv_selectmode == UV_SELECT_FACE)); + const bool use_edge = ((ts->uv_flag & UV_SYNC_SELECTION) ? + (ts->selectmode == SCE_SELECT_EDGE) : + (ts->uv_selectmode == UV_SELECT_EDGE)); + + /* get rectangle from operator */ + WM_operator_properties_border_to_rctf(op, &rectf); + UI_view2d_region_to_view_rctf(®ion->v2d, &rectf, &rectf); + + const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode"); + const bool select = (sel_op != SEL_OP_SUB); + const bool use_pre_deselect = SEL_OP_USE_PRE_DESELECT(sel_op); + + pinned = RNA_boolean_get(op->ptr, "pinned"); + + uv_select_island_limit_default(sima, limit); + + bool changed_multi = false; + + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( + view_layer, ((View3D *)NULL), &objects_len); + + if (use_pre_deselect) { + uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT); + } + + /* don't indent to avoid diff noise! */ + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + + bool changed = false; + + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + + /* do actual selection */ + if (use_face_center && !pinned) { + /* handle face selection mode */ + float cent[2]; + + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + /* assume not touched */ + BM_elem_flag_disable(efa, BM_ELEM_TAG); + + if (uvedit_face_visible_test(scene, efa)) { + uv_poly_center(efa, cent, cd_loop_uv_offset); + if (BLI_rctf_isect_pt_v(&rectf, cent)) { + BM_elem_flag_enable(efa, BM_ELEM_TAG); + changed = true; + } + } + } + + /* (de)selects all tagged faces and deals with sticky modes */ + if (changed) { + uv_select_flush_from_tag_face(sima, scene, obedit, select); + } + } + else if (use_edge && !pinned) { + changed = true; + BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false); + + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (!uvedit_face_visible_test(scene, efa)) { + continue; + } + + BMLoop *l_prev = BM_FACE_FIRST_LOOP(efa)->prev; + MLoopUV *luv_prev = BM_ELEM_CD_GET_VOID_P(l_prev, cd_loop_uv_offset); + bool luv_select_prev = uvedit_uv_select_test(scene, l_prev, cd_loop_uv_offset); + + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + const bool luv_select = uvedit_uv_select_test(scene, l, cd_loop_uv_offset); + if ((select != luv_select) || (select != luv_select_prev)) { + if (BLI_rctf_isect_pt_v(&rectf, luv->uv) && + BLI_rctf_isect_pt_v(&rectf, luv_prev->uv)) { + uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); + uvedit_uv_select_set(em, scene, l_prev, select, false, cd_loop_uv_offset); + BM_elem_flag_enable(l->v, BM_ELEM_TAG); + BM_elem_flag_enable(l_prev->v, BM_ELEM_TAG); + } + } + l_prev = l; + luv_prev = luv; + luv_select_prev = luv_select; + } + } + + if (sima->sticky == SI_STICKY_VERTEX) { + uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset); + } + } + else { + /* other selection modes */ + changed = true; + BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false); + + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (!uvedit_face_visible_test(scene, efa)) { + continue; + } + bool has_selected = false; + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + if ((select) != (uvedit_uv_select_test(scene, l, cd_loop_uv_offset))) { + if (!pinned || (ts->uv_flag & UV_SYNC_SELECTION)) { + /* UV_SYNC_SELECTION - can't do pinned selection */ + if (BLI_rctf_isect_pt_v(&rectf, luv->uv)) { + uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); + BM_elem_flag_enable(l->v, BM_ELEM_TAG); + has_selected = true; + } + } + else if (pinned) { + if ((luv->flag & MLOOPUV_PINNED) && BLI_rctf_isect_pt_v(&rectf, luv->uv)) { + uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); + BM_elem_flag_enable(l->v, BM_ELEM_TAG); + } + } + } + } + if (has_selected && ts->uv_selectmode == UV_SELECT_ISLAND) { + UvNearestHit hit = { + .ob = obedit, + .efa = efa, + }; + uv_select_linked_multi( + scene, objects, objects_len, limit, &hit, true, !select, false, false); + } + } + + if (sima->sticky == SI_STICKY_VERTEX) { + uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset); + } + } + + if (changed || use_pre_deselect) { + changed_multi = true; + + uv_select_sync_flush(ts, em, select); + uv_select_tag_update_for_object(depsgraph, ts, obedit); + } + } + + MEM_freeN(objects); + + return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED; +} + +void UV_OT_select_box(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Box Select"; + ot->description = "Select UV vertices using box selection"; + ot->idname = "UV_OT_select_box"; + + /* api callbacks */ + ot->invoke = WM_gesture_box_invoke; + ot->exec = uv_box_select_exec; + ot->modal = WM_gesture_box_modal; + ot->poll = ED_operator_uvedit_space_image; /* requires space image */ + ot->cancel = WM_gesture_box_cancel; + + /* flags */ + ot->flag = OPTYPE_UNDO; + + /* properties */ + RNA_def_boolean(ot->srna, "pinned", 0, "Pinned", "Border select pinned UVs only"); + + WM_operator_properties_gesture_box(ot); + WM_operator_properties_select_operation_simple(ot); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Circle Select Operator + * \{ */ + +static int uv_circle_select_is_point_inside(const float uv[2], + const float offset[2], + const float ellipse[2]) +{ + /* normalized ellipse: ell[0] = scaleX, ell[1] = scaleY */ + const float co[2] = { + (uv[0] - offset[0]) * ellipse[0], + (uv[1] - offset[1]) * ellipse[1], + }; + return len_squared_v2(co) < 1.0f; +} + +static int uv_circle_select_is_edge_inside(const float uv_a[2], + const float uv_b[2], + const float offset[2], + const float ellipse[2]) +{ + /* normalized ellipse: ell[0] = scaleX, ell[1] = scaleY */ + const float co_a[2] = { + (uv_a[0] - offset[0]) * ellipse[0], + (uv_a[1] - offset[1]) * ellipse[1], + }; + const float co_b[2] = { + (uv_b[0] - offset[0]) * ellipse[0], + (uv_b[1] - offset[1]) * ellipse[1], + }; + return dist_squared_to_line_segment_v2((const float[2]){0.0f, 0.0f}, co_a, co_b) < 1.0f; +} + +static int uv_circle_select_exec(bContext *C, wmOperator *op) +{ + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + SpaceImage *sima = CTX_wm_space_image(C); + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + const ToolSettings *ts = scene->toolsettings; + const ARegion *region = CTX_wm_region(C); + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + MLoopUV *luv; + int x, y, radius, width, height; + float zoomx, zoomy; + float limit[2], offset[2], ellipse[2]; + + const bool use_face_center = ((ts->uv_flag & UV_SYNC_SELECTION) ? + (ts->selectmode == SCE_SELECT_FACE) : + (ts->uv_selectmode == UV_SELECT_FACE)); + const bool use_edge = ((ts->uv_flag & UV_SYNC_SELECTION) ? + (ts->selectmode == SCE_SELECT_EDGE) : + (ts->uv_selectmode == UV_SELECT_EDGE)); + + /* get operator properties */ + x = RNA_int_get(op->ptr, "x"); + y = RNA_int_get(op->ptr, "y"); + radius = RNA_int_get(op->ptr, "radius"); + + /* compute ellipse size and location, not a circle since we deal + * with non square image. ellipse is normalized, r = 1.0. */ + ED_space_image_get_size(sima, &width, &height); + ED_space_image_get_zoom(sima, region, &zoomx, &zoomy); + + ellipse[0] = width * zoomx / radius; + ellipse[1] = height * zoomy / radius; + + UI_view2d_region_to_view(®ion->v2d, x, y, &offset[0], &offset[1]); + + uv_select_island_limit_default(sima, limit); + + bool changed_multi = false; + + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( + view_layer, ((View3D *)NULL), &objects_len); + + const eSelectOp sel_op = ED_select_op_modal(RNA_enum_get(op->ptr, "mode"), + WM_gesture_is_modal_first(op->customdata)); + const bool select = (sel_op != SEL_OP_SUB); + const bool use_pre_deselect = SEL_OP_USE_PRE_DESELECT(sel_op); + + if (use_pre_deselect) { + uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT); + } + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + + bool changed = false; + + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + + /* do selection */ + if (use_face_center) { + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + BM_elem_flag_disable(efa, BM_ELEM_TAG); + /* assume not touched */ + if (select != uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) { + float cent[2]; + uv_poly_center(efa, cent, cd_loop_uv_offset); + if (uv_circle_select_is_point_inside(cent, offset, ellipse)) { + BM_elem_flag_enable(efa, BM_ELEM_TAG); + changed = true; + } + } + } + + /* (de)selects all tagged faces and deals with sticky modes */ + if (changed) { + uv_select_flush_from_tag_face(sima, scene, obedit, select); + } + } + else if (use_edge) { + BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false); + + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (!uvedit_face_visible_test(scene, efa)) { + continue; + } + + BMLoop *l_prev = BM_FACE_FIRST_LOOP(efa)->prev; + MLoopUV *luv_prev = BM_ELEM_CD_GET_VOID_P(l_prev, cd_loop_uv_offset); + bool luv_select_prev = uvedit_uv_select_test(scene, l_prev, cd_loop_uv_offset); + + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + const bool luv_select = uvedit_uv_select_test(scene, l, cd_loop_uv_offset); + if ((select != luv_select) || (select != luv_select_prev)) { + if (uv_circle_select_is_edge_inside(luv->uv, luv_prev->uv, offset, ellipse)) { + changed = true; + uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); + uvedit_uv_select_set(em, scene, l_prev, select, false, cd_loop_uv_offset); + BM_elem_flag_enable(l->v, BM_ELEM_TAG); + BM_elem_flag_enable(l_prev->v, BM_ELEM_TAG); + } + } + l_prev = l; + luv_prev = luv; + luv_select_prev = luv_select; + } + } + + if (sima->sticky == SI_STICKY_VERTEX) { + uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset); + } + } + else { + BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false); + + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (!uvedit_face_visible_test(scene, efa)) { + continue; + } + bool has_selected = false; + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + if ((select) != (uvedit_uv_select_test(scene, l, cd_loop_uv_offset))) { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + if (uv_circle_select_is_point_inside(luv->uv, offset, ellipse)) { + changed = true; + uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); + BM_elem_flag_enable(l->v, BM_ELEM_TAG); + has_selected = true; + } + } + } + if (has_selected && ts->uv_selectmode == UV_SELECT_ISLAND) { + UvNearestHit hit = { + .ob = obedit, + .efa = efa, + }; + uv_select_linked_multi( + scene, objects, objects_len, limit, &hit, true, !select, false, false); + } + } + + if (sima->sticky == SI_STICKY_VERTEX) { + uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset); + } + } + + if (changed || use_pre_deselect) { + changed_multi = true; + + uv_select_sync_flush(ts, em, select); + uv_select_tag_update_for_object(depsgraph, ts, obedit); + } + } + MEM_freeN(objects); + + return changed_multi ? OPERATOR_FINISHED : OPERATOR_CANCELLED; +} + +void UV_OT_select_circle(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Circle Select"; + ot->description = "Select UV vertices using circle selection"; + ot->idname = "UV_OT_select_circle"; + + /* api callbacks */ + ot->invoke = WM_gesture_circle_invoke; + ot->modal = WM_gesture_circle_modal; + ot->exec = uv_circle_select_exec; + ot->poll = ED_operator_uvedit_space_image; /* requires space image */ + ot->cancel = WM_gesture_circle_cancel; + + /* flags */ + ot->flag = OPTYPE_UNDO; + + /* properties */ + WM_operator_properties_gesture_circle(ot); + WM_operator_properties_select_operation_simple(ot); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Lasso Select Operator + * \{ */ + +static bool do_lasso_select_mesh_uv_is_point_inside(const ARegion *region, + const rcti *clip_rect, + const int mcoords[][2], + const int mcoords_len, + const float co_test[2]) +{ + int co_screen[2]; + if (UI_view2d_view_to_region_clip( + ®ion->v2d, co_test[0], co_test[1], &co_screen[0], &co_screen[1]) && + BLI_rcti_isect_pt_v(clip_rect, co_screen) && + BLI_lasso_is_point_inside( + mcoords, mcoords_len, co_screen[0], co_screen[1], V2D_IS_CLIPPED)) { + return true; + } + return false; +} + +static bool do_lasso_select_mesh_uv(bContext *C, + const int mcoords[][2], + const int mcoords_len, + const eSelectOp sel_op) +{ + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + SpaceImage *sima = CTX_wm_space_image(C); + const ARegion *region = CTX_wm_region(C); + Scene *scene = CTX_data_scene(C); + const ToolSettings *ts = scene->toolsettings; + ViewLayer *view_layer = CTX_data_view_layer(C); + const bool use_face_center = ((ts->uv_flag & UV_SYNC_SELECTION) ? + (ts->selectmode == SCE_SELECT_FACE) : + (ts->uv_selectmode == UV_SELECT_FACE)); + const bool use_edge = ((ts->uv_flag & UV_SYNC_SELECTION) ? + (ts->selectmode == SCE_SELECT_EDGE) : + (ts->uv_selectmode == UV_SELECT_EDGE)); + + const bool select = (sel_op != SEL_OP_SUB); + const bool use_pre_deselect = SEL_OP_USE_PRE_DESELECT(sel_op); + + BMIter iter, liter; + + BMFace *efa; + BMLoop *l; + float limit[2]; + bool changed_multi = false; + rcti rect; + + uv_select_island_limit_default(sima, limit); + + BLI_lasso_boundbox(&rect, mcoords, mcoords_len); + + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( + view_layer, ((View3D *)NULL), &objects_len); + + if (use_pre_deselect) { + uv_select_all_perform_multi(scene, objects, objects_len, SEL_DESELECT); + } + + /* don't indent to avoid diff noise! */ + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + + bool changed = false; + + BMEditMesh *em = BKE_editmesh_from_object(obedit); + + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + + if (use_face_center) { /* Face Center Sel */ + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + BM_elem_flag_disable(efa, BM_ELEM_TAG); + /* assume not touched */ + if (select != uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) { + float cent[2]; + uv_poly_center(efa, cent, cd_loop_uv_offset); + if (do_lasso_select_mesh_uv_is_point_inside(region, &rect, mcoords, mcoords_len, cent)) { + BM_elem_flag_enable(efa, BM_ELEM_TAG); + changed = true; + } + } + } + + /* (de)selects all tagged faces and deals with sticky modes */ + if (changed) { + uv_select_flush_from_tag_face(sima, scene, obedit, select); + } + } + else if (use_edge) { + BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false); + + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (!uvedit_face_visible_test(scene, efa)) { + continue; + } + + BMLoop *l_prev = BM_FACE_FIRST_LOOP(efa)->prev; + MLoopUV *luv_prev = BM_ELEM_CD_GET_VOID_P(l_prev, cd_loop_uv_offset); + bool luv_select_prev = uvedit_uv_select_test(scene, l_prev, cd_loop_uv_offset); + + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + const bool luv_select = uvedit_uv_select_test(scene, l, cd_loop_uv_offset); + if ((select != luv_select) || (select != luv_select_prev)) { + if (do_lasso_select_mesh_uv_is_point_inside( + region, &rect, mcoords, mcoords_len, luv->uv) && + do_lasso_select_mesh_uv_is_point_inside( + region, &rect, mcoords, mcoords_len, luv_prev->uv)) { + uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); + uvedit_uv_select_set(em, scene, l_prev, select, false, cd_loop_uv_offset); + changed = true; + BM_elem_flag_enable(l->v, BM_ELEM_TAG); + BM_elem_flag_enable(l_prev->v, BM_ELEM_TAG); + } + } + l_prev = l; + luv_prev = luv; + luv_select_prev = luv_select; + } + } + + if (sima->sticky == SI_STICKY_VERTEX) { + uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset); + } + } + else { /* Vert Sel */ + BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT, BM_ELEM_TAG, false); + + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (!uvedit_face_visible_test(scene, efa)) { + continue; + } + bool has_selected = false; + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + if ((select) != (uvedit_uv_select_test(scene, l, cd_loop_uv_offset))) { + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + if (do_lasso_select_mesh_uv_is_point_inside( + region, &rect, mcoords, mcoords_len, luv->uv)) { + uvedit_uv_select_set(em, scene, l, select, false, cd_loop_uv_offset); + changed = true; + BM_elem_flag_enable(l->v, BM_ELEM_TAG); + has_selected = true; + } + } + } + if (has_selected && ts->uv_selectmode == UV_SELECT_ISLAND) { + UvNearestHit hit = { + .ob = obedit, + .efa = efa, + }; + uv_select_linked_multi( + scene, objects, objects_len, limit, &hit, true, !select, false, false); + } + } + + if (sima->sticky == SI_STICKY_VERTEX) { + uvedit_vertex_select_tagged(em, scene, select, cd_loop_uv_offset); + } + } + + if (changed || use_pre_deselect) { + changed_multi = true; + + uv_select_sync_flush(ts, em, select); + uv_select_tag_update_for_object(depsgraph, ts, obedit); + } + } + MEM_freeN(objects); + + return changed_multi; +} + +static int uv_lasso_select_exec(bContext *C, wmOperator *op) +{ + int mcoords_len; + const int(*mcoords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcoords_len); + + if (mcoords) { + const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode"); + bool changed = do_lasso_select_mesh_uv(C, mcoords, mcoords_len, sel_op); + MEM_freeN((void *)mcoords); + + return changed ? OPERATOR_FINISHED : OPERATOR_CANCELLED; + } + + return OPERATOR_PASS_THROUGH; +} + +void UV_OT_select_lasso(wmOperatorType *ot) +{ + ot->name = "Lasso Select UV"; + ot->description = "Select UVs using lasso selection"; + ot->idname = "UV_OT_select_lasso"; + + ot->invoke = WM_gesture_lasso_invoke; + ot->modal = WM_gesture_lasso_modal; + ot->exec = uv_lasso_select_exec; + ot->poll = ED_operator_uvedit_space_image; + ot->cancel = WM_gesture_lasso_cancel; + + /* flags */ + ot->flag = OPTYPE_UNDO; + + /* properties */ + WM_operator_properties_gesture_lasso(ot); + WM_operator_properties_select_operation_simple(ot); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select Pinned UV's Operator + * \{ */ + +static int uv_select_pinned_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + Scene *scene = CTX_data_scene(C); + const ToolSettings *ts = scene->toolsettings; + ViewLayer *view_layer = CTX_data_view_layer(C); + BMFace *efa; + BMLoop *l; + BMIter iter, liter; + MLoopUV *luv; + + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data_with_uvs( + view_layer, ((View3D *)NULL), &objects_len); + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + bool changed = false; + + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (!uvedit_face_visible_test(scene, efa)) { + continue; + } + + BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) { + luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + + if (luv->flag & MLOOPUV_PINNED) { + uvedit_uv_select_enable(em, scene, l, false, cd_loop_uv_offset); + changed = true; + } + } + } + + if (changed) { + uv_select_tag_update_for_object(depsgraph, ts, obedit); + } + } + MEM_freeN(objects); + + return OPERATOR_FINISHED; +} + +void UV_OT_select_pinned(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Selected Pinned"; + ot->description = "Select all pinned UV vertices"; + ot->idname = "UV_OT_select_pinned"; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* api callbacks */ + ot->exec = uv_select_pinned_exec; + ot->poll = ED_operator_uvedit; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select Overlap Operator + * \{ */ + +BLI_INLINE uint overlap_hash(const void *overlap_v) +{ + const BVHTreeOverlap *overlap = overlap_v; + + /* Designed to treat (A,B) and (B,A) as the same. */ + int x = overlap->indexA; + int y = overlap->indexB; + if (x > y) { + SWAP(int, x, y); + } + return BLI_hash_int_2d(x, y); +} + +BLI_INLINE bool overlap_cmp(const void *a_v, const void *b_v) +{ + const BVHTreeOverlap *a = a_v; + const BVHTreeOverlap *b = b_v; + return !((a->indexA == b->indexA && a->indexB == b->indexB) || + (a->indexA == b->indexB && a->indexB == b->indexA)); +} + +struct UVOverlapData { + int ob_index; + int face_index; + float tri[3][2]; +}; + +static int uv_select_overlap(bContext *C, const bool extend) +{ + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + Scene *scene = CTX_data_scene(C); + 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_with_uvs( + view_layer, ((View3D *)NULL), &objects_len); + + /* Calculate maximum number of tree nodes and prepare initial selection. */ + uint uv_tri_len = 0; + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + + BM_mesh_elem_table_ensure(em->bm, BM_FACE); + BM_mesh_elem_index_ensure(em->bm, BM_VERT | BM_FACE); + BM_mesh_elem_hflag_disable_all(em->bm, BM_FACE, BM_ELEM_TAG, false); + if (!extend) { + uv_select_all_perform(scene, obedit, SEL_DESELECT); + } + + BMIter iter; + BMFace *efa; + BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { + if (!uvedit_face_visible_test_ex(scene->toolsettings, efa)) { + continue; + } + uv_tri_len += efa->len - 2; + } + } + + struct UVOverlapData *overlap_data = MEM_mallocN(sizeof(struct UVOverlapData) * uv_tri_len, + "UvOverlapData"); + BVHTree *uv_tree = BLI_bvhtree_new(uv_tri_len, 0.0f, 4, 6); + + /* Use a global data index when inserting into the BVH. */ + int data_index = 0; + + int face_len_alloc = 3; + float(*uv_verts)[2] = MEM_mallocN(sizeof(*uv_verts) * face_len_alloc, "UvOverlapCoords"); + uint(*indices)[3] = MEM_mallocN(sizeof(*indices) * (face_len_alloc - 2), "UvOverlapTris"); + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *obedit = objects[ob_index]; + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMIter iter, liter; + BMFace *efa; + BMLoop *l; + + const int cd_loop_uv_offset = CustomData_get_offset(&em->bm->ldata, CD_MLOOPUV); + + /* Triangulate each UV face and store it inside the BVH. */ + int face_index; + BM_ITER_MESH_INDEX (efa, &iter, em->bm, BM_FACES_OF_MESH, face_index) { + + if (!uvedit_face_visible_test_ex(scene->toolsettings, efa)) { + continue; + } + + const uint face_len = efa->len; + const uint tri_len = face_len - 2; + + if (face_len_alloc < face_len) { + MEM_freeN(uv_verts); + MEM_freeN(indices); + uv_verts = MEM_mallocN(sizeof(*uv_verts) * face_len, "UvOverlapCoords"); + indices = MEM_mallocN(sizeof(*indices) * tri_len, "UvOverlapTris"); + face_len_alloc = face_len; + } + + int vert_index; + BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, vert_index) { + MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset); + copy_v2_v2(uv_verts[vert_index], luv->uv); + } + + BLI_polyfill_calc(uv_verts, face_len, 0, indices); + + for (int t = 0; t < tri_len; t++) { + overlap_data[data_index].ob_index = ob_index; + overlap_data[data_index].face_index = face_index; + + /* BVH needs 3D, overlap data uses 2D. */ + const float tri[3][3] = { + {UNPACK2(uv_verts[indices[t][0]]), 0.0f}, + {UNPACK2(uv_verts[indices[t][1]]), 0.0f}, + {UNPACK2(uv_verts[indices[t][2]]), 0.0f}, + }; + + copy_v2_v2(overlap_data[data_index].tri[0], tri[0]); + copy_v2_v2(overlap_data[data_index].tri[1], tri[1]); + copy_v2_v2(overlap_data[data_index].tri[2], tri[2]); + + BLI_bvhtree_insert(uv_tree, data_index, &tri[0][0], 3); + data_index++; + } + } + } + BLI_assert(data_index == uv_tri_len); + + MEM_freeN(uv_verts); + MEM_freeN(indices); + + BLI_bvhtree_balance(uv_tree); + + uint tree_overlap_len; + BVHTreeOverlap *overlap = BLI_bvhtree_overlap(uv_tree, uv_tree, &tree_overlap_len, NULL, NULL); + + if (overlap != NULL) { + GSet *overlap_set = BLI_gset_new_ex(overlap_hash, overlap_cmp, __func__, tree_overlap_len); + + for (int i = 0; i < tree_overlap_len; i++) { + /* Skip overlaps against yourself. */ + if (overlap[i].indexA == overlap[i].indexB) { + continue; + } + + /* Skip overlaps that have already been tested. */ + if (!BLI_gset_add(overlap_set, &overlap[i])) { + continue; + } + + const struct UVOverlapData *o_a = &overlap_data[overlap[i].indexA]; + const struct UVOverlapData *o_b = &overlap_data[overlap[i].indexB]; + Object *obedit_a = objects[o_a->ob_index]; + Object *obedit_b = objects[o_b->ob_index]; + BMEditMesh *em_a = BKE_editmesh_from_object(obedit_a); + BMEditMesh *em_b = BKE_editmesh_from_object(obedit_b); + BMFace *face_a = em_a->bm->ftable[o_a->face_index]; + BMFace *face_b = em_b->bm->ftable[o_b->face_index]; + const int cd_loop_uv_offset_a = CustomData_get_offset(&em_a->bm->ldata, CD_MLOOPUV); + const int cd_loop_uv_offset_b = CustomData_get_offset(&em_b->bm->ldata, CD_MLOOPUV); + + /* Skip if both faces are already selected. */ + if (uvedit_face_select_test(scene, face_a, cd_loop_uv_offset_a) && + uvedit_face_select_test(scene, face_b, cd_loop_uv_offset_b)) { + continue; + } + + /* Main tri-tri overlap test. */ + const float endpoint_bias = -1e-4f; + const float(*t1)[2] = o_a->tri; + const float(*t2)[2] = o_b->tri; + float vi[2]; + bool result = ( + /* Don't use 'isect_tri_tri_v2' here + * because it's important to ignore overlap at end-points. */ + isect_seg_seg_v2_point_ex(t1[0], t1[1], t2[0], t2[1], endpoint_bias, vi) == 1 || + isect_seg_seg_v2_point_ex(t1[0], t1[1], t2[1], t2[2], endpoint_bias, vi) == 1 || + isect_seg_seg_v2_point_ex(t1[0], t1[1], t2[2], t2[0], endpoint_bias, vi) == 1 || + isect_seg_seg_v2_point_ex(t1[1], t1[2], t2[0], t2[1], endpoint_bias, vi) == 1 || + isect_seg_seg_v2_point_ex(t1[1], t1[2], t2[1], t2[2], endpoint_bias, vi) == 1 || + isect_seg_seg_v2_point_ex(t1[1], t1[2], t2[2], t2[0], endpoint_bias, vi) == 1 || + isect_seg_seg_v2_point_ex(t1[2], t1[0], t2[0], t2[1], endpoint_bias, vi) == 1 || + isect_seg_seg_v2_point_ex(t1[2], t1[0], t2[1], t2[2], endpoint_bias, vi) == 1 || + isect_point_tri_v2(t1[0], t2[0], t2[1], t2[2]) != 0 || + isect_point_tri_v2(t2[0], t1[0], t1[1], t1[2]) != 0); + + if (result) { + uvedit_face_select_enable(scene, em_a, face_a, false, cd_loop_uv_offset_a); + uvedit_face_select_enable(scene, em_b, face_b, false, cd_loop_uv_offset_b); + } + } + + BLI_gset_free(overlap_set, NULL); + MEM_freeN(overlap); + } + + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + uv_select_tag_update_for_object(depsgraph, scene->toolsettings, objects[ob_index]); + } + + BLI_bvhtree_free(uv_tree); + + MEM_freeN(overlap_data); + MEM_freeN(objects); + + return OPERATOR_FINISHED; +} + +static int uv_select_overlap_exec(bContext *C, wmOperator *op) +{ + bool extend = RNA_boolean_get(op->ptr, "extend"); + return uv_select_overlap(C, extend); +} + +void UV_OT_select_overlap(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Select Overlap"; + ot->description = "Select all UV faces which overlap each other"; + ot->idname = "UV_OT_select_overlap"; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* api callbacks */ + ot->exec = uv_select_overlap_exec; + ot->poll = ED_operator_uvedit; + + /* properties */ + RNA_def_boolean(ot->srna, + "extend", + 0, + "Extend", + "Extend selection rather than clearing the existing selection"); +} + +/** \} */ |